summaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog3663
-rw-r--r--g10/Makefile.am125
-rw-r--r--g10/armor.c378
-rw-r--r--g10/build-packet.c437
-rw-r--r--g10/cipher.c109
-rw-r--r--g10/comment.c40
-rw-r--r--g10/compress.c75
-rw-r--r--g10/dearmor.c8
-rw-r--r--g10/decrypt.c62
-rw-r--r--g10/delkey.c104
-rw-r--r--g10/encode.c519
-rw-r--r--g10/encr-data.c96
-rw-r--r--g10/exec.c579
-rw-r--r--g10/exec.h22
-rw-r--r--g10/export.c168
-rw-r--r--g10/filter.h47
-rw-r--r--g10/free-packet.c225
-rw-r--r--g10/g10.c (renamed from g10/gpg.c)1491
-rw-r--r--g10/getkey.c1867
-rw-r--r--g10/global.h (renamed from g10/basicdefs.h)27
-rw-r--r--g10/gpgd.c24
-rw-r--r--g10/gpgv.c372
-rw-r--r--g10/helptext.c49
-rw-r--r--g10/hkp.c503
-rw-r--r--g10/hkp.h15
-rw-r--r--g10/import.c801
-rw-r--r--g10/kbnode.c56
-rw-r--r--g10/kbx.h51
-rw-r--r--g10/kbxblob.c895
-rw-r--r--g10/kbxfile.c332
-rw-r--r--g10/kbxio.c75
-rw-r--r--g10/kbxutil.c442
-rw-r--r--g10/keydb.c698
-rw-r--r--g10/keydb.h156
-rw-r--r--g10/keyedit.c1722
-rw-r--r--g10/keygen.c1301
-rw-r--r--g10/keyid.c436
-rw-r--r--g10/keylist.c1046
-rw-r--r--g10/keyring.c1550
-rw-r--r--g10/keyring.h45
-rw-r--r--g10/keyserver-internal.h22
-rw-r--r--g10/keyserver.c1033
-rw-r--r--g10/ks-proto.c2
-rw-r--r--g10/ks-proto.h8
-rw-r--r--g10/main.h110
-rw-r--r--g10/mainproc.c833
-rw-r--r--g10/mdfilter.c12
-rw-r--r--g10/misc.c704
-rw-r--r--g10/mkdtemp.c98
-rw-r--r--g10/openfile.c102
-rw-r--r--g10/options.h103
-rw-r--r--g10/options.skel180
-rw-r--r--g10/packet.h239
-rw-r--r--g10/parse-packet.c748
-rw-r--r--g10/passphrase.c1002
-rw-r--r--g10/photoid.c320
-rw-r--r--g10/photoid.h14
-rw-r--r--g10/pipemode.c317
-rw-r--r--g10/pkclist.c1100
-rw-r--r--g10/plaintext.c135
-rw-r--r--g10/pubkey-enc.c231
-rw-r--r--g10/revoke.c374
-rw-r--r--g10/ringedit.c1360
-rw-r--r--g10/seckey-cert.c371
-rw-r--r--g10/seskey.c104
-rw-r--r--g10/sig-check.c370
-rw-r--r--g10/sign.c1276
-rw-r--r--g10/signal.c126
-rw-r--r--g10/skclist.c133
-rw-r--r--g10/status.c348
-rw-r--r--g10/status.h31
-rw-r--r--g10/tdbdump.c411
-rw-r--r--g10/tdbio.c929
-rw-r--r--g10/tdbio.h141
-rw-r--r--g10/textfilter.c18
-rw-r--r--g10/trustdb.c3848
-rw-r--r--g10/trustdb.h58
-rw-r--r--g10/verify.c43
78 files changed, 24084 insertions, 13781 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 9c5acd8a1..21c44df4e 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,429 +1,3446 @@
-2000-11-13 Werner Koch <wk@gnupg.org>
+2002-06-21 Stefan Bellon <sbellon@sbellon.de>
- * Makefile.am: Do not install any program
+ * g10.c [__riscos__]: Moved RISC OS specific stuff to util/riscos.c
+ and include/util.h.
-2000-10-12 Werner Koch <wk@gnupg.org>
+ * gpgv.c [__riscos__]: Likewise.
- * keygen.c (keygen_add_std_prefs): Add Rijndael to the prefs.
+2002-06-20 David Shaw <dshaw@jabberwocky.com>
+
+ * keydb.h, pkclist.c (select_algo_from_prefs): Allow passing a
+ suggested algorithm which will be used if available.
+
+ * encode.c (encode_crypt, encrypt_filter), sign.c (sign_file): Use
+ new select_algo_from_prefs feature to check if forcing an
+ algorithm would violate the recipient preferences.
+
+ * photoid.c (get_default_photo_command, show_photos): Use
+ different default viewers on different platforms. Currently we
+ have Win 9x, Win NT (2k, xp), Mac OSX, RISC OS, and "everybody
+ else". These are #ifdefs as much as possible to avoid clutter.
+
+ * g10.c (strusage, build_list), keyedit.c (show_prefs), main.h,
+ misc.c (compress_algo_to_string, check_compress_algo), pkclist.c
+ (algo_available), keygen.c (keygen_set_std_prefs): New
+ algo_to_string and check functions for compress algorithms.
+
+2002-06-20 Werner Koch <wk@gnupg.org>
+
+ * misc.c (setsysinfo): Removed a #warning for Alpha's uniligedn
+ trap disabling - it is quite possible that this is a debug relict.
+
+2002-06-20 Stefan Bellon <sbellon@sbellon.de>
+
+ * g10.c [__riscos__]: Added image file system feature.
+
+ * gpgv.c [__riscos__]: Added image file system feature.
+
+ * photoid.c (show_photos) [__riscos__]: Set RISC OS filetype of
+ photo id according to MIME type.
+
+2002-06-19 David Shaw <dshaw@jabberwocky.com>
+
+ * hkp.c (parse_hkp_index): Don't leak memory when failing out of a
+ bad HKP keyserver.
+
+ * g10.c (add_notation_data): Relax slightly the rules as to what
+ can go into a notation name - 2440 allows "@", for example.
+
+2002-06-17 David Shaw <dshaw@jabberwocky.com>
+
+ * import.c (clean_subkeys, import_one): Only allow at most 1
+ binding sig and at most 1 revocation sig on a subkey, as per
+ 2440:11.1.
+
+ * hkp.c (parse_hkp_index, hkp_search): Error if the keyserver
+ returns an unparseable HKP response.
+
+2002-06-15 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (show_key_with_all_names), keylist.c
+ (list_keyblock_print): Show "[expired]" before expired uids.
+
+ * keyedit.c (show_key_with_all_names_colon), mainproc.c
+ (list_node), keylist.c (list_keyblock_colon): Show flag 'e' for
+ expired user ids. Use "uat" for user attribute packets instead of
+ "uid". Also use '<count> <length>' rather than the fake user id
+ string on attributes.
+
+ * keygen.c (keygen_add_revkey): Remove unused code.
+
+ * misc.c (check_permissions): Check directory permissions
+ properly - they are not special files.
+
+ * pkclist.c (expand_id, expand_group, build_pk_list): When
+ expanding groups before building a pk list, inherit flags from the
+ original pre-expanded string.
+
+ * pubkey-enc.c (is_algo_in_prefs): Don't use prefs from expired
+ uids.
+
+2002-06-14 David Shaw <dshaw@jabberwocky.com>
+
+ * free-packet.c (copy_signature): Properly copy a signature that
+ carries a revocation key on it.
+
+ * pkclist.c (expand_id, expand_group, build_pk_list): Groups now
+ work properly when used in the "Enter the user ID" prompt.
+
+2002-06-14 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (show_key_with_all_names): Display warning if a user
+ tries to show prefs on a v3 key with a v3 selfsig.
+
+ * kbnode.c (dump_kbnode): Show if a uid is expired.
+
+ * import.c (merge_blocks, import_revoke_cert): Show user ID
+ receiving a revocation certificate.
+
+ * free-packet.c (cmp_user_ids): Properly compare attribute ids.
+
+ * pkclist.c (expand_groups): Maintain the strlist flags while
+ expanding. Members of an expansion inherit their flags from the
+ expansion key.
+
+ * options.h, cipher.c (write_header), g10.c (main), keygen.c
+ (keygen_set_std_prefs): remove the personal_mdc flag. It no
+ longer serves a purpose now that the personal preference lists are
+ split into cipher/digest/zip.
+
+2002-06-14 Timo Schulz <ts@winpt.org>
+
+ * skclist.c (is_insecure): Implemented.
+
+2002-06-12 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_spawn): Properly handle PROGRAM responses
+ when they have a CRLF ending. Noted by Keith Ray.
+
+ * keyserver.c (keyserver_spawn): Handle CRLF endings from
+ keyserver helpers. Also don't leak the last line worth of memory
+ from the keyserver response.
+
+ * main.h, misc.c (deprecated_warning): New function to warn about
+ deprecated options and commands.
+
+ * g10.c (main), keyserver-internal.h, keyserver.c
+ (parse_keyserver_uri): Use new deprecated function to warn about
+ honor-http-proxy, auto-key-retrieve, and x-broken-hkp.
+
+2002-06-11 David Shaw <dshaw@jabberwocky.com>
+
+ * Makefile.am: link gpg with NETLIBS for the built-in HKP access.
+
+2002-06-10 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, keyserver.c (keyserver_opts), g10.c (main): New
+ keyserver option "include-subkeys". This feature already existed,
+ but now can be turned off. It defaults to on.
+
+ * options.h, keyserver.c (parse_keyserver_options,
+ keyserver_spawn): There are now enough options to justify making a
+ structure for the keyserver options rather than a page of
+ if-then-else-if-then-etc.
+
+ * getkey.c (merge_keys_and_selfsig, merge_selfsigs_main): Fix bug
+ in calculating key expiration dates.
+
+2002-06-09 David Shaw <dshaw@jabberwocky.com>
+
+ * keydb.h, getkey.c (get_user_id_native), import.c (import_one):
+ Display user ID while importing a key. Note this applies to both
+ --import and keyserver --recv-keys.
+
+ * exec.c (exec_finish): Log unnatural exit (core dump, killed
+ manually, etc) for fork/exec/pipe child processes.
+
+2002-06-08 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_symmetric): Disable the compat flag
+ when the expert mode is enabled.
+
+2002-06-07 David Shaw <dshaw@jabberwocky.com>
+
+ * options.skel, options.h, main.h, keydb.h, pkclist.c
+ (build_pk_list, expand_groups), g10.c (main, add_group): Add new
+ "group" command to allow one name to expand into multiple keys.
+ For simplicity, and to avoid potential loops, we only expand once
+ - you can't make an alias that points to an alias.
+
+ * main.h, g10.c (main), keygen.c (build_personal_digest_list):
+ Simplify the default digest list - there is really no need for the
+ other hashes since they will never be used after SHA-1 in the
+ list.
+
+ * options.skel, options.h, g10.c (main), hkp.c (hkp_ask_import,
+ hkp_export, hkp_search), keyserver.c (parse_keyserver_options,
+ parse_keyserver_uri, keyserver_work, keyserver_refresh): Make the
+ "x-broken-hkp" keyserver scheme into keyserver-option
+ "broken-http-proxy". Move honor_http_proxy into
+ keyserver_options. Canonicalize the three variations of "hkp",
+ "x-hkp", and "x-broken-hkp" into "hkp".
+
+2002-06-07 Stefan Bellon <sbellon@sbellon.de>
+
+ * g10.c [__riscos__]: Added --attribute-file to do the same as
+ --attribute-fd, but with a filename not a fd as argument.
+ Added magic symbol for RISC OS to use different memory management.
+
+ * gpgv.c [__riscos__]: Added magic symbol for RISC OS to use
+ different memory management.
+
+2002-06-06 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, g10.c (main), keygen.c (build_personal_digest_list): Put
+ in a default digest preference list consisting of SHA-1, followed
+ by every other installed digest except MD5. Note this is the same
+ as having no digest preference at all except for SHA-1 being
+ favored.
+
+ * options.h, g10.c (main), keygen.c (keygen_set_std_prefs),
+ pkclist.c (select_algo_from_prefs): Split
+ --personal-preference-list into three:
+ --personal-{cipher|digest|compress}-preferences. This allows a
+ user to set one without affecting another (i.e. setting only a
+ digest pref doesn't imply an empty cipher pref).
+
+ * exec.c (exec_read): This is a safer way of guessing the return
+ value of system(). Noted by Stefan Bellon.
+
+2002-06-05 David Shaw <dshaw@jabberwocky.com>
+
+ * hkp.c (parse_hkp_index): Be more robust with keyservers
+ returning very unparseable responses.
+
+ * exec.c (exec_read): Catch and display an error when the remote
+ process exits unnaturally (i.e. segfault) so the user knows what
+ happened. Also fix exec_write stub which has a different number
+ of arguments now.
+
+2002-06-05 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_simple): Ignore the new mode for RFC1991.
+ * mainproc.c (symkey_decrypt_sesskey): Better check for weird
+ keysizes.
+
+2002-06-05 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_sesskey): New.
+ (encode_simple): Use it here. But by default we use the compat
+ mode which supress to generate encrypted session keys.
+
+2002-06-05 Timo Schulz <ts@winpt.org>
+
+ * mainproc.c (symkey_decrypt_sesskey): New.
+ (proc_symkey_enc): Support for encrypted session keys.
+
+2002-06-04 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (hash_for, sign_file): When encrypting and signing at the
+ same time, consult the various hash prefs to pick a hash algorithm
+ to use. Pass in a 160-bit hint if any of the signing keys are
+ DSA.
+
+ * keydb.h, pkclist.c (select_algo_from_prefs, algo_available):
+ Pass a "hints" opaque pointer in to let the caller give hints as
+ to what algorithms would be acceptable. The only current hint is
+ for PREFTYPE_HASH to require a 160-bit hash for DSA. Change all
+ callers in encode.c (encode_crypt, encrypt_filter) and sign.c
+ (sign_file). If we settle on MD5 as the best algorithm based
+ solely on recepient keys and SHA1 is also a possibility, use SHA1
+ unless the user intentionally chose MD5. This is as per 2440:13.
+
+ * exec.c (make_tempdir): Fix duplicated filename problem.
+
+2002-06-03 David Shaw <dshaw@jabberwocky.com>
+
+ * packet.h, parse-packet.c (enum_sig_subpkt): Report back from
+ enum_sig_subpkt when a subpacket is critical and change all
+ callers in keylist.c (show_policy_url, show_notation), mainproc.c
+ (print_notation_data), and pkclist.c (do_show_revocation_reason).
+
+ * keylist.c (show_policy_url, show_notation): Display if the
+ policy or notation is critical.
+
+2002-06-03 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, g10.c (main), keylist.c (dump_attribs, set_attrib_fd,
+ list_keyblock_print, list_keyblock_colon), status.h, status.c
+ (get_status_string): New --attribute-fd feature to dump the
+ contents of attribute subpackets for frontends. If --status-fd is
+ also used, then a new status tag ATTRIBUTE is provided for each
+ subpacket.
+
+ * packet.h, getkey.c (fixup_uidnode, merge_selfsigs_main,
+ merge_selfsigs_subkey), parse-packet.c (setup_user_id): Keep track
+ of the expiration time of a user ID, and while we're at it, use
+ the expired flag from the selfsig rather than reparsing the
+ SIG_EXPIRE subpacket.
+
+ * photoid.c (generate_photo_id): When adding a new photo ID,
+ showing the photo for confirmation is not safe when noninteractive
+ since the "user" may not be able to dismiss a viewer window.
+ Noted by Timo Schulz.
+
+2002-06-03 David Shaw <dshaw@jabberwocky.com>
+
+ * options.skel: Sample photo viewers for Win32.
+
+ * misc.c (pct_expando): Use the seckey for %k/%K if the pubkey is
+ not available.
+
+ * photoid.h, photoid.c (show_photos): Include the seckey in case a
+ user tries to view a photo on a secret key, and change all callers
+ in keyedit.c (menu_showphoto), keylist.c (list_keyblock_print),
+ and photoid.c (generate_photo_id).
+
+2002-06-02 David Shaw <dshaw@jabberwocky.com>
+
+ * photoid.c (show_photos): Work properly when not called with a
+ public key.
+
+2002-05-31 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (mk_notation_and_policy): Free unneeded buffer.
+
+ * hkp.c (parse_hkp_index): Properly handle the '&' character
+ (i.e. "&amp;") in HKP responses.
+
+ * getkey.c (merge_selfsigs_main): Fix reversed expiration time
+ check with self-sigs.
+
+ * keyedit.c (sign_uids): When making a new self-sig on a v3 key,
+ make a v3 self-sig unless it is currently a v3 self-sig being
+ promoted to v4.
+
+2002-05-31 Timo Schulz <ts@winpt.org>
+
+ * pkclist.c (do_show_revocation_reason): Don't use capital
+ letters for non-interactive output.
+ (show_revocation_reason): Now it is global.
+ * pubkey-enc.c (get_it): Show if the key has been revoked.
+
+2002-05-30 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (write_signature_packets, sign_file, clearsign_file,
+ sign_symencrypt_file): Make a v4 signature if a policy URL or
+ notation is set, unless v3 sigs are forced via rfc1991 or
+ force-v3-sigs. Also remove some doubled code and clarify an error
+ message (we don't sign in PGP2 mode - just detach-sign).
+
+ * parse-packet.c (parse_one_sig_subpkt): Add KS_FLAGS to the "any
+ size" section.
+
+2002-05-29 David Shaw <dshaw@jabberwocky.com>
+
+ * keygen.c (keygen_set_std_prefs, add_feature_mdc): Use "mdc" and
+ "no-mdc" in the prefs string to allow switching on and off the MDC
+ feature. This is needed to properly export a key from GnuPG for
+ use on PGP which does not support MDC - without this, MDC-capable
+ implementations will still try and generate MDCs which will break
+ PGP.
+
+ * keygen.c (keygen_get_std_prefs): Show "[mdc]" in prefs string if
+ it is enabled.
+
+ * options.h, g10.c (main), cipher.c (write_header), keygen.c
+ (keygen_set_std_prefs): For consistency, allow the user to specify
+ mdc/no-mdc in the --personal-preference-list. If disabled, it
+ acts just like --disable-mdc.
+
+2002-05-29 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, exec.c: Add some debugging info, using the 1024 debug
+ flag.
+
+ * exec.c (win_system): New system()-like function for win32 that
+ does not return until the child process terminates. Of course,
+ this doesn't help if the process itself exits before it is
+ finished.
+
+2002-05-29 Werner Koch <wk@gnupg.org>
+
+ * encode.c (encode_simple): Intialize PKT when --no-literal is used.
+
+ * keyedit.c (show_key_with_all_names_colon): Renamed the record
+ for revocation keys to "rvk".
+
+2002-05-27 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (show_key_with_all_names_colon): New.
+ (show_key_with_all_names): Divert to new function when required.
+ Sanitize printing of revoker name.
+
+2002-05-27 David Shaw <dshaw@jabberwocky.com>
+
+ * build-packet.c (build_sig_subpkt): Handle setting sig flags for
+ certain subpacket types (notation, policy url, exportable,
+ revocable). keyedit.c (sign_mk_attrib): Flags no longer need to
+ be set here.
+
+ * packet.h, parse-packet.c (parse_one_sig_subpkt), build-packet.c
+ (build_sig_subpkt): Call parse_one_sig_subpkt to sanity check
+ buffer lengths before building a sig subpacket.
+
+2002-05-26 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (mk_notation_and_policy): Include secret key to enable %s
+ expandos, and pass notations through pct_expando as well.
+
+ * main.h, misc.c (pct_expando): Add %s and %S expandos for
+ signer's keyid.
+
+2002-05-25 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (strusage, build_list): Add compress algorithms to
+ --version list. Show algorithm numbers when --verbose --version
+ is done.
+
+2002-05-22 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, main.h, keygen.c (keygen_set_set_prefs,
+ keygen_get_std_prefs, keygen_upd_std_prefs), keyedit.c
+ (keyedit_menu), g10.c (main), pkclist.c (select_algo_from_prefs):
+ Add --personal-preference-list which allows the user to factor in
+ their own preferred algorithms when the preference lists are
+ consulted. Obviously, this does not let the user violate a
+ recepient's preferences (and the RFC) - this only influences the
+ ranking of the agreed-on (and available) algorithms from the
+ recepients. Suggested by David Hollenberg.
+
+ * options.h, keygen.c (keygen_set_std_prefs), g10.c (main): Rename
+ --preference-list to --default-preference-list (as that is what it
+ really is), and make it a true default in that if the user selects
+ "default" they get this list and not the compiled-in list.
+
+2002-05-22 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Add missing LF in a info printout and made it
+ translatable. Noted by Michael Tokarev.
+
+2002-05-21 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Removed the undef of USE_SHM_COPROCESSING which
+ was erroneously introduced on 2002-01-09.
+
+ * signal.c (got_fatal_signal): Don't write the Nul to stderr.
+ Reported by David Hollenberg.
+
+2002-05-18 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, g10.c (main), revoke.c (gen_desig_revoke): Generate a
+ designated revocation via --desig-revoke
+
+ * keyedit.c (keyedit_menu, menu_addrevoker): New "addrevoker"
+ command to add a designated revoker to a key.
+
+2002-05-17 David Shaw <dshaw@jabberwocky.com>
+
+ * gpgv.c: Add stub for get_ownertrust().
+
+ * g10.c (main): --allow-freeform-uid should be implied by
+ OpenPGP. Add --no-allow-freeform-uid.
+
+ * keyedit.c (sign_uids): Issue a warning when signing a
+ non-selfsigned uid.
+
+ * getkey.c (merge_selfsigs_main): If a key has no selfsigs, and
+ allow-non-selfsigned-uid is not set, still try and make the key
+ valid by checking all uids for a signature from an ultimately
+ trusted key.
+
+2002-05-16 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, keygen.c (keygen_add_revkey): Add revocation key
+ subpackets to a signature (callable by
+ make_keysig_packet). (write_direct_sig): Write a 1F direct key
+ signature. (parse_revocation_key): Parse a string in
+ algo:fpr:sensitive format into a revocation
+ key. (get_parameter_revkey, do_generate_keypair): Call above
+ functions when prompted from a batch key generation file.
+
+ * build-packet.c (build_sig_subpkt): Allow multiple revocation key
+ subpackets in a single sig.
+
+ * keydb.h, getkey.c (get_seckey_byfprint): Same as
+ get_pubkey_byfprint, except for secret keys. We only know the
+ fingerprint of a revocation key, so this is needed to retrieve the
+ secret key needed to issue a revokation.
+
+ * packet.h, parse-packet.c (parse_signature, parse_revkeys): Split
+ revkey parsing off into a new function that can be used to reparse
+ after manipulating the revkey list.
+
+ * sign.c (make_keysig_packet): Ability to make 1F direct key
+ signatures.
+
+2002-05-15 David Shaw <dshaw@jabberwocky.com>
+
+ * options.skel: keyserver.pgp.com is gone, so list pgp.surfnet.nl
+ as a sample LDAP server instead.
+
+ * getkey.c (merge_selfsigs_main): Properly handle multiple
+ revocation keys in a single packet. Properly handle revocation
+ keys that are in out-of-order packets. Remove duplicates in
+ revocation key list.
+
+2002-05-14 Timo Schulz <ts@winpt.org>
+
+ * exec.c (make_tempdir) [MINGW32]: Added missing '\'.
+
+2002-05-14 Stefan Bellon <sbellon@sbellon.de>
+
+ * exec.c (make_tempdir): Make use of EXTSEP_S instead of hardcoded
+ dot as extension separator.
+
+2002-05-13 David Shaw <dshaw@jabberwocky.com>
+
+ * photoid.c (show_photos): Use the long keyid as the filename for
+ the photo. Use the short keyid as the filename on 8.3 systems.
+
+ * exec.h, exec.c (make_tempdir, exec_write, exec_finish): Allow
+ caller to specify filename. This should make things easier on
+ windows and macs where the file extension is required, but a whole
+ filename is even better.
+
+ * keyedit.c (show_key_with_all_names, show_prefs): Show proper
+ prefs for a v4 key uid with no selfsig at all.
+
+ * misc.c (check_permissions): Don't check permissions on
+ non-normal files (pipes, character devices, etc.)
+
+2002-05-11 Werner Koch <wk@gnupg.org>
+
+ * mainproc.c (proc_symkey_enc): Avoid segv in case the parser
+ encountered an invalid packet.
+
+ * keyserver.c (keyserver_export): Get confirmation before sending
+ all keys.
+
+2002-05-10 Stefan Bellon <sbellon@sbellon.de>
+
+ * g10.c, hkp.c, keyedit.c, keyserver.c: Replaced all occurrances
+ of strcasecmp with ascii_strcasecmp and all occurrances of
+ strncasecmp with ascii_memcasecmp.
+
+2002-05-10 David Shaw <dshaw@jabberwocky.com>
+
+ * packet.h, getkey.c (fixup_uidnode), keyedit.c (show_prefs): Show
+ assumed prefs for hash and compression as well as the cipher pref.
+ Show assumed prefs if there are no prefs at all on a v4
+ self-signed key.
+
+ * options.h, g10.c (main), sign.c (make_keysig_packet): New
+ --cert-digest-algo function to override the default key signing
+ hash algorithm.
+
+2002-05-09 David Shaw <dshaw@jabberwocky.com>
+
+ * getkey.c (merge_selfsigs_main): Make sure the revocation key
+ list starts clean as this function may be called more than once
+ (e.g. from functions in --edit).
+
+ * g10.c, encode.c (encode_crypt), sign.c (sign_file,
+ sign_symencrypt_file): Make --compress-algo work like the
+ documentation says. It should be like --cipher-algo and
+ --digest-algo in that it can override the preferences calculation
+ and impose the setting the user wants. No --compress-algo setting
+ allows the usual preferences calculation to take place.
+
+ * main.h, compress.c (compress_filter): use new
+ DEFAULT_COMPRESS_ALGO define, and add a sanity check for compress
+ algo value.
+
+2002-05-08 David Shaw <dshaw@jabberwocky.com>
+
+ * pkclist.c (select_algo_from_prefs): There is an assumed
+ compression preference for uncompressed data.
+
+2002-05-07 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, g10.c (main), getkey.c (finish_lookup), pkclist.c
+ (algo_available): --pgp7, identical to --pgp6 except that it
+ permits a few algorithms that PGP 7 added: AES128, AES192, AES256,
+ and TWOFISH. Any more of these --pgpX flags, and it'll be time to
+ start looking at a generic --emulate-pgp X option.
+
+ * export.c (do_export_stream): Warn the user when exporting a
+ secret key if it or any of its secret subkeys are protected with
+ SHA1 while simple_sk_checksum is set.
+
+ * parse-packet.c (parse_key): Show when the SHA1 protection is
+ used in --list-packets.
+
+ * options.h, build-packet.c (do_comment), g10.c (main): Rename
+ --no-comment as --sk-comments/--no-sk-comments (--no-comment still
+ works) and make the default be --no-sk-comments.
+
+2002-05-07 Werner Koch <wk@gnupg.org>
+
+ * keygen.c (get_parameter_algo): Never allow generation of the
+ deprecated RSA-E or RSA-S flavors of PGP RSA.
+ (ask_algo): Allow generation of RSA sign and encrypt in expert
+ mode. Don't allow ElGamal S+E unless in expert mode.
+ * helptext.c: Added entry keygen.algo.rsa_se.
+
+2002-05-07 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (sign_uids): If --expert is set, allow re-signing a
+ uid to promote a v3 self-sig to a v4 one. This essentially
+ deletes the old v3 self-sig and replaces it with a v4 one.
+
+ * packet.h, parse-packet.c (parse_key), getkey.c
+ (merge_keys_and_selfsig, merge_selfsigs_main): a v3 key with a v4
+ self-sig must never let the v4 self-sig express a key expiration
+ time that extends beyond the original v3 expiration time.
+
+2002-05-06 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (sign_uids): When making a self-signature via "sign"
+ don't ask about sig level or expiration, and include the usual
+ preferences and such for v4 self-sigs. (menu_set_preferences):
+ Convert uids from UTF8 to native before printing.
+
+ * keyedit.c (sign_uids): Convert uids from UTF8 to native before
+ printing. (menu_set_primary_uid): Show error if the user tries to
+ make a uid with a v3 self-sig primary.
+
+2002-05-05 David Shaw <dshaw@jabberwocky.com>
+
+ * import.c (import_one): When merging with a key we already have,
+ don't let a key conflict (same keyid but different key) stop the
+ import: just skip the bad key and continue.
+
+ * exec.c (make_tempdir): Under Win32, don't try environment
+ variables for temp directories - GetTempDir tries environment
+ variables internally, and it's better not to second-guess it in
+ case MS adds some sort of temp dir handling to Windows at some
+ point.
+
+2002-05-05 Timo Schulz <ts@winpt.org>
+
+ * mainproc.c (proc_symkey_enc): Don't ask for a passphrase
+ in the list only mode.
+
+2002-05-05 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_refresh): --refresh-keys implies
+ --merge-only so as not to import keys with keyids that match the
+ ones being refreshed. Noted by Florian Weimer.
+
+2002-05-04 Stefan Bellon <sbellon@sbellon.de>
+
+ * free-packet.c (copy_public_key): Don't call m_alloc(0), therefore
+ added consistency check for revkey and numrefkeys.
+
+ * getkey.c (check_revocation_keys): Added consistency check for
+ revkey and numrefkeys.
+
+ * keyedit.c (show_key_with_all_names): Likewise.
+
+2002-05-03 David Shaw <dshaw@jabberwocky.com>
+
+ * photoid.c: Provide default image viewer for Win32.
+
+ * misc.c (pct_expando): %t means extension, not name ("jpg", not
+ "jpeg").
+
+ * keyserver.c (keyserver_spawn), photoid.c (show_photos), exec.h,
+ exec.c: Allow the caller to determine the temp file extension when
+ starting an exec_write and change all callers.
+
+ * keyedit.c (sign_uids): Nonrevocable key signatures cause an
+ automatic promotion to v4.
+
+ * exec.c: Provide stubs for exec_ functions when NO_EXEC is
+ defined.
+
+2002-05-02 David Shaw <dshaw@jabberwocky.com>
+
+ * photoid.h, photoid.c (parse_image_header, image_type_to_string):
+ Useful functions to return data about an image.
+
+ * packet.h, parse-packet.c (make_attribute_uidname,
+ parse_attribute_subpkts, parse_attribute), photoid.h, photoid.c
+ (show_photos): Handle multiple images in a single attribute
+ packet.
+
+ * main.h, misc.c (pct_expando), sign.c (mk_notation_and_policy),
+ photoid.c (show_photos): Simpler expando code that does not
+ require using compile-time string sizes. Call
+ image_type_to_string to get image strings (i.e. "jpg",
+ "image/jpeg"). Change all callers.
+
+ * keyedit.c (menu_showphoto), keylist.c (list_keyblock_print):
+ Allow viewing multiple images within a single attribute packet.
+
+ * gpgv.c: Various stubs for link happiness.
+
+2002-05-02 David Shaw <dshaw@jabberwocky.com>
+
+ * build-packet.c (build_sig_subpkt), keyedit.c (sign_uids),
+ options.h, sign.c (mk_notation_and_policy), g10.c (main,
+ add_notation_data, add_policy_url (new), check_policy_url
+ (removed)): Allow multiple policy URLs on a given signature.
+ Split "--notation-data" into "--cert-notation" and
+ "--sig-notation" so the user can set different policies for key
+ and data signing. For backwards compatibility, "--notation-data"
+ sets both, as before.
+
+2002-05-02 Werner Koch <wk@gnupg.org>
+
+ * options.skel: Removed the comment on trusted-keys because this
+ option is now deprecated.
+
+2002-05-01 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (menu_adduid): 2440bis04 says that multiple attribute
+ packets on a given key are legal.
+
+ * keyserver.c (keyserver_refresh): the fake v3 keyid hack applies
+ to "mailto" URLs as well since they are also served by pksd.
+
+2002-04-29 Werner Koch <wk@gnupg.org>
+
+ Added a copyright year for files changed this year.
+
+2002-04-25 Werner Koch <wk@gnupg.org>
+
+ * g10.c, options.h: New options --display, --ttyname, --ttytype,
+ --lc-ctype, --lc-messages to be used with future versions of the
+ gpg-agent.
+ * passphrase.c (agent_send_option,agent_send_all_options): New.
+ (agent_open): Send options to the agent.
+
+ * trustdb.c (update_ownertrust, clear_ownertrust): Do an explicit
+ do_sync because revalidation_mark does it only if when the
+ timestamp actually changes.
+
+2002-04-23 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, keygen.c (do_generate_keypair), keylist.c
+ (print_signature_stats, list_all, list_one, list_keyblock,
+ list_keyblock_print, list_keyblock_colon): After generating a new
+ key, show the key information (name, keyid, fingerprint, etc.)
+ Also do not print uncheckable signatures (missing key..) in
+ --check-sigs. Print statistics (N missing keys, etc.) after
+ --check-sigs.
+
+ * keyedit.c (sign_uids): When signing a key with an expiration
+ date on it, the "Do you want your signature to expire at the same
+ time?" question should default to YES.
+
+2002-04-22 David Shaw <dshaw@jabberwocky.com>
+
+ * parse-packet.c (parse_plaintext), packet.h, plaintext.c
+ (handle_plaintext): Fix bug in handling literal packets with
+ zero-length data (no data was being confused with partial body
+ length).
+
+ * misc.c (pct_expando), options.skel: %t means extension ("jpg").
+ %T means MIME type ("image/jpeg").
+
+ * import.c (import_one): Only trigger trust update if the keyring
+ is actually changed.
+
+ * export.c (do_export_stream): Missing a m_free.
+
+2002-04-22 Stefan Bellon <sbellon@sbellon.de>
+
+ * keyid.c (expirestr_from_sk, expirestr_from_sig): Added _() to
+ string constant.
+
+ * exec.c (make_tempdir) [__riscos__]: Better placement of
+ temporary file.
+
+2002-04-20 David Shaw <dshaw@jabberwocky.com>
+
+ * keygen.c (generate_subkeypair): 2440bis04 adds that creating
+ subkeys on v3 keys is a MUST NOT.
+
+ * getkey.c (finish_lookup): The --pgp6 "use the primary key"
+ behavior should only apply while data signing and not encryption.
+ Noted by Roger Sondermann.
+
+2002-04-19 Werner Koch <wk@gnupg.org>
-2000-10-11 Werner Koch <wk@gnupg.org>
+ * keygen.c (keygen_set_std_prefs): Put back 3DES because the RFC
+ says it is good form to do so.
- * packet.h: Add features sig subpacket definition.
- * parse-packet.c (dump_sig_subpkt,parse_one_sig_subpkt,
- can_handle_critical): Implemented it here.
- * build-packet.c (build_sig_subpkt): and here.
- * keygen.c (keygen_add_std_prefs): Generate a features packet.
+2002-04-19 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (menu_deluid): Only cause a trust update if we delete
+ a non-revoked user id.
+
+ * hkp.c (hkp_ask_import), keyserver.c (parse_keyserver_options,
+ keyserver_spawn), options.h: Remove fast-import keyserver option
+ (no longer meaningful).
+
+ * g10.c (main), keyedit.c (sign_uids), options.h: Change
+ --default-check-level to --default-cert-check-level as it makes
+ clear what it operates on.
+
+ * g10.c (main): --pgp6 also implies --no-ask-sig-expire.
+
+ * delkey.c (do_delete_key): Comment.
+
+ * keyedit.c (sign_uids, keyedit_menu, menu_deluid, menu_delsig,
+ menu_expire, menu_revsig, menu_revkey): Only force a trustdb check
+ if we did something that changes it.
+
+ * g10.c: add "--auto-check-trustdb" to override a
+ "--no-auto-check-trustdb"
+
+2002-04-19 Werner Koch <wk@gnupg.org>
+
+ * tdbio.c (tdbio_write_nextcheck): Return a status whether the
+ stamp was actually changed.
+ * trustdb.c (revalidation_mark): Sync the changes. Removed the
+ sync operation done by its callers.
+ (get_validity): Add logic for maintaining a pending_check flag.
+ (clear_ownertrust): New.
+
+ * keyedit.c (sign_uids): Don't call revalidation_mark depending on
+ primary_pk.
+ (keyedit_menu): Call revalidation_mark after "trust".
+ (show_key_with_all_names): Print a warning on the wrong listed key
+ validity.
+
+ * delkey.c (do_delete_key): Clear the owenertrust information when
+ deleting a public key.
-2000-10-09 Werner Koch <wk@gnupg.org>
+2002-04-18 Werner Koch <wk@gnupg.org>
+
+ * seskey.c (encode_md_value): Print an error message if a wrong
+ digest algorithm is used with DSA. Changed all callers to cope
+ with a NULL return. Problem noted by Imad R. Faiad.
+
+2002-04-18 David Shaw <dshaw@jabberwocky.com>
+
+ * trustdb.c (mark_usable_uid_certs): Properly handle nonrevocable
+ signatures that can expire. In short, the only thing that can
+ override an unexpired nonrevocable signature is another unexpired
+ nonrevocable signature.
+
+ * getkey.c (finish_lookup): Always use primary signing key for
+ signatures when --pgp6 is on since pgp6 and 7 do not understand
+ signatures made by signing subkeys.
+
+2002-04-18 Werner Koch <wk@gnupg.org>
+
+ * trustdb.c (validate_keys): Never schedule a nextcheck into the
+ past.
+ (validate_key_list): New arg curtime use it to set next_expire.
+ (validate_one_keyblock): Take the current time from the caller.
+ (clear_validity, reset_unconnected_keys): New.
+ (validate_keys): Reset all unconnected keys.
+
+ * getkey.c (premerge_public_with_secret): Fixed 0x12345678! syntax
+ for use with secret keys.
+ (lookup): Advance the searchmode after a search FIRST.
+
+ * seckey-cert.c (do_check): Always calculate the old checksum for
+ use after unprotection.
+
+ * g10.c, options.skel: New option --no-escape-from. Made
+ --escape-from and --force-v3-sigs the default and removed them
+ from the options skeleton.
+
+2002-04-16 Werner Koch <wk@gnupg.org>
+
+ * parse-packet.c (parse_key): Support a SHA1 checksum as per
+ draft-rfc2440-bis04.
+ * packet.h (PKT_secret_key): Add field sha1chk.
+ * seckey-cert.c (do_check): Check the SHA1 checksum
+ (protect_secret_key): And create it.
+ * build-packet.c (do_secret_key): Mark it as sha-1 protected.
+ * g10.c, options.h: New option --simple-sk-checksum.
+
+2002-04-13 David Shaw <dshaw@jabberwocky.com>
+
+ * parse-packet.c (parse_signature): Minor fix - signatures should
+ expire at their expiration time and not one second later.
+
+ * keygen.c (proc_parameter_file): Allow specifying preferences
+ string (i.e. "s5 s2 z1 z2", etc) in a batchmode key generation
+ file.
+
+ * keyedit.c (keyedit_menu): Print standard error message when
+ signing a revoked key (no new translation).
+
+ * getkey.c (merge_selfsigs): Get the default set of key prefs from
+ the real (not attribute) primary uid.
+
+2002-04-12 David Shaw <dshaw@jabberwocky.com>
+
+ * pkclist.c (build_pk_list): Fix bug that allowed a key to be
+ selected twice in batch mode if one instance was the default
+ recipient and the other was an encrypt-to. Noted by Stefan
+ Bellon.
+
+ * parse-packet.c (dump_sig_subpkt): Show data in trust and regexp
+ sig subpackets.
+
+ * keyedit.c (keyedit_menu): Use new function real_uids_left to
+ prevent deleting the last real (i.e. non-attribute) uid. Again,
+ according to the attribute draft. (menu_showphoto): Make another
+ string translatable.
+
+2002-04-11 David Shaw <dshaw@jabberwocky.com>
+
+ * build-packet.c (build_sig_subpkt): Delete subpackets from both
+ hashed and unhashed area on update. (find_subpkt): No longer
+ needed.
+
+ * keyedit.c (sign_uids): With --pgp2 on, refuse to sign a v3 key
+ with a v4 signature. As usual, --expert overrides. Try to tweak
+ some strings to a closer match so they can all be translated in
+ one place. Use different helptext keys to allow different help
+ text for different questions.
+
+ * keygen.c (keygen_upd_std_prefs): Remove preferences from both
+ hashed and unhashed areas if they are not going to be used.
+
+2002-04-10 David Shaw <dshaw@jabberwocky.com>
+
+ * misc.c (pct_expando), options.skel: Use %t to indicate type of a
+ photo ID (in this version, it's always "jpeg"). Also tweak string
+ expansion loop to minimize reallocs.
+
+ * mainproc.c (do_check_sig): Variable type fix.
+
+ * keyedit.c (menu_set_primary_uid): Differentiate between true
+ user IDs and attribute user IDs when making one of them primary.
+ That is, if we are making a user ID primary, we alter user IDs.
+ If we are making an attribute packet primary, we alter attribute
+ packets. This matches the language in the latest attribute packet
+ draft.
+
+ * keyedit.c (sign_uids): No need for the empty string hack.
+
+ * getkey.c (fixup_uidnode): Only accept preferences from the
+ hashed segment of the self-sig.
+
+2002-04-10 Werner Koch <wk@gnupg.org>
+
+ * tdbio.c (migrate_from_v2): Fixed the offset to read the old
+ ownertrust value and only add entries to the table if we really
+ have a value.
+
+2002-04-08 David Shaw <dshaw@jabberwocky.com>
+
+ * status.h, status.c (get_status_string): Add KEYEXPIRED, EXPSIG,
+ and EXPKEYSIG. Add "deprecated-use-keyexpired-instead" to
+ SIGEXPIRED.
+
+ * sig-check.c (do_check): Start transition from SIGEXPIRED to
+ KEYEXPIRED, since the actual event is signature verification by an
+ expired key and not an expired signature. (do_signature_check,
+ packet.h): Rename as signature_check2, make public, and change all
+ callers.
+
+ * mainproc.c (check_sig_and_print, do_check_sig): Use status
+ EXPSIG for an expired, but good, signature. Add the expiration
+ time (or 0) to the VALIDSIG status line. Use status KEYEXPSIG for
+ a good signature from an expired key.
+
+ * g10.c (main): remove checks for no arguments now that argparse
+ does it.
+
+2002-04-06 Werner Koch <wk@gnupg.org>
+
+ * keyring.c (keyring_get_keyblock): Disable the keylist mode here.
+
+ * encode.c (encode_simple, encode_crypt): Only test on compressed
+ files if a compress level was not explicity set.
+
+ * keygen.c (keygen_set_std_prefs): Removed Blowfish and Twofish
+ from the list of default preferences, swapped the preferences of
+ RMD160 and SHA1. Don't include a preference to 3DES unless the
+ IDEA kludge gets used.
+
+ * free-packet.c (free_packet): call free_encrypted also for
+ PKT_ENCRYPTED_MDC.
+
+ * compress.c (release_context): New.
+ (handle_compressed): Allocate the context and setup a closure to
+ release the context. This is required because there is no
+ guarabntee that the filter gets popped from the chain at the end
+ of the function. Problem noted by Timo and probably also the
+ cause for a couple of other reports.
+ (compress_filter): Use the release function if set.
+
+ * tdbio.c [__CYGWIN32__]: Don't rename ftruncate. Noted by
+ Disastry.
+
+ * parse-packet.c (parse_signature): Put parens around a bit test.
+
+ * exec.c (make_tempdir): Double backslash for TMP directory
+ creation under Windows. Better strlen the DIRSEP_S constants for
+ allocation measurements.
+
+ * decrypt.c (decrypt_messages): Release the passphrase aquired
+ by get_last_passphrase.
- * keygen.c (do_generate_keypair): Removed the keyblock locking.
+2002-04-02 Werner Koch <wk@gnupg.org>
- * ringedit.c (enum_keyblocks): Replaced by ...
- (enum_keyblocks_begin): New.
- (enum_keyblocks_next): New.
- (enum_keyblocks_end): New. And changed all callers.
+ * Makefile.am (EXTRA_DIST): Removed OPTIONS an pubring.asc - they
+ are no longer of any use.
+
+2002-04-03 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (parse_keyserver_options): fix auto-key-retrieve to
+ actually work as a keyserver-option (noted by Roger Sondermann).
+
+ * keylist.c (reorder_keyblock): do not reorder the primary
+ attribute packet - the first user ID must be a genuine one.
+
+2002-03-31 David Shaw <dshaw@jabberwocky.com>
+
+ * keylist.c (list_keyblock_colon): Fix ownertrust display with
+ --with-colons.
+
+ * keygen.c (generate_user_id), photoid.c (generate_photo_id):
+ Properly initialize the user ID refcount. A few more "y/n" ->
+ "y/N" in photoid.c.
+
+ * keyedit.c (ask_revoke_sig): Warn the user if they are about to
+ revoke an expired sig (not a problem, but they should know). Also
+ tweak a few prompts to change "y/n" to "y/N", which is how most
+ other prompts are written.
+
+ * keyserver.c (keyserver_search_prompt): Control-d escapes the
+ keyserver search prompt.
+
+ * pkclist.c (show_revocation_reason & callers): If a subkey is
+ considered revoked solely because the parent key is revoked, print
+ the revocation reason from the parent key.
+
+ * trustdb.c (get_validity): Allow revocation/expiration to apply
+ to a uid/key with no entry in the trustdb.
+
+2002-03-29 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (printunquoted): unquote backslashes from keyserver
+ searches
+
+ * hkp.c (write_quoted): quote backslashes from keyserver searches
+
+2002-03-26 Werner Koch <wk@gnupg.org>
+
+ * keygen.c (ask_keysize): Removed the warning for key sizes > 1536.
+
+2002-03-25 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (sign_uids): Use 2 strings and not a %s so that
+ translations can be done the right way.
+ * helptext.c: Fixed small typo.
+
+2002-03-23 David Shaw <dshaw@jabberwocky.com>
+
+ * import.c (append_uid, merge_sigs): it is okay to import
+ completely non-signed uids now (with --allow-non-selfsigned-uid).
+
+ * getkey.c (get_primary_uid, merge_selfsigs_main): do not choose
+ an attribute packet (i.e. photo) as primary uid. This prevents
+ oddities like "Good signature from [image of size 2671]". This is
+ still not perfect (one can still select an attribute packet as
+ primary in --edit), but is closer to the way the draft is going.
+
+ * g10.c (build_list): algorithms should include 110.
+
+ * g10.c (main): --pgp2 implies --no-ask-sig-expire and
+ --no-ask-cert-expire as those would cause a v4 sig/cert.
+
+ * armor.c (is_armor_header): be more lenient in what constitutes a
+ valid armor header (i.e. -----BEGIN blah blah-----) as some
+ Windows programs seem to add spaces at the end. --openpgp makes
+ it strict again.
+
+2002-03-18 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_search_prompt): Properly handle a "no
+ keys found" case from the internal HKP code (external HKP is ok).
+ Also, make a COUNT -1 (i.e. streamed) keyserver response a little
+ more efficient.
+
+ * g10.c (main): Add --no-allow-non-selfsigned-uid
+
+2002-03-17 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (main): --openpgp implies --allow-non-selfsigned-uid.
+
+ * getkey.c (merge_selfsigs_main): If none of the uids are primary
+ (because none are valid) then pick the first to be primary (but
+ still invalid). This is for cosmetics in case some display needs
+ to print a user ID from a non-selfsigned key. Also use
+ --allow-non-selfsigned-uid to make such a key valid and not
+ --always-trust. The key is *not* automatically trusted via
+ --allow-non-selfsigned-uid.
+
+ * mainproc.c (check_sig_and_print): Make sure non-selfsigned uids
+ print [uncertain] on verification even though one is primary now.
+
+ * getkey.c (merge_selfsigs): If the main key is not valid, then
+ neither are the subkeys.
+
+ * import.c (import_one): Allow --allow-non-selfsigned-uid to work
+ on completely unsigned keys. Print the uids in UTF8. Remove
+ mark_non_selfsigned_uids_valid().
+
+ * keyedit.c (show_key_with_all_names): Show revocation key as
+ UTF8.
+
+ * sign.c (clearsign_file): Allow --not-dash-escaped to work with
+ v3 keys.
+
+2002-03-14 Werner Koch <wk@gnupg.org>
+
+ * main.h: Changed the default algorithms to CAST5 and SHA1.
+
+2002-03-13 David Shaw <dshaw@jabberwocky.com>
+
+ * import.c (chk_self_sigs): Show which user ID a bad self-sig
+ (invald sig or unsupported public key algorithm) resides on.
+
+ * import.c (chk_self_sigs): any valid self-sig should mark a user
+ ID or subkey as valid - otherwise, an attacker could DoS the user
+ by inventing a bogus invalid self-signature.
+
+2002-03-07 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (main): make a few more strings translatable.
+
+ * options.h, options.skel, g10.c (main), gpgv.c, mainproc.c
+ (check_sig_and_print), keyserver.c (parse_keyserver_options):
+ --auto-key-retrieve should really be a keyserver-option variable.
+
+ * import.c (revocation_present): new function to print a warning
+ if a key is imported that has been revoked by designated revoker,
+ but the designated revoker is not present to verify the
+ revocation. If keyserver-options auto-key-retrieve is set, try
+ and fetch the designated revoker from the keyserver.
+
+ * import.c (import_one): call revocation_present after importing a
+ new key. Note that this applies to --import, --recv-keys, and
+ --search-keys.
+
+ * keyserver-internal.h, keyserver.c (keyserver_import_fprint):
+ import via fingerprint (for revocation keys).
+
+ * keyserver.c (keyserver_import_keyid): much simpler
+ implementation now that we're using KEYDB_SEARCH_DESC internally.
+
+2002-03-04 David Shaw <dshaw@jabberwocky.com>
+
+ * revoke.c (gen_revoke): do not prompt for revocation reason for
+ v3 revocations (unless force-v4-certs is on) since they wouldn't
+ be used anyway.
+
+ * keyedit.c (menu_revsig): show the status of the sigs
+ (exportable? revocable?) to the user before prompting for which
+ sig to revoke. Also, make sure that local signatures get local
+ revocations.
+
+ * keyedit.c (ask_revoke_sig): remind the user which sigs are
+ local.
+
+ * g10.c (main): Add "exec-path" variable to override PATH for
+ execing programs.
+
+ * export.c (do_export_stream): properly check return code from
+ classify_user_id to catch unclassifiable keys.
+
+2002-03-03 David Shaw <dshaw@jabberwocky.com>
+
+ * parse-packet.c (parse_signature): variable type tweak for RISC
+ OS (from Stefan)
+
+2002-02-28 David Shaw <dshaw@jabberwocky.com>
+
+ * getkey.c (check_revocation_keys): New function to check a
+ revocation against a list of potential revocation keys. Note the
+ loop-breaking code here. This is to prevent blowing up if A is
+ B's revocation key, while B is also A's. Note also that this is
+ written so that a revoked revoker can still issue revocations:
+ i.e. If A revokes B, but A is revoked, B is still revoked. I'm
+ not completely convinced this is the proper behavior, but it
+ matches how PGP does it. It does at least have the advantage of
+ much simpler code - my first version of this had lots of loop
+ maintaining code so you could chain revokers many levels deep and
+ if D was revoked, C was not, which meant that B was, and so on.
+ It was sort of scary, actually.
+
+ * getkey.c (merge_selfsigs_main): Add any revocation keys onto the
+ pk. This is particularly interesting since we normally only get
+ data from the most recent 1F signature, but you need multiple 1F
+ sigs to properly handle revocation keys (PGP does it this way, and
+ a revocation key could be marked "sensitive" and hence in a
+ different signature). Also, if a pk has a revocation key set,
+ check for revocation sigs that were not made by us - if made by a
+ valid revocation key, mark the pk revoked.
+
+ * packet.h, getkey.c (cache_public_key): do not cache key if
+ "dont_cache" is set. This allows the revocation key code to look
+ up a key and return information that may be inaccurate to prevent
+ loops without caching the fake data.
+
+ * packet.h, sig-check.c (do_signature_check): Record if a
+ signature was made by a revoked pk.
+
+ * packet.h, parse-packet.c (parse_one_sig_subpkt,
+ can_handle_critical, parse_signature): Get revocation key
+ information out of direct sigs.
- * import.c (import_one): Removed keyblock locking becuase this is
- now done inside of insert_keyblock(). Removed get_keyblock_handle
- because insert_keyblock() now decides what is the default keyring.
+ * keylist.c (list_keyblock_print): don't assume that the presence
+ of a 0x20 signature means the key is revoked. With revocation
+ keys, this may not be true if the revocation key is not around to
+ verify it or if verification failed. Also, 0x1F should get listed
+ as "sig", and not "unexpected signature class".
+
+ * keyedit.c (show_key_with_all_names): Add a flag for printing
+ revoker information and change all callers.
+
+ * import.c (merge_blocks): merge in any new direct key (0x1F)
+ sigs.
+
+ * import.c (import_revoke_cert): don't keep processing after a
+ revocation is rejected.
+
+ * import.c (delete_inv_parts): Allow importing a revocation
+ signature even if it was not issued by the key. This allows a
+ revocation key to issue it. Of course, the sig still needs to be
+ checked before we trust it.
+
+ * free-packet.c (copy_public_key): Include a new copy of the
+ revocation keys when duping a pk.
+
+ * free-packet.c (free_seckey_enc, release_public_key_parts): Free
+ any revocation keys that are attached to a sig or pk.
+
+ * export.c (do_export_stream): Do not export signatures with
+ "sensitive" revocation keys in them.
+
+2002-02-27 David Shaw <dshaw@jabberwocky.com>
+
+ * export.c (do_export_stream): Do not include v3 keys in a
+ --export-secret-subkeys export.
+
+ * getkey.c (merge_selfsigs_main): If a key isn't valid (say,
+ because of no self-signature), allow --always-trust to force it
+ valid so it can be trusted.
+
+2002-02-25 David Shaw <dshaw@jabberwocky.com>
+
+ * hkp.c (hkp_ask_import), hkp.h, keyserver.c (all): treat key
+ lists internally as fingerprints when possible. All this is via
+ KEYDB_SEARCH_DESC - no point in reinventing the wheel. This allows
+ the helper program to search the keyserver by fingerprint if
+ desired (and the keyserver supports it). Note that automatic
+ fingerprint promotion during refresh only applies to v4 keys as a
+ v4 fingerprint can be easily changed into a long or short key id,
+ and a v3 cannot.
+
+ * pubkey-enc.c, getkey.c, misc.c, main.h: Take two copies of
+ hextobyte() from pubkey-enc.c and getkey.c and make them into one
+ copy in misc.c.
+
+2002-02-22 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_search_prompt): Detect a "no keys found"
+ case even if the helper program does not explicitly say how many
+ keys were found.
+
+ * hkp.c (parse_hkp_index): Bug fix - don't report non-revoked keys
+ as revoked in HKP key searches.
+
+2002-02-19 Werner Koch <wk@gnupg.org>
+
+ * parse-packet.c (parse_trust): Made parsing more robust.
+
+2002-02-19 David Shaw <dshaw@jabberwocky.com>
+
+ * hkp.c (parse_hkp_index): Catch corruption in HKP index lines
+ (can be caused by broken or malicious keyservers).
+
+ * keyserver.c (keyserver_work): Add KEYSERVER_NOT_SUPPORTED for
+ unsupported actions (say, a keyserver that has no way to search,
+ or a readonly keyserver that has no way to add). Also add a
+ USE_EXTERNAL_HKP define to disable the internal HKP keyserver
+ code.
+
+2002-02-14 Werner Koch <wk@gnupg.org>
+
+ * g10.c: New option --no-use-agent.
+
+ * pkclist.c (check_signatures_trust): Always print the warning for
+ unknown and undefined trust. Removed the did_add cruft. Reported
+ by Janusz A. Urbanowicz.
+
+2002-02-11 David Shaw <dshaw@jabberwocky.com>
+
+ * hkp.c (parse_hkp_index): Bug fix - properly handle user IDs with
+ colons (":") in them while HKP searching.
+
+2002-02-09 David Shaw <dshaw@jabberwocky.com>
+
+ * misc.c (pct_expando): More comments.
+
+ * keydb.h, sign.c (mk_notation_and_policy): Clarify what is a sig
+ and what is a cert. A sig has sigclass 0x00, 0x01, 0x02, or 0x40,
+ and everything else is a cert.
+
+ * g10.c (main), keyedit.c (keyedit_menu): Add a "nrlsign" for
+ nonrevocable and local key signatures.
+
+ * g10.c (main): Add a --no-force-mdc to undo --force-mdc.
+
+ * options.h, g10.c (main), cipher.c (write_header): Add a knob to
+ --disable-mdc/--no-disable-mdc. Off by default, of course, but is
+ used in --pgp2 and --pgp6 modes.
+
+ * pkclist.c (build_pk_list): Allow specifying multiple users in
+ the "Enter the user ID" loop. Enter a blank line to stop. Show
+ each key+id as it is added.
+
+ * keylist.c (show_policy_url), mainproc.c (print_notation_data):
+ It is not illegal (though possibly silly) to have multiple policy
+ URLs in a given signature, so print all that are present.
+
+ * hkp.c (hkp_search): More efficient implementation of URL-ifying
+ code.
+
+2002-02-04 David Shaw <dshaw@jabberwocky.com>
+
+ * main.h, misc.c (pct_expando): New function to generalize
+ %-expando processing in any arbitrary string.
+
+ * photoid.c (show_photo): Call the new pct_expando function rather
+ than expand strings internally.
+
+ * sign.c (mk_notation_and_policy): Show policy URLs and notations
+ when making a signature if show-policy/show-notation is on.
+ %-expand policy URLs during generation. This lets the user have
+ policy URLs of the form "http://notary.jabberwocky.com/keysign/%K"
+ which will generate a per-signature policy URL.
+
+ * main.h, keylist.c (show_policy_url, show_notation): Add amount
+ to indent so the same function can be used in key listings as well
+ as during sig generation. Change all callers.
+
+2002-02-04 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c, options.h (parse_keyserver_options, keyidlist):
+ Workaround for the pksd and OKS keyserver bug that calculates v4
+ RSA keyids as if they were v3. The workaround/hack is to fetch
+ both the v4 (e.g. 99242560) and v3 (e.g. 68FDDBC7) keyids. This
+ only happens for key refresh while using the HKP scheme and the
+ refresh-add-fake-v3-keyids keyserver option must be set. This
+ should stay off by default.
+
+2002-02-03 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_spawn): Bug fix - do not append keys to
+ each other when --sending more than one.
+
+2002-02-02 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, g10.c (main), keyedit.c (sign_uids), sign.c
+ (mk_notation_and_policy): Split "--set-policy-url" into
+ "--cert-policy-url" and "--sig-policy-url" so the user can set
+ different policies for key and data signing. For backwards
+ compatibility, "--set-policy-url" sets both, as before.
+
+2002-01-30 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): --gen-random --armor does now output a base64
+ encoded string.
+
+2002-01-28 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (main), options.h, pkclist.c (algo_available): --pgp6
+ flag. This is not nearly as involved as --pgp2. In short, it
+ turns off force_mdc, turns on no_comment, escape_from, and
+ force_v3_sigs, and sets compression to 1. It also restricts the
+ user to IDEA (if present), 3DES, CAST5, MD5, SHA1, and RIPEMD160.
+ See the comments above algo_available() for lots of discussion on
+ why you would want to do this.
+
+2002-01-27 David Shaw <dshaw@jabberwocky.com>
+
+ * keygen.c (keygen_set_std_prefs): Comment
+
+ * keyedit.c (sign_uids): Bug fix - when signing with multiple
+ secret keys at the same time, make sure each key gets the sigclass
+ prompt.
+
+ * exec.c (exec_finish): Close the iobuf and FILE before trying to
+ waitpid, so the remote process will get a SIGPIPE and exit. This
+ is only a factor when using a pipe to communicate.
+
+ * exec.c (exec_write): Disable cache-on-close of the fd iobuf (is
+ this right? Why is a fd iobuf cached at all?)
+
+2002-01-26 Werner Koch <wk@gnupg.org>
+
+ * g10.c, options.h: New option --gpg-agent-info
+ * passphrase.c (agent_open): Let it override the environment info.
+ * seckey-cert.c (check_secret_key): Always try 3 times when the
+ agent is enabled.
+ * options.skel: Describe --use-agent.
+
+2002-01-24 David Shaw <dshaw@jabberwocky.com>
+
+ * pubkey-enc.c (is_algo_in_prefs, get_it): Only check preferences
+ against keys with v4 self sigs - there is really little point in
+ warning for every single non-IDEA message encrypted to an old key.
+
+ * pkclist.c (select_algo_from_prefs): Only put in the fake IDEA
+ preference if --pgp2 is on.
+
+ * mainproc.c (check_sig_and_print): Print "Expired" for expired
+ but good signatures (this still prints "BAD" for expired but bad
+ signatures).
+
+2002-01-23 David Shaw <dshaw@jabberwocky.com>
+
+ * keygen.c (ask_keysize): Cosmetic: don't present a RSA signing
+ key as a "keypair" which can be 768 bits long (as RSA minimum is
+ 1024).
+
+ * pubkey-enc.c (is_algo_in_prefs): Allow IDEA as a fake preference
+ for v3 keys with v3 selfsigs.
+
+2002-01-22 David Shaw <dshaw@jabberwocky.com>
+
+ * packet.h, getkey.c (merge_selfsigs_main), pkclist.c
+ (select_algo_from_prefs): Implement the fake IDEA preference as
+ per RFC2440:12.1. This doesn't mean that IDEA will be used (the
+ plugin may not be present), but it does mean that a v3 key with a
+ v3 selfsig has an implicit IDEA preference instead of 3DES. v3
+ keys with v4 selfsigs use preferences as normal.
+
+ * encode.c (encode_crypt): if select_algo_from_prefs fails, this
+ means that we could not find a cipher that both keys like. Since
+ all v4 keys have an implicit 3DES preference, this means there is
+ a v3 key with a v3 selfsig in the list. Use 3DES in this case as
+ it is the safest option (we know the v4 key can handle it, and
+ we'll just hope the v3 key is being used in an implementation that
+ can handle it). If --pgp2 is on, warn the user what we're doing
+ since it'll probably break PGP2 compatibility.
+
+ * g10.c (main): Do not force using IDEA for encrypted files in
+ --pgp2 mode - let the fake IDEA preference choose this for us for
+ better compatibility when encrypting to multiple keys, only some
+ of which are v3.
+
+ * keygen.c (keygen_set_std_prefs): Put 3DES on the end of the
+ default cipher pref list (RFC2440: "...it is good form to place it
+ there explicitly."). If the user has the IDEA plugin installed,
+ put a preference for IDEA *after* 3DES to effectively disable its
+ use for everything except encrypting along with v3 keys.
+
+ * encode.c, g10.c, sign.c: Change the PGP2 warning line from
+ "... will not be usable ..." to "... may not be usable ..." as the
+ user could be using one of the enhanced PGP2 variations.
+
+ * helptext.c: Revise the sign_uid.class help text as suggested by
+ Stefan.
+
+2002-01-20 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c (passphrase_to_dek): Add tryagain_text arg to be
+ used with the agent. Changed all callers.
+ (agent_get_passphrase): Likewise and send it to the agent
+ * seckey-cert.c (do_check): New arg tryagain_text.
+ (check_secret_key): Pass the string to do_check.
+ * keygen.c (ask_passphrase): Set the error text is required.
+ * keyedit.c (change_passphrase): Ditto.
+
+ * passphrase.c (agent_open): Disable opt.use_agent in case of a
+ problem with the agent.
+ (agent_get_passphrase): Ditto.
+ (passphrase_clear_cache): Ditto.
+
+2002-01-19 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c (agent_open): Add support for the new Assuan based
+ gpg-agent. New arg to return the used protocol version.
+ (agent_get_passphrase): Implemented new protocol here.
+ (passphrase_clear_cache): Ditto.
+ (readline): New.
+
+2002-01-15 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_crypt_files): Fail if --output is used.
+
+ * g10.c: New command --decrypt-files.
+
+ * decrypt.c (decrypt_messages): New.
+
+2002-01-09 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c, misc.c, gpgv.c: move idea_cipher_warn to misc.c so gpgv.c
+ doesn't need a stub for it any longer.
+
+ * g10.c (get_temp_dir), main.h: no longer used (it's in exec.c now)
+
+ * g10.c (main), delkey.c (delete_keys), main.h : Allow
+ --delete-key (now --delete-keys, though --delete-key still works,
+ of course) to delete multiple keys in one go. This applies to
+ --delete-secret-key(s) and --delete-secret-and-public-key(s) as
+ well.
+
+2002-01-09 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_crypt_files): Now it behaves like verify_files.
+
+ * g10.c (main): We don't need to check argc for encode_crypt_files
+ any longer.
+
+2002-01-09 Timo Schulz <ts@winpt.org>
+
+ * exec.c: Include windows.h for dosish systems.
+
+2002-01-08 Timo Schulz <ts@winpt.org>
+
+ * g10.c (main): New description for --encrypt-files.
+
+2002-01-08 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Must register the secring for encryption because
+ it is needed to figure out the default recipient. Reported by
+ Roger Sondermann.
+
+2002-01-05 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (menu_adduid): Require --expert before adding a photo
+ ID to a v3 key, and before adding a second photo ID to any key.
+
+ * keyedit.c (keyedit_menu): Don't allow adding photo IDs in
+ rfc1991 or pgp2 mode.
+
+ * getkey.c (merge_selfsigs_subkey): Permit v3 subkeys. Believe it
+ or not, this is allowed by rfc 2440, and both PGP 6 and PGP 7 work
+ fine with them.
+
+ * g10.c, options.h, keyedit.c, sign.c: Move the "ask for
+ expiration" switch off of --expert, which was getting quite
+ overloaded, and onto ask-sig-expire and ask-cert-expire. Both
+ default to off.
+
+ * g10.c (main): Change the default compression algo to 1, to be
+ more OpenPGP compliant (PGP also uses this, so it'll help with
+ interoperability problems as well).
+
+ * encode.c (encode_crypt): Handle compression algo 2, since the
+ default is now 1.
+
+ * build-packet.c (build_attribute_subpkt): Fix off-by-one error.
+
+2002-01-05 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Do not register the secret keyrings for certain
+ commands.
+
+ * keydb.c (keydb_add_resource): Use access to test for keyring
+ existence. This avoids cached opened files which are bad under
+ RISC OS.
+
+2002-01-04 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (sign_file, sign_symencrypt_file): always use one-pass
+ packets unless rfc1991 is enabled. This allows a signature made
+ with a v3 key to work in PGP 6 and 7. Signatures made with v4
+ keys are unchanged.
+
+ * g10.c (main): Disallow non-detached signatures in PGP2 mode.
+ Move the "you must use files and not pipes" PGP2 warning up so all
+ the PGP2 stuff is together.
+
+ * encode.c (encode_simple): Use the actual filesize instead of
+ partial length packets in the internal literal packet from a
+ symmetric message. This breaks PGP5(?), but fixes PGP2, 6, and 7.
+ It's a decent tradeoff. Note there was only an issue with
+ old-style RFC1991 symmetric messages. 2440-style messages in 6
+ and 7 work with or without partial length packets.
+
+2002-01-03 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (main): Removed --no-default-check-level option, as it is
+ not consistent with other "default" options. Plus, it is the same
+ as saying --default-check-level 0.
+
+ * exec.c (exec_read): Disallow caching tempfile from child
+ process, as this keeps the file handle open and can cause unlink
+ problems on some platforms.
+
+ * keyserver.c (keyserver_search_prompt): Minor tweak - don't
+ bother to transform keyids into textual form if they're just going
+ to be transformed back to numbers.
+
+2002-01-03 Timo Schulz <ts@winpt.org>
+
+ * g10.c: New command --encrypt-files.
+
+ * verify.c (print_file_status): Removed the static because
+ encode_crypt_files also uses this function.
+
+ * main.h (print_files_status): New.
+ (encode_crypt_files): New.
+
+ * encode.c (encode_crypt_files): New.
+
+2002-01-02 Stefan Bellon <sbellon@sbellon.de>
+
+ * keyserver.c: Moved util.h include down in order to avoid
+ redefinition problems on RISC OS.
+
+ * keyring.c (keyring_lock): Only lock keyrings that are writable.
+
+ * keyring.c (keyring_update_keyblock): Close unused iobuf.
+
+ * hkp.c (parse_hkp_index, hkp_search) [__riscos__]: Changed
+ unsigned char* to char* because of compiler issues.
+
+ * exec.c (exec_finish) [__riscos__]: Invalidate close cache so
+ that file can be unlinked.
+
+2001-12-28 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (main): Use a different strlist to check extensions since
+ they need to be handled seperately now.
+
+ * misc.c,main.h (check_permissions): Properly handle permission
+ and ownership checks on files in the lib directory
+ (e.g. /usr/local/lib/gnupg), which are owned by root and are
+ world-readable, and change all callers to specify extension or
+ per-user file.
+
+ * photoid.c (show_photo), keyserver.c (keyserver_spawn): Bug fix -
+ don't call exec_finish if exec_write fails.
+
+ * keyserver.c (keyserver_spawn): Look for OPTIONS from the
+ keyserver helper - specifically, a "OUTOFBAND" option for the
+ email keyserver.
+
+ * mainproc.c (list_node), keylist.c (list_keyblock_colon),
+ import.c (delete_inv_parts), export.c (do_export_stream): Use
+ signature flags for exportability check rather than re-parsing the
+ subpacket.
+
+ * keyid.c, keydb.h (get_lsign_letter): No longer needed.
+
+2001-12-27 David Shaw <dshaw@jabberwocky.com>
+
+ * exec.c (exec_finish): Show errors when temp files cannot be
+ deleted for whatever reason.
+
+ * exec.c (exec_read): Don't rely on WEXITSTATUS being present.
+
+ * exec.c (make_tempdir): Add temp file creator for win32. Don't
+ create an incoming temp file if the exec is write-only.
+
+ * keyserver.c (keyserver_spawn): Clean up error handling, for when
+ the spawn fails.
+
+ * photoid.c (show_photo): Clean up error handling.
+
+ * misc.c (check_permissions): Neaten.
+
+2001-12-25 David Shaw <dshaw@jabberwocky.com>
+
+ * mkdtemp.c (mkdtemp): Add copyleft info and tweak the 'X' counter
+ to be a bit simpler.
+
+ * keyserver.c, photoid.c: Remove unused headers left over from
+ when the exec functions lived there.
+
+2001-12-23 Timo Schulz <ts@winpt.org>
+
+ * misc.c (check_permissions): Do not use it for W32 systems.
+
+ * tdbio.c (migrate_from_v2): Define ftruncate as chsize() for W32.
+
+ * mkdtemp.c: W32 support.
+
+ * photoid.c: Ditto.
+
+ * exec.c: Ditto.
+
+2001-12-22 David Shaw <dshaw@jabberwocky.com>
+
+ * exec.c (make_tempdir): avoid compiler warning with const
+
+ * mkdtemp.c (mkdtemp): catch the empty ("") string case in case
+ someone repurposes mkdtemp at some point.
+
+ * photoid.c (generate_photo_id, show_photo): some type changes
+ from Stefan Bellon.
+
+ * exec.c (make_tempdir): handle Win32 systems, suggested by Timo
+ Schulz.
+
+2001-12-22 Werner Koch <wk@gnupg.org>
+
+ * encode.c (encode_simple, encode_crypt): i18n 2 strings.
+
+2001-12-22 Timo Schulz <ts@winpt.org>
+
+ * encode.c (encode_simple, encode_crypt): Use is_file_compressed
+ to avoid to compress compressed files.
+
+2001-12-22 Werner Koch <wk@gnupg.org>
+
+ * keyserver.c (keyserver_spawn): Removed some variables
+ declaration due to shadowing warnings.
+
+ * build-packet.c (build_attribute_subpkt): s/index/idx/ to avoid
+ compiler warnig due to index(3).
+
+ * getkey.c (get_ctx_handle): Use KEYDB_HANDLE as return value.
+ * keylist.c (list_one): Made resname const.
+
+ * keyedit.c (keyedit_menu): Allow "addphoto" only when --openpgp is
+ not used.
+
+ * options.skel: Changed one example photo viewer to qiv.
+
+2001-12-21 David Shaw <dshaw@jabberwocky.com>
+
+ * Makefile.am: add exec.c, exec.h, photoid.c, and photoid.h
+
+ * build-packet.c (build_attribute_subpkt): new function to build
+ the raw attribute subpacket. Note that attribute subpackets have
+ the same format as signature subpackets.
+
+ * exec.c: new file with generic exec-a-program functionality.
+ Used by both photo IDs and keyserver helpers. This is pretty much
+ the same code that used to be keyserver specific, with some
+ changes to be usable generically.
+
+ * free-packet.c (free_attributes (new)): function to free an
+ attribute packet.
+
+ * gpgv.c: added stub show_photo
+
+ * keyedit.c (keyedit_menu, menu_adduid, menu_showphoto): can add a
+ photo (calls generate_photo_id), or display a photo (calls
+ show_photo) from the --edit menu. New commands are "addphoto",
+ and "delphoto" (same as "deluid").
+
+ * keylist.c (list_keyblock_print): show photos during key list if
+ --show-photos enabled.
+
+ * keyserver.c (keyserver_spawn): use the generic exec_xxx
+ functions to call keyserver helper.
+
+ * g10.c, options.h: three new options - --{no-}show-photos, and
+ --photo-viewer to give the command line to display a picture.
+
+ * options.skel: instructions for the photo viewer
+
+ * parse-packet.c (parse_user_id, setup_user_id (new)): common code
+ for both user IDs and attribute IDs moved to setup_user_id.
+
+ * parse-packet.c (make_attribute_uidname (new)): constructs a fake
+ "name" for attribute packets (e.g. "[image of size ...]")
+
+ * parse-packet.c (parse_attribute (replaces parse_photo_id),
+ parse_attribute_subpkts): Builds an array of individual
+ attributes. Currently only handles attribute image / type jpeg
+ subpackets.
+
+ * sign.c (hash_uid): Fix bug in signing attribute (formerly
+ photo_id) packets.
+
+ * packet.h, and callers: globally change "photo_id" to "attribute"
+ and add structures for attributes. The packet format is generic
+ attributes, even though the only attribute type thus far defined
+ is jpeg.
+
+2001-12-21 David Shaw <dshaw@jabberwocky.com>
+
+ * parse-packet.c (can_handle_critical): Can handle critical
+ revocation subpackets now.
+
+ * trustdb.c (mark_usable_uid_certs): Disregard revocations for
+ nonrevocable sigs. Note that this allows a newer revocable
+ signature to override an older nonrevocable signature.
+
+ * sign.c (make_keysig_packet): add a duration field and change all
+ callers. This makes make_keysig_packet closer to
+ write_signature_packets and removes some duplicated expiration
+ code.
+
+ * keyedit.c (keyedit_menu, menu_revsig, sign_uids,
+ sign_mk_attrib): Add nrsign command, don't allow revoking a
+ nonrevocable signature,
+
+ * g10.c (main): Add --nrsign option to nonrevocably sign a key
+ from the command line.
+
+ * build-packet.c (build_sig_subpkt_from_sig): Comment to explain
+ the use of CRITICAL.
+
+2001-12-21 Werner Koch <wk@gnupg.org>
+
+ * g10.c. options.h : New option --show-keyring
+ * getkey.c (get_ctx_handle): New.
+ * keylist.c (list_one): Implement option here. By David Champion.
+
+2001-12-20 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (keyserver_spawn): Use mkdtemp() to make temp
+ directory.
+
+ * mkdtemp.c: replacement function for those platforms that don't
+ have mkdtemp (make a temp directory securely).
+
+2001-12-19 David Shaw <dshaw@jabberwocky.com>
+
+ * misc.c (check_permissions): New function to stat() and ensure
+ the permissions of GNUPGHOME and the files have safe permissions.
+
+ * keydb.c (keydb_add_resource): Check keyring permissions.
+
+ * tdbio.c (tdbio_set_dbname): Check permissions of trustdb.gpg
+
+ * keyserver.c (keyserver_spawn): Disable keyserver schemes that
+ involve running external programs if the options file has unsafe
+ permissions or ownership.
+
+ * g10.c, options.h: New option --no-permission-warning to disable
+ the permission warning message(s). This also permits use of the
+ keyserver if it had been disabled (see above). Also check the
+ permissions/ownership of random_seed.
+
+ * keyserver.c (keyserver_spawn): The new glibc prints a warning
+ when using mktemp() (the code was already secure, but the warning
+ was bound to cause confusion). Use a different implementation
+ based on get_random_bits() instead. Also try a few times to get
+ the temp dir before giving up.
+
+2001-12-19 Werner Koch <wk@gnupg.org>
+
+ * g10.c, passphrase.c [CYGWIN32]: Allow this as an alias for MINGW32.
+
+2001-12-18 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c (idea_cipher_warn): Add a flag to show the warning always
+ or once per session and change all callers (show always except for
+ the secret key protection and unknown cipher from an encrypted
+ message errors). Also make the strings translatable.
+
+ * pubkey-enc.c (get_it): Add the IDEA cipher warning if the user
+ tries to decrypt an IDEA encrypted message without the IDEA
+ plugin.
+
+ * keyserver.c (parse_keyserver_uri): More strict checking of the
+ keyserver URI. Specifically, fail if the ":port" section is
+ anything except a number between 1 and 65535.
+
+2001-12-17 David Shaw <dshaw@jabberwocky.com>
+
+ * keyserver.c (print_keyinfo): No need to check for
+ control/illegal characters, as utf8_to_native does this for us.
+
+ * mainproc.c (proc_encrypted): Use generic IDEA warning.
+
+ * gpgv.c: add stub for idea_cipher_warn
+
+ * g10.c, hkp.c, keyserver.c: Fix capitalization and plural issues.
+
+ * encode.c (encode_crypt), sign.c (sign_file, clearsign_file):
+ disable pgp2 mode after the message is no longer pgp2 compatible.
+
+ * g10.c (main): Tweak the PGP2.x IDEA warning to use the generic
+ warning, and not merely fail if the IDEA plugin isn't there.
+
+ * g10.c (main, idea_cipher_warn), keygen.c (set_one_pref),
+ seckey-cert.c (do_check): Add a generic IDEA warning for when the
+ IDEA plugin is not present. This pops up when the user uses
+ "--cipher-algo idea", when setpref is used to set a "S1"
+ preference, and when a secret key protected with IDEA is used.
+
+2001-12-15 Werner Koch <wk@gnupg.org>
+
+ * keyserver.c (keyserver_spawn): Assert that we have dropped privs.
+
+2001-12-13 Werner Koch <wk@gnupg.org>
+
+ * pubkey-enc.c (get_session_key): Check that the public key
+ algorithm is indeed usable for en/decryption. This avoid a
+ strange error message from pubkey_decrypt if for some reasons a
+ bad algorithm indentifier is passed.
+
+2001-12-12 David Shaw <dshaw@jabberwocky.com>
+
+ * Fixed some types for portability. Noted by Stefan Bellon.
+
+2001-12-11 Werner Koch <wk@gnupg.org>
+
+ * hkp.c (hkp_export): Do not print possible control characters
+ from a keyserver response.
+ (parse_hkp_index): Made uid an unsigned char* because it is passed to
+ isspace().
+ (hkp_search): Ditto for the char* vars.
+
+ * g10.c (main): Print the IDEA warning also for -c and -se.
+
+ * g10.c (get_temp_dir): Assert that we have dropped privs
+
+ * encode.c (encode_crypt): Include the first key into the --pgp2
+ check.
+
+2001-12-07 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c, options.h: New option --pgp2. This is identical to
+ "--rfc1991 --cipher-algo idea --compress-algo 1 --digest-algo md5
+ --force_v3_sigs" with the addition of an warning to advise the
+ user not to use a pipe (which would break pgp2 compatibility).
+
+ * encode.c (encode_crypt): warn if the user tries to encrypt to
+ any key that is not RSA and <= 2048 bits when the --pgp2 option is
+ used.
+
+ * sign.c (sign_file, clearsign_file): When using --pgp2, make a v3
+ sig, and warn if the signature is made with a non-v3 key.
+
+2001-12-05 David Shaw <dshaw@jabberwocky.com>
+
+ * sign.c (sign_file, clearsign_file, sign_symencrypt_file): Prompt
+ for sig expiration if --expert is set and --force-v3-sigs is not
+ set (v3 sigs cannot expire).
+
+ * mainproc.c (check_sig_and_print): After checking a sig, print
+ expiration status. This causes a error return if the sig is
+ expired.
+
+ * build-packet.c (build_sig_subpkt_from_sig): Include a critical
+ sig expiration subpacket if the sig is to expire.
+
+ * keyedit.c (sign_uids): Do not sign an expired key unless
+ --expert is set, in which case prompt. Also, offer to expire a
+ signature when the key the user is signing expires.
+
+ * keygen.c (ask_expire_interval): Add a value to determine whether
+ to prompt for a key or sig expiration and change all callers.
+
+ * keyid.c: New functions: expirestr_from_sig and
+ colon_expirestr_from_sig.
+
+ * keylist.c (list_keyblock_colon): Show sig expiration date in the
+ --with-colons listing.
+
+ * sign.c (make_keysig_packet, write_signature_packets): Pass in an
+ optional timestamp for the signature packet, and change all
+ callers.
+
+ * keyedit.c (sign_mk_attrib): Include a critical expiration
+ subpacket in the signature if an expiration date is given.
+
+2001-12-04 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (sign_uids): If the user tries to sign a
+ locally-signed key, allow the cert to be promoted to a full
+ exportable signature. This essentially deletes the old
+ non-exportable sig, and replaces it with a new exportable one.
+
+2001-12-04 David Shaw <dshaw@jabberwocky.com>
+
+ * keyedit.c (keyedit_menu): Do not allow signing a revoked key
+ unless --expert is set, and ask even then.
+
+ * keyedit.c (sign_uids): Do not allow signing a revoked UID unless
+ --expert is set, and ask even then.
+
+ * g10.c, options.h : New option --expert
+
+2001-11-16 David Shaw <dshaw@jabberwocky.com>
+
+ * Allow the user to select no compression via "--compress-algo 0"
+ on the command line.
+
+ * keyedit.c (show_prefs): Show compression preferences in the
+ long-form "showpref" style.
+
+ * keygen.c (set_one_pref): Permit setting a no-compression ("Z0")
+ preference.
+
+ * getkey.c (fixup_uidnode): Fix compression preference corruption
+ bug.
+
+2001-12-02 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c: Add advisory --for-your-eyes-only option as per section
+ 5.9 of 2440.
+
+2001-12-05 David Shaw <dshaw@jabberwocky.com>
+
+ * Force a V4 sig if the user has a notation or policy URL set.
+
+2001-12-04 David Shaw <dshaw@jabberwocky.com>
+
+ * g10.c: Add options --keyserver-options, --temp-directory, and
+ auto-key-retrieve (the opposite of no-auto-key-retrieve).
+
+ * hkp.c (hkp_search): New function to handle searching a HKP
+ keyserver for a key
+
+ * hkp.c (hkp_ask_import, hkp_export): Pretty large changes to make
+ them communicate via the generic functions in keyserver.c
+
+ * keyserver.c: new file with generic keyserver routines for
+ getting keys from a keyserver, sending keys to a keyserver, and
+ searching for keys on a keyserver. Calls the internal HKP stuff
+ in hkp.c for HKP keyserver functions. Other calls are handled by
+ an external program which is spawned and written to and read from
+ via pipes. Platforms that don't have pipes use temp files.
+
+2001-11-20 David Shaw <dshaw@jabberwocky.com>
+
+ * options.h, g10.c: New options show-notation, no-show-notation,
+ default-check-level, no-default-check-level, show-policy-url,
+ no-show-policy-url.
+
+ * packet.h, sign.c (make_keysig_packet), parse-packet.c
+ (parse_signature), free-packet.c (free_seckey_enc): Fill in
+ structures for notation, policy, sig class, exportability, etc.
+
+ * keyedit.c, keylist.c (print_and_check_one_sig,
+ list_keyblock_print): Show flags in signature display for cert
+ details (class, local, notation, policy, revocable). If selected,
+ show the notation and policy url.
+
+ * keyedit.c (sign_uids): Prompt for and use different key sig
+ classes.
+
+ * helptext.c (helptexts): Add help text to explain different
+ key signature classes
+
+2001-11-26 David Shaw <dshaw@jabberwocky.com>
+
+ * trustdb.c (mark_usable_uid_certs): Fix segfault from bad
+ initialization and fix reversed key signature expiration check.
+
+2001-11-09 Werner Koch <wk@gnupg.org>
+
+ * export.c (do_export_stream): Put all given names into a search
+ description and change the loop so that all matching names are
+ returned.
+
+2001-11-08 Werner Koch <wk@gnupg.org>
+
+ * pubkey-enc.c (get_it): To reduce the number of questions on the
+ MLs print the the name of cipher algorithm 1 with the error message.
+
+ * mainproc.c: Changed the way old rfc1991 encryption cipher is
+ selected. Based on a patch by W Lewis.
+
+ * pkclist.c (do_edit_ownertrust): Allow to skip over keys, the non
+ working "show info" is now assigned to "i"
+ * trustdb.c (ask_ownertrust, validate_keys): Implement a real quit
+ here. Both are by David Shaw.
+
+ * trustdb.c (validate_keys): Make sure next_exipire is initialized.
+
+ * sign.c (make_keysig_packet): Use SHA-1 with v4 RSA keys.
+
+ * g10.c, options.h : New option --[no-]froce-v4-certs.
+ * sign.c (make_keysig_packet): Create v4 sigs on v4 keys even with
+ a v3 key. Use that new option. By David Shaw
+
+ * revoke.c (ask_revocation_reason): Allow to select "no reason".
+ By David Shaw.
+
+ * keyid.c (fingerprint_from_sk): Calculation of an v3 fpr was
+ plain wrong - nearly the same code in fingerprint_from_pk is correct.
+
+ * build-packet.c (do_secret_key): Added a few comments to the code.
+
+2001-11-07 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Print a warning when -r is used w/o encryption.
+ Suggested by Pascal Scheffers.
+
+2001-10-23 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (keyedit_menu): Changed helptext for showpref
+ command. Suggested by Reinhard Wobst.
+
+ * keyring.c (keyring_search): When marking the offtbl ready, take
+ into account that we may have more than one keyring.
+
+2001-10-22 Werner Koch <wk@gnupg.org>
+
+ * Makefile.am: Do not use OMIT_DEPENDENCIES
+
+ * build-packet.c (build_sig_subpkt): Default is now to put all
+ types of subpackets into the hashed area and only list those which
+ should go into the unhashed area.
+
+2001-10-18 Werner Koch <wk@gnupg.org>
+
+ * keydb.c (keydb_add_resource): Rearranged the way we keep track
+ of the resource. There will now be an entry for each keyring here
+ and not in keyring.c itself. Store a token to allow creation of a
+ keyring handle. Changed all functions to utilize this new design.
+ (keydb_locate_writable): Make a real implementation.
+ * keyring.c (next_kr): Removed and changed all callers to set the
+ resource directly from the one given with the handle.
+ (keyring_is_writable): New.
+ (keyring_rebuild_cache): Add an arg to pass the token from keydb.
+
+2001-10-17 Werner Koch <wk@gnupg.org>
+
+ * keyring.c (keyring_search): Enabled word search mode but print a
+ warning that it is buggy.
+
+2001-10-11 Werner Koch <wk@gnupg.org>
+
+ * hkp.c (hkp_ask_import): No more need to set the port number for
+ the x-hkp scheme.
+ (hkp_export): Ditto.
+
+2001-10-06 Stefan Bellon <sbellon@sbellon.de>
+
+ * passphrase.c [__riscos__]: Disabled agent specific stuff.
+ * g10.c: New option --no-force-v3-sigs.
+
+2001-10-04 Werner Koch <wk@gnupg.org>
+
+ * export.c (do_export_stream): Do not push the compress filter
+ here because the context would run out of scope due to the
+ iobuf_close done by the caller.
+ (do_export): Do it here instead.
+
+2001-09-28 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (sign_uids): Always use the primary key to sign keys.
+ * getkey.c (finish_lookup): Hack to return only the primary key if
+ a certification key has been requested.
+
+ * trustdb.c (cmp_kid_for_make_key_array): Renamed to
+ (validate_one_keyblock): this and changed arg for direct calling.
+ (make_key_array): Renamed to
+ (validate_one_keyblock): this and changed args for direct calling.
+ (mark_usable_uid_certs, validate_one_keyblock)
+ (validate_key_list): Add next_expire arg to keep track of
+ expiration times.
+ (validate_keys): Ditto for UTKs and write the stamp.
+
+ * tdbio.c (migrate_from_v2): Check return code of tbdio_sync.
+
+ * tdbdump.c (import_ownertrust): Do a tdbio_sync().
+
+ * keyring.c: Made the offtbl an global object.
+
+2001-09-27 Werner Koch <wk@gnupg.org>
+
+ * pkclist.c (do_edit_ownertrust): Allow settin of ultimate trust.
+
+ * trustdb.c (mark_keyblock_seen): New.
+ (make_key_array): Use it to mark the subkeys too.
+ (validate_keys): Store validity for ultimatly trusted keys.
+
+2001-09-26 Werner Koch <wk@gnupg.org>
+
+ * pkclist.c (check_signatures_trust, do_we_trust): Removed the
+ invocation of add_ownertrust. Minor changes to the wording.
+ (add_ownertrust, add_ownertrust_cb): Removed.
+
+ * trustdb.c (get_validity): Allow to lookup the validity using a
+ subkey.
+
+ * trustdb.c (new_key_hash_table): Increased the table size to 1024
+ and changed the masks accordingly.
+ (validate): Changed stats printing.
+ (mark_usable_uid_certs): New.
+ (cmp_kid_for_make_key_array): Does now check the signatures and
+ figures out a usable one.
+
+2001-09-25 Werner Koch <wk@gnupg.org>
+
+ * keyring.c (new_offset_item,release_offset_items)
+ (new_offset_hash_table, lookup_offset_hash_table)
+ (update_offset_hash_table, update_offset_hash_table_from_kb): New.
+ (keyring_search): Use a offset table to optimize search for
+ unknown keys.
+ (keyring_update_keyblock, keyring_insert_keyblock): Insert new
+ offsets.
+ * getkey.c (MAX_UNK_CACHE_ENTRIES): Removed the unknown keys
+ caching code.
+
+ * g10.c, options.h, import.c: Removed the entire
+ allow-secret-key-import stuff because the validity is now
+ controlled by other means.
+
+ * g10.c: New command --rebuild-keydb-caches.
+ * keydb.c (keydb_rebuild_caches): New.
+ * keyring.c (do_copy): Moved some code to
+ (create_tmp_file, rename_tmp_file, write_keyblock): new functions.
+ (keyring_rebuild_cache): New.
+
+ * packet.h (PKT_ring_trust): Add sigcache field.
+ * parse-packet.c (parse_trust): Parse sigcache.
+ * keyring.c (do_copy): Always insert a sigcache packet.
+ (keyring_get_keyblock): Copy the sigcache packet to the signature.
+ * sig-check.c (cache_sig_result): Renamed from
+ cache_selfsig_result. Changed implementation to use the flag bits
+ and changed all callers.
+ (mdc_kludge_check): Removed this unused code.
+ (do_check): Do not set the sig flags here.
+
+ * import.c (read_block): Make sure that ring_trust packets are
+ never imported.
+ * export.c (do_export_stream): and never export them.
+
+ * trustdb.c (make_key_array): Skip revoked and expired keys.
+
+2001-09-24 Werner Koch <wk@gnupg.org>
+
+ * g10.c, options.h: New option --no-auto-check-trustdb.
+
+ * keygen.c (do_generate_keypair): Set newly created keys to
+ ultimately trusted.
+
+ * tdbio.h, tdbio.c: Removed all support for records DIR, KEY, UID,
+ PREF, SIG, SDIR and CACH. Changed migration function to work
+ direct on the file.
+ (tdbio_read_nextcheck): New.
+ (tdbio_write_nextcheck): New.
+
+2001-09-21 Werner Koch <wk@gnupg.org>
+
+ Revamped the entire key validation system.
+ * trustdb.c: Complete rewrite. No more validation on demand,
+ removed some functions, adjusted to all callers to use the new
+ and much simpler interface. Does not use the LID anymore.
+ * tdbio.c, tdbio.h: Add new record types trust and valid. Wrote a
+ migration function to convert to the new trustdb layout.
+ * getkey.c (classify_user_id2): Do not allow the use of the "#"
+ prefix.
+ * keydb.h: Removed the TDBIDX mode add a skipfnc to the
+ descriptor.
+ * keyring.c (keyring_search): Implemented skipfnc.
+
+ * passphrase.c (agent_open): Add missing bracket. Include windows.h.
+
+2001-09-19 Werner Koch <wk@gnupg.org>
+
+ * keylist.c (print_fingerprint): Renamed from fingerprint, made
+ global available. Added new arg to control the print style.
+ * mainproc.c (print_fingerprint): Removed.
+ * pkclist.c (print_fpr, fpr_info): Removed and changed callers to
+ use print_fingerprint.
+ * keyedit.c (show_fingerprint): Ditto.
+
+ * passphrase.c (writen, readn)
+ (agent_open, agent_close)
+ (agent_get_passphrase)
+ (passphrase_clear_cache): Support for W32. Contributed by Timo.
+
+ * import.c (import_one): Release keydb handles at 2 more places.
+
+ * keyring.c (keyring_release): Close the iobuf.
+ (keyring_get_keyblock): Init ret_kb to NULL and store error contidion.
+
+ * import.c (import_new_stats_handle): New.
+ (import_release_stats_handle): New.
+ (import_print_stats): Renamed from static fnc print_stats.
+ (import_keys, import_keys_stream): Add an optional status handle
+ arg and changed all callers.
+ * hkp.c (hkp_ask_import): Add an stats_handle arg and changed all
+ callers.
+
+ * mainproc.c (print_pkenc_list): Use print_utf8_string2().
+
+2001-09-18 Werner Koch <wk@gnupg.org>
+
+ * g10.c: New command --refresh-keys.
+ * hkp.c (hkp_refresh_keys): New. Contributed by Timo Schulz.
+
+ * parse-packet.c (parse): Stop on impossible packet lengths.
+
+2001-09-17 Werner Koch <wk@gnupg.org>
+
+ * mainproc.c (print_notation_data): Wrap notation data status lines
+ after 50 chars.
+
+ * mainproc.c (proc_pubkey_enc): Make option try-all-secrets work.
+ By disastry@saiknes.lv.
+
+2001-09-14 Werner Koch <wk@gnupg.org>
+
+ * parse-packet.c (dump_sig_subpkt): List key server preferences
+ and show the revocable flag correctly. Contributed by David Shaw.
+
+2001-09-09 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (keyedit_menu): No need to define another p.
+
+ * keylist.c (print_capabilities): s/used/use/ so that it
+ does not shadow a global.
+ * sign.c (sign_file): Renamed arg encrypt to encryptflag
+ * keygen.c: Replaced all "usage" by "use".
+ * misc.c (openpgp_pk_algo_usage): Ditto.
+
+ * pubkey-enc.c (get_it): Renamed arg k to enc so that the later
+ defined k does not shadow it.
+
+ * parse-packet.c (parse_gpg_control): No need to define another i.
+
+ * getkey.c (get_pubkey_byfprint): Must use the enum values and not
+ the fprint_len.
+ * keyring.c (keyring_search): Removed a non-sense break. Both
+ bugs pointed out by Stefan.
+
+2001-09-07 Werner Koch <wk@gnupg.org>
+
+ * status.c, status.h: Added NO_RECP and ALREADY_SIGNED.
+ * pkclist.c (build_pk_list): Issue NO_RECP.
+ * keyedit.c (sign_uids): Added experimental ALREADY_SIGNED
+
+ * hkp.c (hkp_import): Use log_error. Bug reported by Neal H
+ Walfield.
+
+ * getkey.c (classify_user_id2): Change args to take the desc union
+ direct. It was a stupid idea to pass the individual fields of an
+ union to this function. Changed all callers.
+ (classify_user_id): Ditto and allow to pass NULL as the description.
+
+2001-09-06 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (fixup_uidnode): Features flag is now a bit vector.
+ * keygen.c (add_feature_mdc): Ditto.
+
+ Revamped the entire key I/O code to be prepared for other ways of
+ key storages and to get rid of the existing shit. GDBM support has
+ gone.
+ * keydb.c: New
+ * keyring.c, keyring.h: New.
+ * ringedit.c: Removed. Moved some stuff to keyring.c
+ * getkey.c: Changed everything related to the key retrieving
+ functions which are now using the keydb_ functions.
+ (prepare_search, word_match_chars, word_match)
+ (prepare_word_match, compare_name): Moved to keyring.c
+ (get_pubkey_byname): Removed ctx arg and add ret_kdbhd
+ arg. Changed all callers.
+ (key_byname): Use get_pubkey_end to release the context and take
+ new ret_kbdhd arg. Changed all callers.
+ (classify_user_id2): Fill the 16 byte fingerprint up with 4 null
+ bytes not with zero bytes of value 4, tsss.
+ * import.c (import_one): Updated to use the new keydb interface.
(import_secret_one): Ditto.
(import_revoke_cert): Ditto.
- (import_one): Ditto.
-
-Fri Oct 6 14:29:16 CEST 2000 Werner Koch <wk@openit.de>
-
- Started to rework the whole getkey/ringedit stuff to make
- it simpler, correcter and faster.
-
- * parse-packet.c (parse_packet): Add a 3rd arg to return the filepos.
- Changed all callers.
- * getkey.c (classify_user_id): Add new mode 21.
- (find_by_fpr): Find using this new mode.
- (get_seckey_byname): New arg to return the context. Changed all
- callers.
- * keyid.c (unified_fingerprint_from_pk): New.
- (unified_fingerprint_from_sk): New.
- * ringedit.c (find_keyblock_bypk): Changed to use the unified
- fingerprint for lookup. I can't see a reason why we did compare
- the entire public key.
- (find_keyblock_bysk): Ditto.
- (search,cmp_pubkey,cmp_seckey): Removed.
- (keyring_search, do_kbxf_search): Removed.
- (locate_keyblock_by_fpr,locate_keyblock_by_keyid): Removed.
- (find_keyblock_byname): Removed use o search function.
- (find_secret_keyblock_byname): Ditto.
- (merge_public_with_secret): Fixed removing subkeys.
- (premerge_public_with_secret): New.
-
- * ringedit.c: Removed all GDBM support
-
- * ringedit.c (read_keyblock): Removed.
- * ringedit.c (find_keyblock_byname,find_secret_keyblock_byname,
- find_keyblock_bypk,find_keyblock_bysk): Moved from here to ....
- * getkey.c: ... here. Changed first arg to return a keyblock and
- changed all callers to merge the old read_keyblock() with these
- functions.
-
-Wed Oct 4 13:16:18 CEST 2000 Werner Koch <wk@openit.de>
-
- * getkey.c (merge_selfsigs_main): Fixed for v3 keys.
-
- * sign.c (hash_for): New arg to take packet version in account. Changed
- all callers.
- (write_one_sig): New. Moved the shared code from sign_file and
- clearsign_file to here.
- * skclist.c (build_sk_list): Fixed usage check.
- * pkclist.c (build_pk_list): Ditto.
-
- * encode.c (encode_crypt): Removed duplicated stuff by using
- encrypt_filter as sign.c already did. Removed already disabled
- comment-packet code.
-
-Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
-
- * parse-packet.c (dump_sig_subpkt): Dump key flags.
- (parse_one_sig_subpkt,can_handle_critical): Add KeyFlags support.
- * build-packet.c (build_sig_subpkt): Ditto.
+ * delkey.c (do_delete_key): Ditto.
+ * keyedit.c (keyedit_menu): Ditto.
+ (get_keyblock_byname): Removed.
+ * revoke.c (gen_revoke): Ditto.
+ * export.c (do_export_stream): Ditto.
+ * trustdb.c (update_trustdb): Ditto.
+ * g10.c, gpgv.c (main): Renamed add_keyblock_resource to
+ keydb_add_resource.
+ * Makefile.am: Added and removed files.
- * g10.c: New option --allow-freeform-uid. By Jeroen C. van Gelderen.
- * keygen.c (ask_user_id): Implemented here.
+ * keydb.h: Moved KBNODE typedef and MAX_FINGERPRINT_LEN to
+ * global.h: this new header.
+
+2001-09-03 Werner Koch <wk@gnupg.org>
- * parse-packet.c (dump_sig_subpkt): Print info about the ARR.
+ * passphrase.c (agent_get_passphrase): Changed nread to size_t.
+ (passphrase_clear_cache): Ditto.
- * openfile.c (overwrite_filep): Always return okay if the file is
- called /dev/null.
- (make_outfile_name): Add ".sign" to the list of know extensions.
- (open_sigfile): Ditto.
+ * keyid.c (mk_datestr): Avoid trigraphs.
+ (fingerprint_from_pk): Cache the keyid in the pk.
- * getkey.c: Large parts rewritten to have a better sub key selection
- and handle some meta information from signatures more correctly.
- (get_primary_seckey): Removed.
- * seckey_cert.c (do_check): Set main keyid from the data in the sk.
- * free-packet.c (copy_public_parts_to_secret_key): New.
- * sig-check.c (check_key_signature2): Enabled shortcut for already
- checked signatures.
- * keydb.h: New macros IS_xxx_SIG, IS_xxx_REV.
- * misc.c (openpgp_pk_algo_usage): New.
- * packet.h: New field req_uage and do not use pubkey_usage anymore
- to request a specific usage. Changed at all places.
- * keyid.c (keyid_from_sk): Cache the keyid in the sk
+ * options.h: Add opt.with_fingerprint so that we know whether the
+ corresponding options was used.
+ * g10.c (main): Set it here.
+ * pkclist.c (check_signatures_trust): Always print fingerprint
+ when this option is used. Mixed a minor memory leak.
- * passphrase.c (hash_passphrase): Removed funny assert. Reported by
- David Mathog.
+ * status.c, status.h: New status INV_RECP.
+ * pkclist.c (build_pk_list): Issue this status.
- * keyedit.c (keyedit_menu): Allow "debug" on secret keys.
+2001-08-31 Werner Koch <wk@gnupg.org>
- * keygen.c (keygen_add_std_prefs): Changed order of preferences to
- twofish, cast5, blowfish.
+ * parse-packet.c (parse_key,parse_pubkeyenc)
+ (parse_signature): Return error on reading bad MPIs.
+
+ * mainproc.c (check_sig_and_print): Always print the user ID even
+ if it is not bound by a signature. Use the primary UID in the
+ status messages and encode them in UTF-8
+ * status.c (write_status_text_and_buffer): New.
+
+2001-08-30 Werner Koch <wk@gnupg.org>
+
+ * packet.h (sigsubpkttype_t): Add SIGSUBPKT_FEATURES.
+ (PKT_public_key, PKT_user_id): Add a flag for it.
+ * parse-packet.c, build-packet.c: Add support for them.
+ * getkey.c (fixup_uidnode, merge_selfsigs): Set the MDC flags.
+ * keygen.c (add_feature_mdc): New.
+ (keygen_upd_std_prefs): Always set the MDC feature.
+ * keyedit.c (show_prefs): List the MDC flag
+ * pkclist.c (select_mdc_from_pklist): New.
+ * encode.c (encode_crypt, encrypt_filter): Test whether MDC
+ should be used.
+ * cipher.c (write_header): Set MDC use depending on the above test.
+ Print more status info.
+
+ * delkey.c (do_delete_key): Kludge to delete a secret key with no
+ public key available.
+
+ * ringedit.c (find_secret_keyblock_direct): New.
+ * getkey.c (seckey_available): Simplified.
+
+ * ringedit.c (cmp_seckey): Now compares the secret key against the
+ public key while ignoring all secret parts.
+ (keyring_search): Use a public key packet as arg. Allow to search
+ for subnkeys
+ (search): Likewise. Changed all callers.
+ (find_secret_keyblock_bypk): New.
+ (find_secret_keyblock_byname): First locate the pubkey and then
+ find the correponding secret key.
+ * parse-packet.c (parse): Renamed pkttype arg to onlykeypkts and
+ changed code accordingly. Changed all callers.
+ (search_packet): Removed pkttype arg.
+ * keyedit.c (keyedit_menu): First locate the public key and then
+ try to locate a secret key.
+
+ * ringedit.c (locate_keyblock_by_fpr): Removed.
+ (locate_keyblock_by_keyid): Removed.
+ (find_keyblock_bysk): Removed.
+
+ * sig-check.c (check_key_signature2): Print the keyid along with
+ the wrong sig class errors.
+
+2001-08-24 Werner Koch <wk@gnupg.org>
+
+ * sign.c (sign_file): Stripped the disabled comment packet code.
+ (sign_file, sign_symencrypt_file): Moved common code to ..
+ (write_onepass_sig_packets): .. this new function.
+ (sign_file, clearsign_file, sign_symencrypt_file): Moved common
+ code to
+ (write_signature_packets): this new function.
+ (write_signature_packets, make_keysig_packet)
+ (update_keysig_packet): Moved common code to
+ (hash_uid, hash_sigclass_to_magic): these new functions
+ (sign_file, sign_symencrypt_file): Moved common code to
+ (write_plaintext_packet): this new function.
+
+2001-08-21 Stefan Bellon <sbellon@sbellon.de>
+
+ * trustdb.c (query_trust_info): Changed trustlevel to signed int.
+ * g10.c [__riscos__]: Fixed handling of --use-agent --lock-multiple.
+
+2001-08-20 Werner Koch <wk@gnupg.org>
+
+ * encr-data.c (decrypt_data): Keep track on whether we already
+ printed information about the used algorithm.
+ * mainproc.c (proc_encrypted): Removed the non-working IDEA hack
+ and print a message about the assumed algorithm.
+ * passphrase.c (passphrase_to_dek): Use the same algorithm as above.
+ (proc_symkey_enc): Print the algorithm, so that the user knows it
+ before entering the passphrase.
+ (proc_pubkey_enc, proc_pubkey_enc): Zero the DEK out.
+ * encode.c (encode_crypt, encrypt_filter): Ditto.
+
+ * g10.c: Allow for --sign --symmetric.
+ * sign.c (sign_and_symencrypt): New.
+
+ Applied patches from Stefan Bellon <sbellon@sbellon.de> to support
+ RISC OS. Nearly all of these patches are identified by the
+ __riscos__ macro.
+ * compress.c: Added a couple of casts.
+ * g10.c [__riscos__]: Some patches and new options foo-file similar
+ to all foo-fd options.
+ * gpgv.c, openfile.c, ringedit.c, tdbio.c: Minor fixes. Mainly
+ replaced hardcoded path separators with EXTSEP_S like macros.
+ * passprase.c [__riscos__]: Disabled agent stuff
+ * trustdb.c (check_trust): Changed r_trustlevel to signed int to
+ avoid mismatch problems in pkclist.c
+ * pkclist.c (add_ownertrust): Ditto.
+ * plaintext.c (handle_plaintext) [__riscos__]: Print a note when
+ file can't be created.
+ * options.h [__riscos__]: Use an extern unless included from the
+ main module.
+ * signal.c (got_fatal_signal) [__riscos__]: Close all files.
+
+2001-08-14 Werner Koch <wk@gnupg.org>
+
+ * keygen.c (ask_algo): New arg r_usage. Allow for RSA keys.
+ (gen_rsa): Enabled the code.
+ (do_create): Enabled RSA branch.
+ (parse_parameter_usage): New.
+ (proc_parameter_file): Handle usage parameter.
+ (read_parameter_file): Ditto.
+ (generate_keypair): Ditto.
+ (generate_subkeypair): Ditto.
+ (do_generate_keypair): Ditto.
+ (do_add_key_flags): New.
+ (keygen_add_std_prefs): Use the new function.
+ (keygen_add_key_flags_and_expire): New.
+ (write_selfsig, write_keybinding): Handle new usage arg.
+ * build-packet.c (build_sig_subpkt): Make sure that key flags go
+ into the hashed area.
+
+ * keygen.c (write_uid): Initialize the reference cunter.
+
+ * keyedit.c (keyedit_menu): No more need to update the trustdb for
+ preferences. Added calls to merge keblock.
+
+ * kbnode.c (dump_kbnode): Print some more flags.
+
+2001-08-10 Werner Koch <wk@gnupg.org>
+
+ Revamped the preference handling.
+
+ * packet.h (prefitem_t, preftype_t): New.
+ (PKT_public_key): Added a uid field.
+ (PKT_user_id): Added field to store preferences and a reference
+ counter.
+ * parse-packet.c (parse_user_id,parse_photo_id): Initialize them
+ * free-packet.c (free_user_id): Free them.
+ (copy_user_id): Removed.
+ (scopy_user_id): New.
+ (cmp_user_ids): Optimized for identical pointers.
+ (release_public_key_parts): Release the uid.
+ (copy_public_key_with_new_namehash): Removed.
+ (copy_prefs): New.
+ * keyedit.c (menu_adduid): Use the new shallow copy user id.
+ (show_prefs): Adjusted implementation.
+ (keyedit_menu): No more need to update the trustdb after changing
+ preferences.
+ * getkey.c (fixup_uidnode): Store preferences.
+ (find_by_name): Return a user id packet and remove namehash stuff.
+ (lookup): Removed the unused namehash stuff.
+ (finish_lookup): Added foundu arg.
+ (pk_from_block): Removed the namehash arg and changed all callers.
+ (merge_selfsigs): Copy prefs to all keys.
+ * trustdb.c (get_pref_data): Removed.
+ (is_algo_in_prefs): Removed.
+ (make_pref_record): Deleted and removed all class.
+ * pkclist.c (select_algo_from_prefs): Adjusted for the new
+ preference implementation.
+ * pubkey-enc.c (is_algo_in_prefs): New.
+ (get_it): Use that new function.
+
+2001-08-09 Werner Koch <wk@gnupg.org>
+
+ * build-packet.c (build_sig_subpkt): Fixed calculation of
+ newarea->size.
+
+ * g10.c (main): New option "--preference-list"
+ * keyedit.c (keyedit_menu): New commands "setpref" and "updpref".
+ (menu_set_preferences): New.
+ * keygen.c (keygen_set_std_prefs): New.
+ (set_one_pref): New.
+ (check_zip_algo): New.
+ (keygen_get_std_prefs): New.
+ (keygen_upd_std_prefs): New
+ (keygen_add_std_prefs): Move the pref setting code into the above fnc.
+ * build-packet.c (build_sig_subpkt): Updated the list of allowed
+ to update subpackets.
+
+2001-08-08 Werner Koch <wk@gnupg.org>
+
+ * packet.h (subpktarea_t): New.
+ (PKT_signature): Use that type for hashed_data and unhashed_data and
+ removed the _data prefix from those fields. Changed all users.
+ * parse-packet.c (parse_signature): Changed allocation for that.
+ (parse_sig_subpkt): Changed declaration
+ (enum_sig_subpkt): Ditto and changed implementation accordingly.
+ * free-packet.c (cp_subpktarea): Renamed from cp_data_block and
+ adjusted implementation. Changed caller.
+ * sig-check.c (mdc_kludge_check): Adjusted the hashing.
+ (do_check): Ditto.
+ * sign.c (sign_file, clearsign_file, make_keysig_packet,
+ update_keysig_packet): Ditto.
+ * build-packet.c (build_sig_subpkt): Partial rewrite.
+ (find_subpkt): Adjusted and made static.
+ (delete_sig_subpkt): Adjusted.
+ (do_signature): Ditto.
- * gpg.c: The --trusted-key option is back.
- * trustdb.c (verify_own_key): Handle this option.
- (add_ultimate_key): Moved stuff from verify_own_key to this new func.
- (register_trusted_key): New.
+ * keygen.c (ask_keysize): Do not print the notes about suggested
+ key sizes if just a DSA key is generated.
- * openfile.c (try_make_homedir): Changes for non-Posix systems.
- * gpg.c (main): Take the default homedir from macro.
+ * trustdb.c (add_ultimate_key): s/log_error/log_info/ for
+ duplicated inserted trusted keys.
- * encode.c (encode_simple, encode_crypt): Fix for large files.
- * sign.c (sign_file): Ditto.
+2001-08-07 Werner Koch <wk@gnupg.org>
- * gpg.c (main): Don't set --quite along with --no-tty. By Frank Tobin.
+ * sign.c (sleep): Redefine for W32.
- * misc.c (disable_core_dump): Don't display a warning here but a return
- a status value and ...
- * gpg.c (main): ...print warning here. Suggested by Sam Roberts.
+ * g10.c, options.h: Set new flag opt.no_homedir_creation when
+ --no-options is given.
+ * openfile.c (try_make_homedir): Don't create the homedir in that case.
- * misc.c (print_pubkey_algo_note): Do not print the RSA notice.
- * sig-check.c (do_signature_check): Do not emit the RSA status message.
- * pubkey-enc.c (get_session_key): Ditto.
+2001-08-03 Werner Koch <wk@gnupg.org>
- * ringedit.c (cmp_seckey): Fix for v4 RSA keys.
- * seckey-cert.c (do_check): Workaround for PGP 7 bug.
+ * armor.c (armor_filter): Removed the default comment string
+ because it could get us in trouble due to translations using non
+ ascii characters.
- * pkclist.c (algo_available): Removed hack to disable Twofish.
+2001-08-01 Werner Koch <wk@gnupg.org>
- * gpg.c (main): Default S2K algorithms are now SHA1 and CAST5 - this
- should solve a lot of compatibility problems with other OpenPGP
- apps because those algorithms are SHOULD and not optional. The old
- way to force it was by using the --openpgp option whith the drawback
- that this would disable a couple of workarounds for PGP.
+ * keylist.c (list_keyblock_print): Do not list revoked UIDs unless
+ in verbose mode and we do no signature listing.
+
+ * getkey.c (finish_lookup): Skip subkeys which are not yet valid.
+ * g10.c, options.h: New option --ignore-valid-from.
+
+ * sign.c (make_keysig_packet): Added new sigversion argument to
+ allow the caller to force generation of required signature
+ version. Changed all callers. Suggested by Thomas Roessler.
+
+ * keyedit.c (sign_uids): Force v4 signature generation for local
+ sigs. Removed the check for local signature and pre-v4 keys.
+
+2001-07-27 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (sign_uids): Check that we are not trying to to a
+ lsign with a pre-v4 key. Bug noticed by Thomas Roessler.
+
+2001-07-26 Werner Koch <wk@gnupg.org>
+
+ * parse-packet.c (parse_photo_id): Reset all variables.
+ * getkey.c (merge_selfsigs_main): Removed checks on PHOTO_ID
+ because this is handled identically to a user ID.
+
+2001-07-06 Werner Koch <wk@gnupg.org>
+
+ * cipher.c (write_header): Don't use MDC with --rfc1991. Suggested
+ by disastry@saiknes.lv.
+
+2001-07-05 Werner Koch <wk@gnupg.org>
+
+ * g10.c, options.h: New option --preserve-permissions.
+ * ringedit.c (add_keyblock_resource): Use it here
+ (keyring_copy): and here.
+
+ * trustdb.c (verify_own_keys): Be more silent on --quiet.
+ Suggested by Thomas Roessler.
+ * sig-check.c (check_key_signature2): Ditto.
+ * mainproc.c (proc_encrypted, proc_tree): Ditto
+ * getkey.c (lookup): Ditto.
+
+2001-07-04 Werner Koch <wk@gnupg.org>
+
+ * ringedit.c (add_keyblock_resource): Restore filename in case of error.
+
+2001-06-25 Werner Koch <wk@gnupg.org>
+
+ * kbnode.c (dump_kbnode): Print the signature timestamp.
+
+ * keyedit.c (keyedit_menu): New menu point "primary".
+ (change_primary_uid_cb): New.
+ (menu_set_primary_uid): New.
+ * sign.c (update_keysig_packet): New.
+ * build-packet.c (build_sig_subpkt): Put the primary UID flag into
+ the hashed area. Allow update of some more packets.
+
+2001-06-15 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (merge_selfsigs): Exit gracefully when a secret key is
+ encountered. May happen if a secret key is in public keyring.
+ Reported by Francesco Potorti.
+
+2001-06-12 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (compare_name): Use ascii_memistr(), ascii_memcasecmp()
+ * keyedit.c (keyedit_menu): Use ascii_strcasecmp().
+ * armor.c (radix64_read): Use ascii_toupper().
+ * ringedit.c (do_bm_search): Ditto.
+ * keygen.c (read_parameter_file): Ditto.
+ * openfile.c (CMP_FILENAME): Ditto.
+ * g10.c (i18n_init): We can now use just LC_ALL.
+
+2001-05-29 Werner Koch <wk@gnupg.org>
+
+ * keygen.c (generate_subkeypair): Print a warning if a subkey is
+ created on a v3 key. Suggested by Brian M. Carlson.
+
+2001-05-27 Werner Koch <wk@gnupg.org>
+
+ * keyid.c (get_lsign_letter): New.
+ * keylist.c (list_keyblock_colon): Use it here.
+ * mainproc.c (list_node): and here.
+
+ * getkey.c, packet.h, free-packet.c: Removed that useless key
+ created field; I dunno why I introducded this at all - the
+ creation time is always bound to the key packet and subject to
+ fingerprint calculation etc.
+
+ * getkey.c (fixup_uidnode): Add keycreated arg and use this
+ instead of the signature timestamp to calculate the
+ help_key_expire. Bug reported by David R. Bergstein.
+ (merge_selfsigs_main): Correct key expiration time calculation.
+ (merge_selfsigs_subkey): Ditto.
+
+2001-05-25 Werner Koch <wk@gnupg.org>
+
+ * revoke.c (gen_revoke): Add a cast to a tty_printf arg.
+ * delkey.c (do_delete_key): Ditto.
+ * keyedit.c (print_and_check_one_sig): Ditto.
+ (ask_revoke_sig): Ditto.
+ (menu_revsig): Ditto.
+ (check_all_keysigs): Removed unused arg.
+
+2001-05-23 Werner Koch <wk@gnupg.org>
+
+ * g10.c (opts): Typo fix by Robert C. Ames.
+
+2001-05-06 Werner Koch <wk@gnupg.org>
+
+ * revoke.c: Small typo fix
+
+2001-05-04 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c (passphrase_clear_cache): Shortcut if agent usage
+ is not enabled.
+
+2001-05-01 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c (writen): Replaced ssize_t by int. Thanks to
+ to Robert Joop for reporting that SunOS 4.1.4 does not have it.
+
+2001-04-28 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (merge_public_with_secret): pkttype was not set to subkey.
+
+2001-04-27 Werner Koch <wk@gnupg.org>
+
+ * skclist.c (build_sk_list): Changed one log_debug to log_info.
+
+2001-04-25 Werner Koch <wk@gnupg.org>
+
+ * keyedit.c (show_prefs): Add a verbose mode.
+ (show_key_with_all_names): Pass verbose flag for special value of
+ with_pref.
+ (keyedit_menu): New command "showpref"
+ (show_key_with_all_names): Mark revoked uids and the primary key.
+
+2001-04-24 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (get_primary_uid): Return a different string in case of
+ error and made it translatable.
+
+ * build-packet.c (do_secret_key): Ugly, we wrote a zero
+ instead of the computed ndays. Thanks to M Taylor for complaining
+ about a secret key import problem.
+
+2001-04-23 Werner Koch <wk@gnupg.org>
+
+ * hkp.c (hkp_ask_import): Allow to specify a port number for the
+ keyserver. Add a kudge to set the no_shutdown flag.
+ (hkp_export): Ditto.
+ * options.skel: Document the changes
+
+2001-04-20 Werner Koch <wk@gnupg.org>
+
+ * options.skel: Add some more comments.
+
+2001-04-19 Werner Koch <wk@gnupg.org>
+
+ * keyid.c (mk_datestr): New. Handles negative times. We must do
+ this because Windoze segvs on negative times passed to gmtime().
+ Changed all datestr_from function to use this one.
+
+ * keyid.c, keyid.h (colon_strtime): New. To implement the
+ fixed-list-mode.
+ (colon_datestr_from_pk): New.
+ (colon_datestr_from_sk): New.
+ (colon_datestr_from_sig): New.
+ * keylist.c (list_keyblock_colon): Use these functions here.
+ * mainproc.c (list_node): Ditto.
+
+2001-04-18 Werner Koch <wk@gnupg.org>
+
+ * openfile.c (open_sigfile): Fixed the handling of ".sign".
+ * mainproc.c (proc_tree): Use iobuf_get_real_fname.
+ Both are by Vincent Broman.
+
+2001-04-14 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (fixup_uidnode): Removed check for !sig which is
+ pointless here. Thanks to Jan Niehusmann.
+
+2001-04-10 Werner Koch <wk@gnupg.org>
+
+ * sig-check.c (check_key_signature2): Use log_info instead of
+ log_error so that messed up keys do not let gpg return an error.
+ Suggested by Christian Kurz.
+
+ * getkey.c (merge_selfsigs_main): Do a fixup_uidnode only if we
+ have both, uid and sig. Thanks to M Taylor.
+
+2001-04-05 Werner Koch <wk@gnupg.org>
+
+ * armor.c (unarmor_pump_new,unarmor_pump_release): New.
+ (unarmor_pump): New.
+ * pipemode.c (pipemode_filter): Use the unarmor_pump to handle
+ armored or non-armored detached signatures. We can't use the
+ regular armor_filter becuase this does only chack for armored
+ signatures the very first time. In pipemode we may have a mix of
+ armored and binary detached signatures.
+ * mainproc.c (proc_tree): Do not print the "old style" notice when
+ this is a pipemode processes detached signature.
+ (proc_plaintext): Special handling of pipemode detached sigs.
+
+ * packet.h (CTRLPKT_PLAINTEXT_MARK): New.
+ * parse-packet.c (create_gpg_control): New.
+ * kbnode.c (dump_kbnode): Support it here.
+ * mainproc.c (check_sig_and_print): Fixed the check for bad
+ sequences of multiple signatures.
+ (proc_plaintext): Add the marker packet.
+ (proc_tree): We can now check multiple detached signatures.
+
+2001-04-02 Werner Koch <wk@gnupg.org>
+
+ The length of encrypted packets for blocksizes != 8 was not
+ correct encoded. I think this is a minor problem, because we
+ usually use partial length packets. Kudos to Kahil D. Jallad for
+ pointing this out.
+ * packet.h: Add extralen to PKT_encrypted.
+ * cipher.c (write_header): Set extralen.
+ * build-packet.c (do_encrypted): Use extralen instead of const 10.
+ (do_encrypted_mdc): Ditto.
+ * parse-packet.c (parse_encrypted): Set extralen to 0 because we
+ don't know it here.
+
+2001-03-30 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (premerge_public_with_secret): Changed wording an add
+ the keyID to the info message.
+
+2001-03-29 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (premerge_public_with_secret): Use log_info instead of
+ log_error when no secret key was found for a public one.
+ Fix the usage if the secret parts of a key are not available.
+
+ * openfile.c (ask_outfile_name): Trim spaces.
+ (open_outfile): Allow to enter an alternate filename. Thanks to
+ Stefan Bellon.
+ * plaintext.c (handle_plaintext): Ditto.
+
+2001-03-28 Werner Koch <wk@gnupg.org>
+
+ * mainproc.c (do_check_sig): Allow direct key and subkey
+ revocation signature.
+ * sig-check.c (check_key_signature2): Check direct key signatures.
+ Print the signature class along with an error.
+
+2001-03-27 Werner Koch <wk@gnupg.org>
+
+ * packet.h: Add a missing typedef to an enum. Thanks to Stefan Bellon.
+
+ * g10.c: New option --no-sig-create-check.
+ * sign.c (do_sign): Implement it here.
+ * g10.c: New option --no-sig-cache.
+ * sig-check.c (check_key_signature2): Implement it here.
+ (cache_selfsig_result): and here.
+
+ * keylist.c (list_keyblock): Removed debugging stuff.
+
+ * getkey.c (cache_public_key): Made global.
+ * keygen.c (write_selfsig, write_keybinding): Cache the new key.
+
+ * getkey.c (key_byname): Add new arg secmode and changed all
+ callers to request explicitly the mode. Deriving this information
+ from the other supplied parameters does not work if neither pk nor
+ sk are supplied.
+
+2001-03-25 Werner Koch <wk@gnupg.org>
+
+ * packet.h (ctrlpkttype_t): New.
+ * mainproc.c (add_gpg_control,proc_plaintext,proc_tree): Use the
+ new enum values.
+ * pipemode.c (make_control): Ditto.
+ * armor.c (armor_filter): Ditto.
+
+2001-03-24 Werner Koch <wk@gnupg.org>
+
+ * sign.c (do_sign): Verify the signature right after creation.
+
+2001-03-23 Werner Koch <wk@gnupg.org>
+
+ * status.c, status.h (STATUS_UNEXPECTED): New.
+ * mainproc.c (do_proc_packets): And emit it here.
+
+2001-03-21 Werner Koch <wk@gnupg.org>
+
+ * status.c: Add sys/types.h so that it runs on Ultrix. Reported
+ by Georg Schwarz.x
+
+ * build-packet.c (build_sig_subpkt): Fixed generaton of packet
+ length header in case where 2 bytes headers are needed. Thanks to
+ Piotr Krukowiecki.
+
+2001-03-19 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): the default keyring is no always used unless
+ --no-default-keyring is given.
+
+ * ringedit.c (add_keyblock_resource): invalidate cache after file
+ creation.
+
+2001-03-15 Werner Koch <wk@gnupg.org>
+
+ * keygen.c (ask_algo): Changed the warning of the ElGamal S+E Algo.
+
+ * keylist.c (print_capabilities): New.
+ (list_keyblock_colon): and use it here.
+
+2001-03-13 Werner Koch <wk@gnupg.org>
+
+ * main.c, options.h: New option --fixed_list_mode.
+ * keylist.c (list_keyblock_colon): use it here.
+
+ * getkey.c (merge_keys_and_selfsig): Divert merging of public keys
+ to the function used in key selection..
+ * keylist.c (is_uid_valid): Removed.
+ (list_keyblock): Splitted into ..
+ (list_keyblock_print, list_keyblock_colon): .. these.
+ functions. Changed them to use the flags set in the key lookup code.
+ (reorder_keyblock): New, so that primary user IDs are listed first.
+
+ * ringedit.c (keyring_copy): flush the new iobuf chaces before
+ rename or remove operations. This is mainly needed for W32.
+
+ * hkp.c [HAVE_DOSISH_SYSTEM]: Removed the disabled code because we
+ have now W32 socket support in ../util/http.c
+
+ * skclist.c (key_present_in_sk_list): New.
+ (is_duplicated_entry): New.
+ (build_sk_list): Check for duplicates and do that before unlocking.
+
+2001-03-12 Werner Koch <wk@gnupg.org>
+
+ * armor.c (parse_header_line): Removed double empty line check.
+ (parse_header_line): Replaced trim_trailing_ws with a counting
+ function so that we can adjust for the next read.
+
+ * options.skel: Fixed 3 typos. By Thomas Klausner. Replaced the
+ keyserver example by a better working server.
+
+ * parse-packet.c (parse_symkeyenc): Return Invalid_Packet on error.
+ (parse_pubkeyenc): Ditto.
+ (parse_onepass_sig): Ditto.
+ (parse_plaintext): Ditto.
+ (parse_encrypted): Ditto.
+ (parse_signature): Return error at other places too.
+ (parse_key): Ditto.
+ * g10.c (main): Set opt.list_packets to another value when invoked
+ with the --list-packets command.
+ * mainproc.c (do_proc_packets): Don's stop processing when running
+ under --list-packets command.
+
+ * signal.c (do_sigaction): Removed.
+ (init_one_signal): New to replace the above. Needed to support
+ systems without sigactions. Suggested by Dave Dykstra.
+ (got_fatal_signal,init_signals): Use the above here.
+ (do_block): Use sigset() if sigprocmask() is not available.
+
+ * armor.c (parse_hash_header): Test on TIGER192, which is the
+ correct value as per rfc2440. By Edwin Woudt.
+
+2001-03-08 Werner Koch <wk@gnupg.org>
+
+ * misc.c: Include time.h. By James Troup.
+
+ * getkey.c: Re-enabled the unknown user Id and PK caches and
+ increased their sizes.
+
+ * getkey.c (merge_selfsigs_main): Set expire date and continue
+ processing even if we found a revoked key.
+ (merge_selfsigs_subkeys): Ditto.
+
+ * packet.h: Add an is_revoked flag to the user_id packet.
+ * getkey.c (fixup_uidnode): Set that flag here.
+ (merge_selfsigs_main): Fix so that the latest signature is used to
+ find the self-signature for an UID.
+ * parse-packet.c (parse_user_id): Zero out all fields.
+ * mainproc.c (check_sig_and_print): Print the primary user ID
+ according the the node flag and then all other non-revoked user IDs.
+ (is_uid_revoked): Removed; it is now handled by the key selection code.
+
+ Changed the year list of all copyright notices.
+
+2001-03-07 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (finish_lookup): Print an info message only in verbose mode.
+
+2001-03-05 Werner Koch <wk@gnupg.org>
+
+ * packet.h: Replaced sigsubpkt_t value 101 by PRIV_VERIFY_CACHE.
+ We have never used the old value, so we can do this without any harm.
+ * parse-packet.c (dump_sig_subpkt): Ditto.
+ (parse_one_sig_subpkt): Parse that new sub packet.
+ * build-packet.c (build_sig_subpkt): Removed the old one from the
+ hashed area.
+ (delete_sig_subpkt): New.
+ (build_sig_subpkt): Allow an update of that new subpkt.
+ * sig-check.c (check_key_signature2): Add verification caching
+ (cache_selfsig_result): New.
+ * export.c (do_export_stream): Delete that sig subpkt before exporting.
+ * import.c (remove_bad_stuff): New.
+ (import): Apply that function to all imported data
+
+2001-03-03 Werner Koch <wk@gnupg.org>
+
+ * getkey.c: Introduced a new lookup context flag "exact" and used
+ it in all place where we once used primary.
+ (classify_user_id2): Replaced the old function and add an extra
+ argument to return whether an exact keyID has been requested.
+ (key_byname): Removed the unused ctx.primary flag
+ (get_seckey_byname2): Ditto.
+ (finish_lookup): Changed debugging output.
+
+2001-03-02 Werner Koch <wk@gnupg.org>
+
+ * keylist.c (list_one): Remove the merge key calls.
+
+2001-03-01 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (finish_lookup): Don't use it if we no specific usage
+ has been requested.
+ (merge_selfsigs_main): fix UID only if we have an signature.
+ (lookup): Return UNU_PUBKEY etc. instead of NO_PUBKEY if we found
+ a key but the requested usage does not allow this key.
+ * import.c (import_one): Take UNU_PUBKEY into account.
+ * mainproc.c (list_node): Ditto.
+ * keylist.c (list_keyblock): Ditto.
+ * keyedit.c (print_and_check_one_sig): Ditto.
+
+2001-02-09 Werner Koch <wk@gnupg.org>
+
+ * delkey.c (delete_key): Removed that silly assert which rendered
+ the whole new stuff meaningless.
+
+2001-02-08 Werner Koch <wk@gnupg.org>
+
+ * getkey.c (key_byname): It can happen that we have both, sk and pk
+ NULL, fix for that.
+
+ * parse-packet.c (parse_one_sig_subpkt): Add support for
+ primary_uid and key_flags.
+ (can_handle_critical): Ditto
+
+ * parse-packet.c (parse_encrypted): Fixed listing of pktlen for
+ MDC packets.
+
+ * getkey.c: Backported the version of this file from gpg 1.1. this
+ involved some changes in other files too.
+ * parse-packet.c (parse_key): Clear req_usage.
+ * skclist.c (build_sk_list): Use req_usage to pass the usage
+ information to the lookup function.
+ * pkclist.c (build_pk_list): Ditto.
+ * free-packet.c (copy_public_parts_to_secret_key): New.
+ * keydb.h: Add IS_* macros to check the sig_class.
+ * misc.c (openpgp_cipher_test_algo): New.
+ (openpgp_pk_test_algo): New.
+ (openpgp_pk_algo_usage): New.
+ (openpgp_md_test_algo): New.
+ * packet.h: Add a few fields to PKT_{public,secret}_key and
+ PKT_user_id.
+ * seckey-cert.c (do_check): Use the new main_keyid field.
+
+2001-02-04 Werner Koch <wk@gnupg.org>
+
+ * encr-data.c (decrypt_data): Catch error when we had problems to
+ parse the encrypted packet. By Timo.
+
+2001-01-29 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): --batch does now set nogreeting.
+
+ * delkey.c (do_delete_key): Fixed delete-both functionality.
+
+2001-01-22 Werner Koch <wk@gnupg.org>
+
+ * g10.c: New command --delete-secret-and-public-key.
+ * delkey.c (delete_key): Add new arg allow_both.
+ (do_delete_key): Move most stuff from above to this new function.
+
+2001-01-12 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c (passphrase_to_dek): Use MD5 when IDEA is installed
+ and we have no S2K.
+ * mainproc.c (proc_encrypted): Likewise
+
+2001-01-11 Werner Koch <wk@gnupg.org>
+
+ * sig-check.c (do_check): Print the signature key expire message
+ only in verbose mode and added the keyID.
+
+2001-01-09 Werner Koch <wk@gnupg.org>
+
+ * status.c, status.h: New status USERID_HINT.
+ (write_status_text): Replace LF and CR int text by C-escape sequence.
+
+ * passphrase.c (passphrase_to_dek): Fixed the NEED_PASSPHRASE
+ output. It does now always print 2 keyIDs. Emit the new
+ USERID_HINT.
+
+2001-01-08 Werner Koch <wk@gnupg.org>
+
+ * g10.c, options.h: New option --no-expensive-trust-checks.
+ * keylist.c (list_keyblock): Act on this option.
+
+2001-01-04 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Set homedir only in the pre-parsing phase and
+ replace backslashes in the W32 version.
- * gpg.c: New option --merge-only. Suggested by Brendan O'Dea.
- * import.c (import_one): Implemented it here.
- (import_secret_one): Ditto.
- (print_stats): and give some stats.
+2001-01-03 Werner Koch <wk@gnupg.org>
- * gpg.c: New option --try-all-secrets on suggestion from
- Matthias Urlichs.
- * pubkey-enc.c (get_session_key): Quite easy to implement here.
+ * status.c, status.h : New status KEY_CREATED
+ * keygen.c (do_generate_keypair,generate_subkeypair): Emit it.
-Mon Aug 21 17:59:17 CEST 2000 Werner Koch <wk@openit.de>
+2000-12-28 Werner Koch <wk@gnupg.org>
- * gpg.c: New option --use-agent
+ * signal.c (got_fatal_signal): Remove lockfiles here because the
+ atexit stuff does not work due to the use of raise. Suggested by
+ Peter Fales.
+ * gpgv.c (remove_lockfiles): New stub.
+
+2000-12-19 Werner Koch <wk@gnupg.org>
+
+ * status.c, status.h (cpr_get_no_help): New.
+ * keyedit.c (keyedit_menu): Use it here because we have our own
+ help list here.
+
+2000-12-18 Werner Koch <wk@gnupg.org>
+
+ * mainproc.c (print_failed_pkenc): Don't print the sometimes
+ confusing message about unavailabe secret key. Renamed ...
+ (print_pkenc_list): ... to this and introduced failed arg.
+ (proc_encrypted): Print the failed encryption keys and then
+ the one to be used.
+ (proc_pubkey_enc): Store also the key we are going to use.
+
+ * mainproc.c (check_sig_and_print): Don't list revoked user IDs.
+ (is_uid_revoked): New.
+
+2000-12-08 Werner Koch <wk@gnupg.org>
+
+ * pipemode.c: Made the command work. Currently only for
+ non-armored detached signatures.
+ * mainproc.c (release_list): Reset the new pipemode vars.
+ (add_gpg_control): Handle the control packets for pipemode
+ * status.c, status.h: New stati {BEGIN,END}_STREAM.
+
+2000-12-07 Werner Koch <wk@gnupg.org>
+
+ * g10.c: New option --allow-secret-key-import.
+ * import.c (import_keys,import_keys_stream): Honor this option.
+ (import): New arg allow_secret and pass that arg down to ...
+ (import_secret_one): to this and print a warning if secret key
+ importing is not allowed.
+
+2000-12-05 Werner Koch <wk@gnupg.org>
+
+ * cipher.c (cipher_filter): Moved the end_encryption status ...
+ * encode.c (encode_simple,encode_crypt): to here
+ * sign.c (sign_file): and here.
+
+ * status.c (mywrite): Removed.
+ (get_status_string): Removed the LFs from the strings.
+ (set_status_fd,is_status_enabed,write_status_text,
+ write_status_buffer): Replaced all mywrite by stdio calls and use
+ fdopen to create a strem. This is needed to make things smoother
+ in the W32 version.
+
+2000-12-04 Werner Koch <wk@gnupg.org>
+
+ * import.c (merge_blocks): Increment n_sigs for revocations.
+
+2000-11-30 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): Use iobuf_translate_file_handle for all options
+ with filehandles as arguments. This is function does some magic
+ for the W32 API.
+
+ * verify.c (verify_signatures): Add a comment rant about the
+ detached signature problem.
+ * mainproc.c (proc_tree): Issue an error if a detached signature
+ is assumed but a standard one was found.
+ * plaintext.c (hash_datafiles): Don't fall back to read signature
+ from stdin.
+ * openfile.c (open_sigfile): Print verbose message only if the
+ file could be accessed.
+
+2000-11-24 Werner Koch <wk@gnupg.org>
+
+ * passphrase.c [HAVE_DOSISH_SYSTEM]: Disabled all the agent stuff.
+
+2000-11-16 Werner Koch <wk@gnupg.org>
+
+ * g10.c: New option --use-agent
* passphrase.c (agent_open,agent_close): New.
(agent_get_passphrase,agent_clear_passphrase): New.
+ (passphrase_clear_cache): New.
(passphrase_to_dek): Use the agent here.
- * seckey-cert.c (do_check): Clear wrong cached passphrases.
+ * seckey-cert.c (do_check): Clear cached passphrases.
-Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
+2000-11-15 Werner Koch <wk@gnupg.org>
- * status.c (do_get_from_fd): Ooops, we used fd instead of opt.command_fd.
- Thanks to Michael Tokarev.
+ * status.c (write_status_text): Moved the big switch to ...
+ (get_status_string): ... new function.
+ (write_status_buffer): New.
-Mon Jul 31 10:04:47 CEST 2000 Werner Koch <wk@openit.de>
+ * status.c (mywrite): New and replaced all write() by this.
- * encode.c, sign.c, keygen.c, pubkey-enc.c: Replaced all
- gcry_sexp_{car,cdr}_{data,mpi} by the new gcry_sexp_nth_{data,mpi} functions.
+ * status.c, status.h: Add 3 status lcodes for notaions and policy.
+ * mainproc.c (print_notation_data): Do status output of notations.
+
+2000-11-13 Werner Koch <wk@gnupg.org>
- * keygen.c (gen_dsa,gen_elg): Changed the way the factors are stored.
- (factors_from_sexp): Removed.
- * comment.c (make_mpi_comment_node): Removed.
- (make_comment_node_from_buffer): New.
+ * sign.c (clearsign_file): Use LF macro to print linefeed.
+
+2000-11-11 Paul Eggert <eggert@twinsun.com>
-Fri Jul 28 18:19:11 CEST 2000 Werner Koch <wk@openit.de>
+ Clean up the places in the code that incorrectly use "long" or
+ "unsigned long" for file offsets. The correct type to use is
+ "off_t". The difference is important on large-file hosts,
+ where "off_t" is longer than "long".
- * sig-check.c (pk_verify): Fixed the S-Exp withe the pkey.
+ * keydb.h (struct keyblock_pos_struct.offset):
+ Use off_t, not ulong, for file offsets.
+ * packet.h (dbg_search_packet, dbg_copy_some_packets,
+ search_packet, copy_some_packets): Likewise.
+ * parse-packet.c (parse, dbg_search_packet, search_packet,
+ dbg_copy_some_packets, copy_some_packets): Likewise.
+ * ringedit.c (keyring_search): Likewise.
- * gpg.c (main): Use setmode(O_BINARY) for MSDOS while generating random bytes
- (print_mds): Likewise for stdin.
- * plaintext.c (handle_plaintext): Likewise for stdout.
+ * parse-packet.c (parse): Do not use %lu to report file
+ offsets in error diagnostics; it's not portable.
+ * ringedit.c (keyring_search): Likewise.
-Tue Jul 25 17:44:15 CEST 2000 Werner Koch <wk@openit.de>
+2000-11-09 Werner Koch <wk@gnupg.org>
- * keyedit.c (menu_expire): expire date for primary key can be set again.
+ * g10.c (main): New option --enable-special-filenames.
- * keylist.c (is_uid_valid): New.
- (list_keyblock): Print validity information for all user IDs. Note, this
- has to be done at other places too; for now we have only minimal support.
+2000-11-07 Werner Koch <wk@gnupg.org>
+
+ * g10.c (main): New command --pipemode.
+ * pipemode.c: New.
- * sign.c (pk_sign): Changed to use the new S-Exp interface.
- * encode.c (pk_encrypt): Ditto.
- * sig-check.c (pk_verify): Ditto.
- * seckey-cert.c (pk_check_secret_key): Ditto.
- * pubkey-enc.c (pk_decrypt): Ditto.
- * misc.c (pubkey_nbits): Ditto.
- * keygen.c (key_from_sexp,factors_from_sexp,gen_elg,gen_dsa): Ditto.
+2000-10-23 Werner Koch <wk@gnupg.org>
-Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+ * armor.c (armor_filter): Changed output of hdrlines, so that a CR
+ is emitted for DOS systems.
- Replaced everything with the code from the STABLE-BRANCH-1-0 and
- started to backport the changes from the 1.1 development branch
- which are dated according to the ChangeLog of the 1.1 from
- Sat Sep 18 12:16:08 CEST 1999 to Thu May 25 18:39:11 CEST 2000.
- Here are those changes, some of them are duplicates because they
- have been done on both branch simultaneously.
+ * keygen.c (read_parameter_file): Add a cast for isspace().
- * gpg.c (print_mds): Add arg keys as a kludge to print hmacs
- (main): New option --print-hmac.
+ * status.c (myread): Use SIGINT instead of SIGHUP for DOS.
- * trustdb.c (verify_own_keys): Do not print warning about unprotected
- key when in quiet mode.
+2000-10-19 Werner Koch <wk@gnupg.org>
- * build-paket.c (do_user_id): Save offset where name has been stored.
+ * g10.c: New option --ignore-crc-error
+ * armor.c (invalid_crc): New.
+ (radix64_read): Act on new option.
- * ringedit.c : Add new access method KBXF
+ * openfile.c (try_make_homedir): Klaus Singvogel fixed a stupid
+ error introduced on Sep 6th.
- * kbxfile.c: New.
+2000-10-18 Werner Koch <wk@gnupg.org>
- * kbx.h: New.
- * kbxblob.c: Started to work on the keybox stuff.
+ * misc.c (print_cipher_algo_note): Don't print the note for AES.
+ Changed wording.
- * keygen.c (gen_dsa): Modified to work with gcry_pk_genkey.
+2000-10-16 Werner Koch <wk@gnupg.org>
- * Removed dummy-cipher.h from all files.
+ * mainproc.c (do_proc_packets): Hack to fix the problem that
+ signatures are not detected when there is a MDC packet but no
+ compression packet.
+
+ * g10.c (print_hashline): New.
+ (print_mds): Use above func with --with-colons.
- * keygen.c (gen_elg): Modified to work with gcry_pk_genkey.
- (key_from_sexp): New.
- (factors_from_sexp): New.
+ * mainproc.c (check_sig_and_print): Detect multiple signatures
+ and don't verify them.
- * g10.c : Renamed to ...
- * gpg.c : ... this
- * Makefile.am: And fixed it here.
+2000-10-14 Werner Koch <wk@gnupg.org>
- * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_".
+ * mainproc.c (add_onepass_sig): There is an easier solution to the
+ error fixed yesterday; just check that we only have onepass
+ packets. However, the other solution provides an cleaner
+ interface and opens the path to get access to other information
+ from the armore headers.
+ (release_list): Reset some more variables.
- * misc.c (mpi_read_opaque): Fixed double counting.
+2000-10-13 Werner Koch <wk@gnupg.org>
- * seckey-cert.c (do_check): Removed buffer and the unmotivated free
- on it.
+ * mainproc.c (add_gpg_control): New.
+ (do_proc_packets): use it.
+ (proc_plaintext): Changed logic to detect clearsigns.
+ (proc_tree): Check the cleartext sig with some new code.
- * pubkey-enc.c (pk_decrypt): New wrapper for the gcry_ function.
- * seckey-cert.c (pk_check_secret_key): Likewise.
- * encode.c (pk_encrypt): Likewise.
+ * packet.h: New packet PKT_GPG_CONTROL.
+ * parse-packet.c (parse_gpg_control): New.
+ * misc.c (get_session_marker): New.
+ * armor.c (armor_filter): Replaced the faked 1-pass packet by the
+ new control packet.
- * parse-packet.c (parse_key): Fixed case of unencrypted secret keys.
+ * keyedit.c (keyedit_menu): Allow batchmode with a command_fd.
+ * status.c (my_read): New.
+ (do_get_from_fd): use it.
- * misc.c (mpi_print): Use gcry_mpi_aprint.
- (pubkey_nbits): Kludge to use the gcry_pk_ API.
+2000-10-12 Werner Koch <wk@gnupg.org>
- * seskey.c (encode_session_key): Replaced mpi_set_buffer by *_scan.
- (do_encode_md): Ditto.
- (encode_md_value): Ditto.
- * seckey-cert.c (protect_secret_key): Ditto.
- * comment.c (make_mpi_comment_node): Replaced mpi_get_buffer by _print.
- * pubkey-enc.c (get_it): Ditto.
- * sig-check.c (do_signature_check): Ditto.
+ * keygen.c (keygen_add_std_prefs): Add Rijndael to the prefs.
- * keyid.c (do_fingerprint_md): Replaced mpi_get_buffer by gcry_mpi_print.
- (v3_keyid): New.
- (keyid_from_sk): And use it here.
- (keyid_from_pk): Ditto.
- (fingerprint_from_sk): Ditto.
- (fingerprint_from_pk): Ditto.
+2000-10-07 Werner Koch <wk@gnupg.org>
- * misc.c (mpi_print): New.
+ * gpgv.c: Add more stubs for ununsed code to make the binary smaller.
- * misc.c (checksum_mpi): Now uses gcry_mpi_print to get the data.
+Wed Oct 4 15:50:18 CEST 2000 Werner Koch <wk@openit.de>
- * seckey-cert.c (do_check): Replaced mpi_read_from_buffer.
+ * sign.c (hash_for): New arg to take packet version in account, changed
+ call callers.
- * armor.c (armor_filter): Made the "Comment:" header translatable.
+ * gpgv.c: New.
+ * Makefile.am: Rearranged source files so that gpgv can be build with
+ at least files as possible.
- * seckey-cert.c: Removed obsolete mpi_*_protect_flag.
- * parse-packet.c: Ditto.
+Mon Sep 18 12:13:52 CEST 2000 Werner Koch <wk@openit.de>
- * misc.c (mpi_read): Removed the secure argumet becuase it is
- never used. Changed all Callers.
- (mpi_read_opaque): New.
- (mpi_write_opaque): New.
- * parse-packet.c (parse_key): Use the opaque method also for
- v3 keys.
- * build-packet.c (do_secret_key): Likewise.
+ * hkp.c (not_implemented): Print a notice for W32
- * g10.c (main): Check libgcrypt version.
+Fri Sep 15 18:40:36 CEST 2000 Werner Koch <wk@openit.de>
- * packet.h: replaced inclusion of mpi.h by a plain typeedef of the
- gcry_mpi structure and removed all inclusions of "mpi.h" in all
- sources.
+ * keygen.c (keygen_add_std_prefs): Changed order of preferences to
+ twofish, cast5, blowfish.
- * g10.c: Add --delete-secret-key to the help page.
+ * pkclist.c (algo_available): Removed hack to disable Twofish.
- * g10.c (main): Changed the default homedir to "~/.gnupg-test" so
- that we don't mess up with the stable version.
+Thu Sep 14 17:45:11 CEST 2000 Werner Koch <wk@openit.de>
- * misc.c (mpi_write): New.
- (mpi_write): New.
+ * parse-packet.c (dump_sig_subpkt): Dump key flags. Print special
+ warning in case of faked ARRs.
- * misc.c (checksum_u16_nobug): Removed.
- (checksum_mpi_counted_nbits): Renamed to ...
- (checksum_mpi): ... this to superseed the old one. Changed all
- callers. This is because we do not emulate the old gpg bug anymore.
- * g10.c (oEmuChecksumBug): Removed.
+ * getkey.c (finsih_lookup): Hack so that for v4 RSA keys the subkey
+ is used for encryption.
- * g10.c (register_extension): New...
- (main): Use it here instead of register_cipher_extesnion.
- (strusage): s/strusage/my_strusage/ . Made static.
- (main): Use set_strusage().
+Thu Sep 14 14:20:38 CEST 2000 Werner Koch <wk@openit.de>
- * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that
- traditional cpp don't mess up the macros. Suggested by Jos Backus.
+ * g10.c (main): Default S2K algorithms are now SHA1 and CAST5 - this
+ should solve a lot of compatibility problems with other OpenPGP
+ apps because those algorithms are SHOULD and not optional. The old
+ way to force it was by using the --openpgp option whith the drawback
+ that this would disable a couple of workarounds for PGP.
- * armor.c (parse_header_line): Stop parsing on a only WS line too.
- Suggested by Aric Cyr.
+ * g10.c (main): Don't set --quite along with --no-tty. By Frank Tobin.
- * misc.c (pull_in_libs): Removed.
+ * misc.c (disable_core_dump): Don't display a warning here but a return
+ a status value and ...
+ * g10.c (main): ...print warnining here. Suggested by Sam Roberts.
- * mainproc.c (list_node): Print the PK algo in the --with-colon mode.
- * keylist.c (list_keyblock): Ditto.
+Wed Sep 13 18:12:34 CEST 2000 Werner Koch <wk@openit.de>
- * misc.c (pull_in_libs): Removed pull in of g10c.
+ * keyedit.c (keyedit_menu): Allow to use "debug" on the secret key.
- * misc.c (map_gcry_rc): Removed here and chnaged all users.
+ * ringedit.c (cmp_seckey): Fix for v4 RSA keys.
+ * seckey-cert.c (do_check): Workaround for PGP 7 bug.
- * getkey.c: Replaced check_pubkey_algo by openpgp_pk_test_algo.
- * import.c (delete_inv_parts): Ditto.
- * pkclist.c: Ditto.
- * skclist.c: Ditto.
- * pubkey-enc.c: Ditto.
+Wed Sep 6 17:55:47 CEST 2000 Werner Koch <wk@openit.de>
- * g10.c (main): Replaced the function to diable PK algos.
+ * misc.c (print_pubkey_algo_note): Do not print the RSA notice.
+ * sig-check.c (do_signature_check): Do not emit the RSA status message.
+ * pubkey-enc.c (get_session_key): Ditto.
- * g10.c (main): Replaced get_random_bits by gcry_random_bytes.
- * seskey.c (encode_session_key): Likewise.
- (make_session_key): Renamed randomize_buffer to gcry_randomize
- and use the GCRY_xxx_RANDOM constants.
- * cipher.c (write_header): Ditto.
- * passphrase.c (hash_passphrase): Ditto.
- * seckey-cert.c (protect_secret_key): Ditto.
+ * encode.c (encode_simple, encode_crypt): Fix for large files.
+ * sign.c (sign_file): Ditto.
- * getkey.c (find_by_name): Replaced rmd160_hash_buffer
- by gcry_md_hash_buffer.
- * keyedit.c (show_prefs): Ditto.
- * keylist.c (list_keyblock): Ditto.
- * trustdb.c (print_uid_from_keyblock): Ditto.
- (make_uid_records): Ditto.
+Wed Sep 6 14:59:09 CEST 2000 Werner Koch <wk@openit.de>
- * skclist.c (build_sk_list): Removed the test on faked RNGs.
- (is_insecure): Removed.
- * g10.c (--quick-random): Removed this option.
+ * passphrase.c (hash_passphrase): Removed funny assert. Reported by
+ David Mathog.
- * Replaced all PUBKEY_ALGO_xxx by GCRY_PK_xxxx.
+ * openfile.c (try_make_homedir): Changes for non-Posix systems.
+ * g10.c (main): Take the default homedir from macro.
- * misc.c (pubkey_algo_npkey): New as a wrapper around the gcry fucntion.
- (pubkey_algo_nskey): Ditto.
- (pubkey_algo_nsig): Ditto.
- (pubkey_algo_nenc): Ditto.
+ * g10.c: The --trusted-key option is back.
+ * trustdb.c (verify_own_key): Handle this option.
+ (add_ultimate_key): Moved stuff from verify_own_key to this new func.
+ (register_trusted_key): New.
- * Makefile.am (basicdefs.h): Added.
- (install-data-local): Removed the handling for historic gpgm.
+Fri Aug 25 16:05:38 CEST 2000 Werner Koch <wk@openit.de>
- * misc.c (openpgp_cipher_test_algo): New.
- (openpgp_pk_test_algo): New.
- (openpgp_md_test_algo): New.
+ * parse-packet.c (dump_sig_subpkt): Print info about the ARR.
+
+ * openfile.c (overwrite_filep): Always return okay if the file is
+ called /dev/null.
+ (make_outfile_name): Add ".sign" to the list of know extensions.
+ (open_sigfile): Ditto.
+
+Wed Aug 23 19:52:51 CEST 2000 Werner Koch <wk@openit.de>
+
+ * g10.c: New option --allow-freeform-uid. By Jeroen C. van Gelderen.
+ * keygen.c (ask_user_id): Implemented here.
+
+Fri Aug 4 14:23:05 CEST 2000 Werner Koch <wk@openit.de>
+
+ * status.c (do_get_from_fd): Ooops, we used fd instead of opt.command_fd.
+ Thanks to Michael Tokarev.
- * g10.c (build_list): Changed to use the new functions from libgcrypt.
+Tue Aug 1 20:06:23 CEST 2000 Werner Koch <wk@openit.de>
- * ringedit.c (enum_keyblocks): Set .rt to 0 on open.
+ * g10.c: New opttion --try-all-secrets on suggestion from Matthias Urlichs.
+ * pubkey-enc.c (get_session_key): Quite easy to implement here.
- * encode.c (encode_simple): Use new CTB when we don't have the
- length of the file. This is somewhat strange as the comment above
- indicates that this part is actually fixed for PGP 5 - maybe I simply
- lost the source line, tsss.
+Thu Jul 27 17:33:04 CEST 2000 Werner Koch <wk@openit.de>
- * sign.c (clearsign_file): Avoid duplicated Entries in the "Hash:"
- line. Those headers are now only _not_ printed when there are
- only old-style keys _and_ all hashs are MD5.
+ * g10.c: New option --merge-only. Suggested by Brendan O'Dea.
+ * import.c (import_one): Implemented it here
+ (import_secret_one): Ditto.
+ (print_stats): and give some stats.
- (clearsign_file): Use gcry_md_test_algo() and gcry_md_algo_name().
+Thu Jul 27 12:01:00 CEST 2000 Werner Koch <wk@openit.de>
- * openfile.c (make_outfile_name): Use case-insenstive compare for
- DOS systems. Add ".pgp" to the list of know extensions.
- (open_outfile): For DOS systems try to replace the suffix instead of
- appending it.
+ * g10.c: New options --show-session-key and --override-session-key
+ * pubkey-enc.c (hextobyte): New.
+ (get_override_session_key): New.
+ * mainproc.c (proc_pubkey_enc): Add session-key stuff.
+ * status.h, status.c (STATUS_SESSION_KEY): New.
- * encr-data.c (decrypt_data): Reset error on a weak key.
+Thu Jul 27 10:02:38 CEST 2000 Werner Koch <wk@openit.de>
- * cipher.c: Replaced the cipher and digest functions by the gcry_ ones.
- * seckey-cert.c: Ditto.
- * seskey.c: Ditto.
- * g10.c (print_mds): Replaced digst functions with the new gcry_ ones.
- * keyid.c: Ditto.
- * mainproc.c: Ditto.
- * passphrase.c: Ditto.
- * sig-check.c: Ditto.
- * sign.c: Ditto.
+ * g10.c (main): Use setmode(O_BINARY) for MSDOS while generating random bytes
+ (print_mds): Likewise for stdin.
+ * plaintext.c (handle_plaintext): Likewise for stdout.
+
+Mon Jul 24 10:30:17 CEST 2000 Werner Koch <wk@openit.de>
+
+ * keyedit.c (menu_expire): expire date for primary key can be set again.
+
+Wed Jul 19 11:26:43 CEST 2000 Werner Koch <wk@openit.de>
+
+ * keylist.c (is_uid_valid): New.
+ (list_keyblock): Print validity information for all user IDs. Note, this
+ has to be done at other places too; for now we have only minimal support.
+
+Wed Jul 12 13:32:06 CEST 2000 Werner Koch <wk@openit.de>
- * pkclist.c (do_edit_ownertrust): Made the answer string const.
+ * helptext.c, pkclist.c: s/superseeded/superseded/
- * basicdefs.h: New. Move some defs and decl to this header.
+Mon Jul 10 16:08:57 CEST 2000 Werner Koch <wk@openit.de>
- * openfile.c (open_outfile): Fixed the 8dot3 handling.
+ * parse-packet.c (enum_sig_subpkt): Fixed testing on crtitical bit in case
+ of a NULL buffer. Reported by Peter Marschall.
- * passphrase.c (passphrase_to_dek): Print uid using utf8 func.
- * delkey.c (delete_key): Ditto.
- * pkclist.c (show_paths,do_edit_ownertrust,do_we_trust): Ditto
- (do_we_trust_pre): Ditto.
- * trustdb.c (print_user_id,check_uidsigs): Ditto.
- * revoke.c (gen_revoke,ask_revoke_sig): Ditto.
+Wed Jul 5 13:28:45 CEST 2000 Werner Koch <wk@openit.de>
- * filter.h: Changed cipher handle types to the the GCRY_xxx ones.
- replaces include cipher by system header include gcrypt.h.
- * cipher.c: replaced the cipher functions by the gcry_ ones.
- Ditto for the md functions.
+ * keyedit.c, keyid.c: Add some _()
- * misc.c (map_gcry_rc): New.
+ * argparse.c: Changed the flag to suppress --version handling to also
+ suppress --help.
-Wed Jun 28 11:54:44 CEST 2000 Werner Koch <wk@>
+Wed Jun 28 11:54:44 CEST 2000 Werner Koch <wk@openit.de>
* armor.c (armor_filter): Set sigclass to 0 in case of non-dash-escaped
clearsig. This makes this mode work again.
@@ -461,7 +3478,7 @@ Fri Jun 9 10:09:52 CEST 2000 Werner Koch <wk@openit.de>
Wed Jun 7 19:19:09 CEST 2000 Werner Koch <wk@openit.de>
- * sig-check.c (do_check): Use EMULATE_MDENCODE also on v4 paclets.
+ * sig-check.c (do_check): Use EMULATE_MDENCODE also on v4 packets.
Wed Jun 7 17:25:38 CEST 2000 Werner Koch <wk@openit.de>
@@ -3280,3 +6297,13 @@ Thu Feb 12 22:24:42 1998 Werner Koch (wk@frodo)
* pubkey-enc.c (get_session_key): rewritten
+
+ Copyright 1998,1999,2000,2001,2002 Free Software Foundation, Inc.
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 3e724512b..f59cd8b2d 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -1,84 +1,104 @@
+# Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
## Process this file with automake to produce Makefile.in
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
-EXTRA_DIST = OPTIONS pubring.asc options.skel
-OMIT_DEPENDENCIES = zlib.h zconf.h
-LDFLAGS = @LDFLAGS@ $(LIBGCRYPT_LIBS)
-# we need to add libutil.la a second time because we have to resolve
-# gpg_log_ in some libjnlib modules. - very ugly - should be removed soon.
-needed_libs = ../util/libutil.a \
- ../jnlib/libjnlib.a ../util/libutil.a
+INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl
+EXTRA_DIST = options.skel
+# it seems that we can't use this with automake 1.5
+#OMIT_DEPENDENCIES = zlib.h zconf.h
+LDFLAGS = @LDFLAGS@ @DYNLINK_LDFLAGS@
+needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
#noinst_PROGRAMS = gpgd
-#bin_PROGRAMS = gpg kbxutil
-noinst_PROGRAMS = gpg kbxutil
+bin_PROGRAMS = gpg gpgv
common_source = \
+ global.h \
build-packet.c \
compress.c \
- basicdefs.h \
filter.h \
free-packet.c \
getkey.c \
- keydb.h \
- delkey.c \
- pkclist.c \
- skclist.c \
- ringedit.c \
+ keydb.c keydb.h \
+ keyring.c keyring.h \
+ seskey.c \
kbnode.c \
- kbx.h \
- kbxblob.c \
- kbxio.c \
- kbxfile.c \
main.h \
mainproc.c \
armor.c \
mdfilter.c \
textfilter.c \
- cipher.c \
misc.c \
options.h \
openfile.c \
keyid.c \
- trustdb.c \
- trustdb.h \
- tdbdump.c \
- tdbio.c \
- tdbio.h \
- hkp.h \
- hkp.c \
packet.h \
parse-packet.c \
- passphrase.c \
- pubkey-enc.c \
- seckey-cert.c \
- seskey.c \
- import.c \
- export.c \
comment.c \
status.c \
status.h \
- sign.c \
plaintext.c \
- encr-data.c \
- encode.c \
- revoke.c \
- keylist.c \
sig-check.c \
- signal.c \
- helptext.c
+ keylist.c \
+ signal.c
-gpg_SOURCES = gpg.c \
+gpg_SOURCES = g10.c \
$(common_source) \
+ pkclist.c \
+ skclist.c \
+ pubkey-enc.c \
+ passphrase.c \
+ seckey-cert.c \
+ encr-data.c \
+ cipher.c \
+ encode.c \
+ sign.c \
verify.c \
+ revoke.c \
decrypt.c \
keyedit.c \
dearmor.c \
- keygen.c
+ import.c \
+ export.c \
+ hkp.h \
+ hkp.c \
+ trustdb.c \
+ trustdb.h \
+ tdbdump.c \
+ tdbio.c \
+ tdbio.h \
+ delkey.c \
+ keygen.c \
+ pipemode.c \
+ helptext.c \
+ keyserver.c \
+ keyserver-internal.h \
+ photoid.c photoid.h \
+ exec.c exec.h
+
+
+
+gpgv_SOURCES = gpgv.c \
+ $(common_source) \
+ verify.c
+
-# fixme: remove unused sources from kbxutil
-kbxutil_SOURCES = kbxutil.c \
- $(common_source)
#gpgd_SOURCES = gpgd.c \
@@ -88,15 +108,18 @@ kbxutil_SOURCES = kbxutil.c \
# ks-db.h \
# $(common_source)
-
-LDADD = $(needed_libs) @ZLIBS@ @INTLLIBS@
-
+LDADD = $(needed_libs) @ZLIBS@ @INTLLIBS@
+# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
+gpg_LDADD = @LIBOBJS@ $(LDADD) @NETLIBS@
$(PROGRAMS): $(needed_libs)
-
install-data-local:
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
$(INSTALL_DATA) $(srcdir)/options.skel \
$(DESTDIR)$(pkgdatadir)/options.skel
-
+ @set -e;\
+ if test -f $(DESTDIR)$(bindir)/gpgm ; then \
+ echo "removing obsolete gpgm binary" ; \
+ rm $(DESTDIR)$(bindir)/gpgm ; \
+ fi
diff --git a/g10/armor.c b/g10/armor.c
index 819c951dc..9c7858fe6 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -1,5 +1,5 @@
/* armor.c - Armor flter
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -28,7 +28,7 @@
#include "errors.h"
#include "iobuf.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "filter.h"
#include "packet.h"
@@ -151,8 +151,9 @@ initialize(void)
}
/****************
- * Check whether this is an armored file or not
- * See also parse-packet.c for details on this code
+ * Check whether this is an armored file or not See also
+ * parse-packet.c for details on this code For unknown historic
+ * reasons we use a string here but only the first byte will be used.
* Returns: True if it seems to be armored
*/
static int
@@ -195,6 +196,7 @@ use_armor_filter( IOBUF a )
byte buf[1];
int n;
+ /* fixme: there might be a problem with iobuf_peek */
n = iobuf_peek(a, buf, 1 );
if( n == -1 )
return 0; /* EOF, doesn't matter whether armored or not */
@@ -210,7 +212,7 @@ static void
invalid_armor(void)
{
write_status(STATUS_BADARMOR);
- gpg_exit(1); /* stop here */
+ g10_exit(1); /* stop here */
}
@@ -245,7 +247,9 @@ parse_hash_header( const char *line )
found |= 2;
else if( !strncmp( s, "MD5", s2-s ) )
found |= 4;
- else if( !strncmp( s, "TIGER", s2-s ) )
+ else if( !strncmp( s, "TIGER192", s2-s ) )
+ found |= 8;
+ else if( !strncmp( s, "TIGER", s2-s ) ) /* used by old versions */
found |= 8;
else
return 0;
@@ -283,6 +287,14 @@ is_armor_header( byte *line, unsigned len )
return -1;
save_p = p;
p += 5;
+
+ /* Some mail programs on Windows seem to add spaces to the end of
+ the line. This becomes strict if --openpgp is set. */
+
+ if(!opt.rfc2440)
+ while(*p==' ')
+ p++;
+
if( *p == '\r' )
p++;
if( *p == '\n' )
@@ -312,19 +324,19 @@ is_armor_header( byte *line, unsigned len )
* >0: Good header line
*/
static int
-parse_header_line( armor_filter_context_t *afx, byte *line, unsigned len )
+parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len )
{
byte *p;
int hashes=0;
+ unsigned int len2;
- /* fixme: why this double check? I think the original code w/o the
- * second check for an empty line was done from an early draft of
- * of OpenPGP - or simply very stupid code */
- if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
- return 0; /* empty line */
- len = trim_trailing_ws( line, len );
- if( !len )
- return 0; /* WS only same as empty line */
+ len2 = check_trailing_ws( line, len );
+ if( !len2 ) {
+ afx->buffer_pos = len2; /* (it is not the fine way to do it here) */
+ return 0; /* WS only: same as empty line */
+ }
+ len = len2;
+ line[len2] = 0;
p = strchr( line, ':');
if( !p || !p[1] ) {
@@ -399,7 +411,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
if( afx->in_cleartext ) {
log_error(_("nested clear text signatures\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
afx->in_cleartext = 1;
}
@@ -429,7 +441,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
i = parse_header_line( afx, line, len );
if( i <= 0 ) {
if( i )
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
break;
}
}
@@ -502,7 +514,7 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
/* the buffer is always allocated with enough space to append
* the removed [CR], LF and a Nul
* The reason for this complicated procedure is to keep at least
- * the original tupe of lineending - handling of the removed
+ * the original type of lineending - handling of the removed
* trailing spaces seems to be impossible in our method
* of faking a packet; either we have to use a temporary file
* or calculate the hash here in this module and somehow find
@@ -590,6 +602,15 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
}
+static int
+invalid_crc(void)
+{
+ if ( opt.ignore_crc_error )
+ return 0;
+ log_inc_errorcount();
+ return G10ERR_INVALID_ARMOR;
+}
+
static int
radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
@@ -636,9 +657,9 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
if( isxdigit(cc1) && isxdigit(cc2)
&& strchr( "=\n\r\t ", cc3 )) {
/* well it seems to be the case - adjust */
- c = isdigit(cc1)? (cc1 - '0'): (toupper(cc1)-'A'+10);
+ c = isdigit(cc1)? (cc1 - '0'): (ascii_toupper(cc1)-'A'+10);
c <<= 4;
- c |= isdigit(cc2)? (cc2 - '0'): (toupper(cc2)-'A'+10);
+ c |= isdigit(cc2)? (cc2 - '0'): (ascii_toupper(cc2)-'A'+10);
afx->buffer_pos += 2;
afx->qp_detected = 1;
goto again;
@@ -728,20 +749,23 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
break; /* eof */
} while( ++idx < 4 );
if( c == -1 ) {
- log_error(_("premature eof (in CRC)\n"));
- rc = GPGERR_INVALID_ARMOR;
- }
+ log_info(_("premature eof (in CRC)\n"));
+ rc = invalid_crc();
+ }
else if( idx != 4 ) {
- log_error(_("malformed CRC\n"));
- rc = GPGERR_INVALID_ARMOR;
+ log_info(_("malformed CRC\n"));
+ rc = invalid_crc();
}
else if( mycrc != afx->crc ) {
- log_error(_("CRC error; %06lx - %06lx\n"),
+ log_info (_("CRC error; %06lx - %06lx\n"),
(ulong)afx->crc, (ulong)mycrc);
- rc = GPGERR_INVALID_ARMOR;
+ rc = invalid_crc();
}
else {
rc = 0;
+ /* FIXME: Here we should emit another control packet,
+ * so that we know in mainproc that we are processing
+ * a clearsign message */
#if 0
for(rc=0;!rc;) {
rc = 0 /*check_trailer( &fhdr, c )*/;
@@ -754,11 +778,11 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
rc = 0;
else if( rc == 2 ) {
log_error(_("premature eof (in Trailer)\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
else {
log_error(_("error in trailer line\n"));
- rc = GPGERR_INVALID_ARMOR;
+ rc = G10ERR_INVALID_ARMOR;
}
#endif
}
@@ -815,7 +839,9 @@ armor_filter( void *opaque, int control,
*ret_len = n;
}
else if( control == IOBUFCTRL_UNDERFLOW ) {
- if( size < 15+(4*15) ) /* need space for up to 4 onepass_sigs */
+ /* We need some space for the faked packet. The minmum required
+ * size is ~18 + length of the session marker */
+ if( size < 50 )
BUG(); /* supplied buffer too short */
if( afx->faked )
@@ -831,7 +857,14 @@ armor_filter( void *opaque, int control,
rc = -1;
}
else if( afx->faked ) {
- unsigned hashes = afx->hashes;
+ unsigned int hashes = afx->hashes;
+ const byte *sesmark;
+ size_t sesmarklen;
+
+ sesmark = get_session_marker( &sesmarklen );
+ if ( sesmarklen > 20 )
+ BUG();
+
/* the buffer is at least 15+n*15 bytes long, so it
* is easy to construct the packets */
@@ -842,36 +875,21 @@ armor_filter( void *opaque, int control,
afx->pgp2mode = 1;
}
n=0;
- do {
- /* first some onepass signature packets */
- buf[n++] = 0x90; /* old format, type 4, 1 length byte */
- buf[n++] = 13; /* length */
- buf[n++] = 3; /* version */
- buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
- if( hashes & 1 ) {
- hashes &= ~1;
- buf[n++] = GCRY_MD_RMD160;
- }
- else if( hashes & 2 ) {
- hashes &= ~2;
- buf[n++] = GCRY_MD_SHA1;
- }
- else if( hashes & 4 ) {
- hashes &= ~4;
- buf[n++] = GCRY_MD_MD5;
- }
- else if( hashes & 8 ) {
- hashes &= ~8;
- buf[n++] = GCRY_MD_TIGER;
- }
- else
- buf[n++] = 0; /* (don't know) */
-
- buf[n++] = 0; /* public key algo (don't know) */
- memset(buf+n, 0, 8); /* don't know the keyid */
- n += 8;
- buf[n++] = !hashes; /* last one */
- } while( hashes );
+ /* first a gpg control packet */
+ buf[n++] = 0xff; /* new format, type 63, 1 length byte */
+ n++; /* see below */
+ memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
+ buf[n++] = CTRLPKT_CLEARSIGN_START;
+ buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */
+ if( hashes & 1 )
+ buf[n++] = DIGEST_ALGO_RMD160;
+ if( hashes & 2 )
+ buf[n++] = DIGEST_ALGO_SHA1;
+ if( hashes & 4 )
+ buf[n++] = DIGEST_ALGO_MD5;
+ if( hashes & 8 )
+ buf[n++] = DIGEST_ALGO_TIGER;
+ buf[1] = n - 2;
/* followed by a plaintext packet */
buf[n++] = 0xaf; /* old packet format, type 11, var length */
@@ -908,9 +926,8 @@ armor_filter( void *opaque, int control,
PRINTABLE_OS_NAME ")" LF );
/* write the comment string or a default one */
- s = opt.comment_string ? opt.comment_string
- : _("For info see http://www.gnupg.org");
- if( *s ) {
+ s = opt.comment_string;
+ if( s && *s ) {
iobuf_writestr(a, "Comment: " );
for( ; *s; s++ ) {
if( *s == '\n' )
@@ -925,8 +942,15 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a, LF );
}
- if( afx->hdrlines )
- iobuf_writestr(a, afx->hdrlines);
+ if ( afx->hdrlines ) {
+ for ( s = afx->hdrlines; *s; s++ ) {
+ #ifdef HAVE_DOSISH_SYSTEM
+ if ( *s == '\n' )
+ iobuf_put( a, '\r');
+ #endif
+ iobuf_put(a, *s );
+ }
+ }
iobuf_writestr(a, LF );
afx->status++;
afx->idx = 0;
@@ -1041,7 +1065,7 @@ armor_filter( void *opaque, int control,
if( afx->qp_detected )
log_error(_("quoted printable character in armor - "
"probably a buggy MTA has been used\n") );
- gcry_free( afx->buffer );
+ m_free( afx->buffer );
afx->buffer = NULL;
}
else if( control == IOBUFCTRL_DESC )
@@ -1058,7 +1082,7 @@ make_radix64_string( const byte *data, size_t len )
{
char *buffer, *p;
- buffer = p = gcry_xmalloc( (len+2)/3*4 + 1 );
+ buffer = p = m_alloc( (len+2)/3*4 + 1 );
for( ; len >= 3 ; len -= 3, data += 3 ) {
*p++ = bintoasc[(data[0] >> 2) & 077];
*p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
@@ -1078,3 +1102,221 @@ make_radix64_string( const byte *data, size_t len )
return buffer;
}
+
+/***********************************************
+ * For the pipemode command we can't use the armor filter for various
+ * reasons, so we use this new unarmor_pump stuff to remove the armor
+ */
+
+enum unarmor_state_e {
+ STA_init = 0,
+ STA_bypass,
+ STA_wait_newline,
+ STA_wait_dash,
+ STA_first_dash,
+ STA_compare_header,
+ STA_found_header_wait_newline,
+ STA_skip_header_lines,
+ STA_skip_header_lines_non_ws,
+ STA_read_data,
+ STA_wait_crc,
+ STA_read_crc,
+ STA_ready
+};
+
+struct unarmor_pump_s {
+ enum unarmor_state_e state;
+ byte val;
+ int checkcrc;
+ int pos; /* counts from 0..3 */
+ u32 crc;
+ u32 mycrc; /* the one store in the data */
+};
+
+
+
+UnarmorPump
+unarmor_pump_new (void)
+{
+ UnarmorPump x;
+
+ if( !is_initialized )
+ initialize();
+ x = m_alloc_clear (sizeof *x);
+ return x;
+}
+
+void
+unarmor_pump_release (UnarmorPump x)
+{
+ m_free (x);
+}
+
+/*
+ * Get the next character from the ascii armor taken from the IOBUF
+ * created earlier by unarmor_pump_new().
+ * Return: c = Character
+ * 256 = ignore this value
+ * -1 = End of current armor
+ * -2 = Premature EOF (not used)
+ * -3 = Invalid armor
+ */
+int
+unarmor_pump (UnarmorPump x, int c)
+{
+ int rval = 256; /* default is to ignore the return value */
+
+ switch (x->state) {
+ case STA_init:
+ {
+ byte tmp[1];
+ tmp[0] = c;
+ if ( is_armored (tmp) )
+ x->state = c == '-'? STA_first_dash : STA_wait_newline;
+ else {
+ x->state = STA_bypass;
+ return c;
+ }
+ }
+ break;
+ case STA_bypass:
+ return c; /* return here to avoid crc calculation */
+ case STA_wait_newline:
+ if (c == '\n')
+ x->state = STA_wait_dash;
+ break;
+ case STA_wait_dash:
+ x->state = c == '-'? STA_first_dash : STA_wait_newline;
+ break;
+ case STA_first_dash: /* just need for initalization */
+ x->pos = 0;
+ x->state = STA_compare_header;
+ case STA_compare_header:
+ if ( "-----BEGIN PGP SIGNATURE-----"[++x->pos] == c ) {
+ if ( x->pos == 28 )
+ x->state = STA_found_header_wait_newline;
+ }
+ else
+ x->state = c == '\n'? STA_wait_dash : STA_wait_newline;
+ break;
+ case STA_found_header_wait_newline:
+ /* to make CR,LF issues easier we simply allow for white space
+ behind the 5 dashes */
+ if ( c == '\n' )
+ x->state = STA_skip_header_lines;
+ else if ( c != '\r' && c != ' ' && c != '\t' )
+ x->state = STA_wait_dash; /* garbage after the header line */
+ break;
+ case STA_skip_header_lines:
+ /* i.e. wait for one empty line */
+ if ( c == '\n' ) {
+ x->state = STA_read_data;
+ x->crc = CRCINIT;
+ x->val = 0;
+ x->pos = 0;
+ }
+ else if ( c != '\r' && c != ' ' && c != '\t' )
+ x->state = STA_skip_header_lines_non_ws;
+ break;
+ case STA_skip_header_lines_non_ws:
+ /* like above but we already encountered non white space */
+ if ( c == '\n' )
+ x->state = STA_skip_header_lines;
+ break;
+ case STA_read_data:
+ /* fixme: we don't check for the trailing dash lines but rely
+ * on the armor stop characters */
+ if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
+ break; /* skip all kind of white space */
+
+ if( c == '=' ) { /* pad character: stop */
+ if( x->pos == 1 ) /* in this case val has some value */
+ rval = x->val;
+ x->state = STA_wait_crc;
+ break;
+ }
+
+ {
+ int c2;
+ if( (c = asctobin[(c2=c)]) == 255 ) {
+ log_error(_("invalid radix64 character %02x skipped\n"), c2);
+ break;
+ }
+ }
+
+ switch(x->pos) {
+ case 0:
+ x->val = c << 2;
+ break;
+ case 1:
+ x->val |= (c>>4)&3;
+ rval = x->val;
+ x->val = (c<<4)&0xf0;
+ break;
+ case 2:
+ x->val |= (c>>2)&15;
+ rval = x->val;
+ x->val = (c<<6)&0xc0;
+ break;
+ case 3:
+ x->val |= c&0x3f;
+ rval = x->val;
+ break;
+ }
+ x->pos = (x->pos+1) % 4;
+ break;
+ case STA_wait_crc:
+ if( c == '\n' || c == ' ' || c == '\r' || c == '\t' || c == '=' )
+ break; /* skip ws and pad characters */
+ /* assume that we are at the next line */
+ x->state = STA_read_crc;
+ x->pos = 0;
+ x->mycrc = 0;
+ case STA_read_crc:
+ if( (c = asctobin[c]) == 255 ) {
+ rval = -1; /* ready */
+ if( x->crc != x->mycrc ) {
+ log_info (_("CRC error; %06lx - %06lx\n"),
+ (ulong)x->crc, (ulong)x->mycrc);
+ if ( invalid_crc() )
+ rval = -3;
+ }
+ x->state = STA_ready; /* not sure whether this is correct */
+ break;
+ }
+
+ switch(x->pos) {
+ case 0:
+ x->val = c << 2;
+ break;
+ case 1:
+ x->val |= (c>>4)&3;
+ x->mycrc |= x->val << 16;
+ x->val = (c<<4)&0xf0;
+ break;
+ case 2:
+ x->val |= (c>>2)&15;
+ x->mycrc |= x->val << 8;
+ x->val = (c<<6)&0xc0;
+ break;
+ case 3:
+ x->val |= c&0x3f;
+ x->mycrc |= x->val;
+ break;
+ }
+ x->pos = (x->pos+1) % 4;
+ break;
+ case STA_ready:
+ rval = -1;
+ break;
+ }
+
+ if ( !(rval & ~255) ) { /* compute the CRC */
+ x->crc = (x->crc << 8) ^ crc_table[((x->crc >> 16)&0xff) ^ rval];
+ x->crc &= 0x00ffffff;
+ }
+
+ return rval;
+}
+
+
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 93381879c..e24ac3b2a 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -1,5 +1,5 @@
/* build-packet.c - assemble packets and write them
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,13 +24,14 @@
#include <string.h>
#include <assert.h>
-#include <gcrypt.h>
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
+#include "mpi.h"
#include "util.h"
+#include "cipher.h"
+#include "memory.h"
#include "options.h"
-#include "main.h"
static int do_comment( IOBUF out, int ctb, PKT_comment *rem );
@@ -80,8 +81,8 @@ build_packet( IOBUF out, PACKET *pkt )
case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break;
case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break;
case PKT_USER_ID:
- if( pkt->pkt.user_id->photo )
- pkttype = PKT_PHOTO_ID;
+ if( pkt->pkt.user_id->attrib_data )
+ pkttype = PKT_ATTRIBUTE;
break;
default: break;
}
@@ -91,7 +92,7 @@ build_packet( IOBUF out, PACKET *pkt )
else
ctb = 0x80 | ((pkttype & 15)<<2);
switch( pkttype ) {
- case PKT_PHOTO_ID:
+ case PKT_ATTRIBUTE:
case PKT_USER_ID:
rc = do_user_id( out, ctb, pkt->pkt.user_id );
break;
@@ -134,7 +135,7 @@ build_packet( IOBUF out, PACKET *pkt )
rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig );
break;
case PKT_RING_TRUST:
- break; /* ignore it */
+ break; /* ignore it (keyring.c does write it directly)*/
default:
log_bug("invalid packet type in build_packet()\n");
break;
@@ -158,7 +159,7 @@ calc_packet_length( PACKET *pkt )
n = calc_plaintext( pkt->pkt.plaintext );
new_ctb = pkt->pkt.plaintext->new_ctb;
break;
- case PKT_PHOTO_ID:
+ case PKT_ATTRIBUTE:
case PKT_USER_ID:
case PKT_COMMENT:
case PKT_PUBLIC_KEY:
@@ -195,10 +196,10 @@ write_fake_data( IOBUF out, MPI a )
static int
do_comment( IOBUF out, int ctb, PKT_comment *rem )
{
- if( !opt.no_comment ) {
+ if( opt.sk_comments ) {
write_header(out, ctb, rem->len);
if( iobuf_write( out, rem->data, rem->len ) )
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
}
return 0;
}
@@ -206,19 +207,15 @@ do_comment( IOBUF out, int ctb, PKT_comment *rem )
static int
do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
{
- if( uid->photo ) {
- write_header(out, ctb, uid->photolen);
- uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */
- /* ... and it does only work when used with a temp iobuf */
- if( iobuf_write( out, uid->photo, uid->photolen ) )
- return GPGERR_WRITE_FILE;
+ if( uid->attrib_data ) {
+ write_header(out, ctb, uid->attrib_len);
+ if( iobuf_write( out, uid->attrib_data, uid->attrib_len ) )
+ return G10ERR_WRITE_FILE;
}
else {
write_header(out, ctb, uid->len);
- uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */
- /* ... and it does only work when used with a temp iobuf */
if( iobuf_write( out, uid->name, uid->len ) )
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
}
return 0;
}
@@ -252,7 +249,7 @@ do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 );
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
iobuf_close(a);
return rc;
@@ -263,7 +260,7 @@ do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
* Make a hash value from the public key certificate
*/
void
-hash_public_key( GCRY_MD_HD md, PKT_public_key *pk )
+hash_public_key( MD_HANDLE md, PKT_public_key *pk )
{
PACKET pkt;
int rc = 0;
@@ -283,7 +280,7 @@ hash_public_key( GCRY_MD_HD md, PKT_public_key *pk )
pkt.pkttype = PKT_PUBLIC_KEY;
pkt.pkt.public_key = pk;
if( (rc = build_packet( a, &pkt )) )
- log_fatal("build public_key for hashing failed: %s\n", gpg_errstr(rc));
+ log_fatal("build public_key for hashing failed: %s\n", g10_errstr(rc));
if( !(pk->version == 3 && pk->pubkey_algo == 16) ) {
/* skip the constructed header but don't do this for our very old
@@ -314,10 +311,10 @@ hash_public_key( GCRY_MD_HD md, PKT_public_key *pk )
}
}
/* hash a header */
- gcry_md_putc( md, 0x99 );
+ md_putc( md, 0x99 );
pktlen &= 0xffff; /* can't handle longer packets */
- gcry_md_putc( md, pktlen >> 8 );
- gcry_md_putc( md, pktlen & 0xff );
+ md_putc( md, pktlen >> 8 );
+ md_putc( md, pktlen & 0xff );
}
/* hash the packet body */
while( (c=iobuf_get(a)) != -1 ) {
@@ -328,7 +325,7 @@ hash_public_key( GCRY_MD_HD md, PKT_public_key *pk )
i=0;
}
#endif
- gcry_md_putc( md, c );
+ md_putc( md, c );
}
#if 0
putc('\n', fp);
@@ -343,43 +340,64 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
{
int rc = 0;
int i, nskey, npkey;
- IOBUF a = iobuf_temp();
+ IOBUF a = iobuf_temp(); /* build in a self-enlarging buffer */
+ /* Write the version number - if none is specified, use 3 */
if( !sk->version )
iobuf_put( a, 3 );
else
iobuf_put( a, sk->version );
write_32(a, sk->timestamp );
+
+ /* v3 needs the expiration time */
if( sk->version < 4 ) {
u16 ndays;
if( sk->expiredate )
ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
else
ndays = 0;
- write_16(a, 0 );
+ write_16(a, ndays);
}
+
iobuf_put(a, sk->pubkey_algo );
+
+ /* get number of secret and public parameters. They are held in
+ one array first the public ones, then the secret ones */
nskey = pubkey_get_nskey( sk->pubkey_algo );
npkey = pubkey_get_npkey( sk->pubkey_algo );
+
+ /* If we don't have any public parameters - which is the case if
+ we don't know the algorithm used - the parameters are stored as
+ one blob in a faked (opaque) MPI */
if( !npkey ) {
write_fake_data( a, sk->skey[0] );
goto leave;
}
assert( npkey < nskey );
+ /* Writing the public parameters is easy */
for(i=0; i < npkey; i++ )
mpi_write(a, sk->skey[i] );
+
+ /* build the header for protected (encrypted) secret parameters */
if( sk->is_protected ) {
if( is_RSA(sk->pubkey_algo) && sk->version < 4
&& !sk->protect.s2k.mode ) {
+ /* the simple rfc1991 (v3) way */
iobuf_put(a, sk->protect.algo );
iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
}
else {
- iobuf_put(a, 0xff );
+ /* OpenPGP protection according to rfc2440 */
+ iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
iobuf_put(a, sk->protect.algo );
if( sk->protect.s2k.mode >= 1000 ) {
- iobuf_put(a, 101 );
+ /* These modes are not possible in OpenPGP, we use them
+ to implement our extesnsions, 101 can ve views as a
+ private/experimental extension (this is not
+ specified in rfc2440 but the same scheme is used
+ for all other algorithm identifiers) */
+ iobuf_put(a, 101 );
iobuf_put(a, sk->protect.s2k.hash_algo );
iobuf_write(a, "GNU", 3 );
iobuf_put(a, sk->protect.s2k.mode - 1000 );
@@ -392,34 +410,41 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
|| sk->protect.s2k.mode == 3 )
iobuf_write(a, sk->protect.s2k.salt, 8 );
if( sk->protect.s2k.mode == 3 )
- iobuf_put(a, sk->protect.s2k.count );
+ iobuf_put(a, sk->protect.s2k.count );
+
+ /* For out special mode 1001 we do not need an IV */
if( sk->protect.s2k.mode != 1001 )
iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
}
}
else
iobuf_put(a, 0 );
+
if( sk->protect.s2k.mode == 1001 )
- ;
+ ; /* GnuPG extension - don't write a secret key at all */
else if( sk->is_protected && sk->version >= 4 ) {
+ /* The secret key is protected - write it out as it is */
byte *p;
- size_t n;
- assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
- p = gcry_mpi_get_opaque( sk->skey[i], &n );
- iobuf_write(a, p, (n+7)/8 );
+ assert( mpi_is_opaque( sk->skey[npkey] ) );
+ p = mpi_get_opaque( sk->skey[npkey], &i );
+ iobuf_write(a, p, i );
}
else {
+ /* v3 way - same code for protected and non- protected key */
for( ; i < nskey; i++ )
mpi_write(a, sk->skey[i] );
write_16(a, sk->csum );
}
leave:
+ /* Build the header of the packet - which we must do after writing all
+ the other stuff, so that we know the length of the packet */
write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes, 1 );
+ /* And finally write it out the real stream */
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
- iobuf_close(a);
+ iobuf_close(a); /* close the remporary buffer */
return rc;
}
@@ -448,7 +473,7 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
iobuf_close(a);
return rc;
@@ -482,7 +507,7 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
iobuf_close(a);
return rc;
@@ -511,12 +536,12 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
for(i=0; i < pt->namelen; i++ )
iobuf_put(out, pt->name[i] );
if( write_32(out, pt->timestamp ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
n = 0;
while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
if( iobuf_write(out, buf, nbytes) == -1 ) {
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
break;
}
n += nbytes;
@@ -539,7 +564,7 @@ do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed )
int rc = 0;
u32 n;
- n = ed->len ? (ed->len + 10) : 0;
+ n = ed->len ? (ed->len + ed->extralen) : 0;
write_header(out, ctb, n );
/* This is all. The caller has to write the real data */
@@ -555,7 +580,7 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
assert( ed->mdc_method );
- n = ed->len ? (ed->len + 10) : 0;
+ n = ed->len ? (ed->len + ed->extralen) : 0;
write_header(out, ctb, n );
iobuf_put(out, 1 ); /* version */
@@ -572,7 +597,7 @@ do_mdc( IOBUF out, PKT_mdc *mdc )
iobuf_put( out, 0xd3 ); /* packet ID and 1 byte length */
iobuf_put( out, 0x14 ); /* length = 20 */
if( iobuf_write( out, mdc->hash, sizeof(mdc->hash) ) )
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
return 0;
}
@@ -591,36 +616,36 @@ do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
}
-
/****************
- * Find a subpacket of type REQTYPE in BUFFER and a return a pointer
- * to the first byte of that subpacket data.
- * And return the length of the packet in RET_N and the number of
- * header bytes in RET_HLEN (length header and type byte).
+ * Delete all subpackets of type REQTYPE and return a bool whether a packet
+ * was deleted.
*/
-byte *
-find_subpkt( byte *buffer, sigsubpkttype_t reqtype,
- size_t *ret_hlen, size_t *ret_n )
+int
+delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
{
int buflen;
sigsubpkttype_t type;
- byte *bufstart;
+ byte *buffer, *bufstart;
size_t n;
+ size_t unused = 0;
+ int okay = 0;
- if( !buffer )
- return NULL;
- buflen = (*buffer << 8) | buffer[1];
- buffer += 2;
+ if( !area )
+ return 0;
+ buflen = area->len;
+ buffer = area->data;
for(;;) {
- if( !buflen )
- return NULL; /* end of packets; not found */
+ if( !buflen ) {
+ okay = 1;
+ break;
+ }
bufstart = buffer;
n = *buffer++; buflen--;
if( n == 255 ) {
if( buflen < 4 )
break;
n = (buffer[0] << 24) | (buffer[1] << 16)
- | (buffer[2] << 8) | buffer[3];
+ | (buffer[2] << 8) | buffer[3];
buffer += 4;
buflen -= 4;
}
@@ -633,137 +658,175 @@ find_subpkt( byte *buffer, sigsubpkttype_t reqtype,
}
if( buflen < n )
break;
+
type = *buffer & 0x7f;
if( type == reqtype ) {
buffer++;
+ buflen--;
n--;
if( n > buflen )
break;
- if( ret_hlen )
- *ret_hlen = buffer - bufstart;
- if( ret_n )
- *ret_n = n;
- return buffer;
+ buffer += n; /* point to next subpkt */
+ buflen -= n;
+ memmove (bufstart, buffer, buflen); /* shift */
+ unused += buffer - bufstart;
+ buffer = bufstart;
}
- buffer += n; buflen -=n;
+ else {
+ buffer += n; buflen -=n;
+ }
}
- log_error("find_subpkt: buffer shorter than subpacket\n");
- return NULL;
+ if (!okay)
+ log_error ("delete_subpkt: buffer shorter than subpacket\n");
+ assert (unused <= area->len);
+ area->len -= unused;
+ return !!unused;
}
/****************
- * Create or update a signature subpacket for SIG of TYPE.
- * This functions knows where to put the data (hashed or unhashed).
- * The function may move data from the unhased part to the hashed one.
- * Note: All pointers into sig->[un]hashed are not valid after a call
- * to this function. The data to but into the subpaket should be
- * in buffer with a length of buflen.
+ * Create or update a signature subpacket for SIG of TYPE. This
+ * functions knows where to put the data (hashed or unhashed). The
+ * function may move data from the unhashed part to the hashed one.
+ * Note: All pointers into sig->[un]hashed (e.g. returned by
+ * parse_sig_subpkt) are not valid after a call to this function. The
+ * data to put into the subpaket should be in a buffer with a length
+ * of buflen.
*/
void
-build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
+build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen )
{
- byte *data;
- size_t hlen, dlen, nlen;
- int found=0;
- int critical, hashed, realloced;
- size_t n, n0;
+ byte *p;
+ int critical, hashed;
+ subpktarea_t *oldarea, *newarea;
+ size_t nlen, n, n0;
critical = (type & SIGSUBPKT_FLAG_CRITICAL);
type &= ~SIGSUBPKT_FLAG_CRITICAL;
- if( type == SIGSUBPKT_NOTATION )
- ; /* we allow multiple packets */
- else if( (data = find_subpkt( sig->hashed_data, type, &hlen, &dlen )) )
- found = 1;
- else if( (data = find_subpkt( sig->unhashed_data, type, &hlen, &dlen )))
- found = 2;
+ /* Sanity check buffer sizes */
+ if(parse_one_sig_subpkt(buffer,buflen,type)<0)
+ BUG();
+
+ switch(type)
+ {
+ case SIGSUBPKT_NOTATION:
+ case SIGSUBPKT_POLICY:
+ case SIGSUBPKT_REV_KEY:
+ /* we do allow multiple subpackets */
+ break;
+
+ default:
+ /* we don't allow multiple subpackets */
+ delete_sig_subpkt(sig->hashed,type);
+ delete_sig_subpkt(sig->unhashed,type);
+ break;
+ }
+
+ /* Any special magic that needs to be done for this type so the
+ packet doesn't need to be reparsed? */
+ switch(type)
+ {
+ case SIGSUBPKT_NOTATION:
+ sig->flags.notation=1;
+ break;
+
+ case SIGSUBPKT_POLICY:
+ sig->flags.policy_url=1;
+ break;
+
+ case SIGSUBPKT_EXPORTABLE:
+ if(buffer[0])
+ sig->flags.exportable=1;
+ else
+ sig->flags.exportable=0;
+ break;
+
+ case SIGSUBPKT_REVOCABLE:
+ if(buffer[0])
+ sig->flags.revocable=1;
+ else
+ sig->flags.revocable=0;
+ break;
+
+ default:
+ break;
+ }
- if( found )
- log_bug("build_sig_packet: update nyi\n");
if( (buflen+1) >= 8384 )
- nlen = 5;
+ nlen = 5; /* write 5 byte length header */
else if( (buflen+1) >= 192 )
- nlen = 2;
+ nlen = 2; /* write 2 byte length header */
else
- nlen = 1;
+ nlen = 1; /* just a 1 byte length header */
switch( type ) {
- case SIGSUBPKT_SIG_CREATED:
- case SIGSUBPKT_PRIV_ADD_SIG:
- case SIGSUBPKT_PREF_SYM:
- case SIGSUBPKT_PREF_HASH:
- case SIGSUBPKT_PREF_COMPR:
- case SIGSUBPKT_KS_FLAGS:
- case SIGSUBPKT_KEY_EXPIRE:
- case SIGSUBPKT_NOTATION:
- case SIGSUBPKT_POLICY:
- case SIGSUBPKT_REVOC_REASON:
- case SIGSUBPKT_KEY_FLAGS:
- case SIGSUBPKT_FEATURES:
- hashed = 1; break;
- default: hashed = 0; break;
- }
-
- if( hashed ) {
- n0 = sig->hashed_data ? ((*sig->hashed_data << 8)
- | sig->hashed_data[1]) : 0;
- n = n0 + nlen + 1 + buflen; /* length, type, buffer */
- realloced = !!sig->hashed_data;
- data = sig->hashed_data ? gcry_xrealloc( sig->hashed_data, n+2 )
- : gcry_xmalloc( n+2 );
- }
- else {
- n0 = sig->unhashed_data ? ((*sig->unhashed_data << 8)
- | sig->unhashed_data[1]) : 0;
- n = n0 + nlen + 1 + buflen; /* length, type, buffer */
- realloced = !!sig->unhashed_data;
- data = sig->unhashed_data ? gcry_xrealloc( sig->unhashed_data, n+2 )
- : gcry_xmalloc( n+2 );
+ case SIGSUBPKT_ISSUER:
+ case SIGSUBPKT_PRIV_VERIFY_CACHE: /*(obsolete)*/
+ hashed = 0;
+ break;
+ default:
+ hashed = 1;
+ break;
}
if( critical )
type |= SIGSUBPKT_FLAG_CRITICAL;
- data[0] = (n >> 8) & 0xff;
- data[1] = n & 0xff;
- if( nlen == 5 ) {
- data[n0+2] = 255;
- data[n0+3] = (buflen+1) >> 24;
- data[n0+4] = (buflen+1) >> 16;
- data[n0+5] = (buflen+1) >> 8;
- data[n0+6] = (buflen+1);
- data[n0+7] = type;
- memcpy(data+n0+8, buffer, buflen );
+ oldarea = hashed? sig->hashed : sig->unhashed;
+
+ /* Calculate new size of the area and allocate */
+ n0 = oldarea? oldarea->len : 0;
+ n = n0 + nlen + 1 + buflen; /* length, type, buffer */
+ if (oldarea && n <= oldarea->size) { /* fits into the unused space */
+ newarea = oldarea;
+ /*log_debug ("updating area for type %d\n", type );*/
}
- else if( nlen == 2 ) {
- data[n0+2] = (buflen+1-192) / 256 + 192;
- data[n0+3] = (buflen+1-192) & 256;
- data[n0+4] = type;
- memcpy(data+n0+5, buffer, buflen );
+ else if (oldarea) {
+ newarea = m_realloc (oldarea, sizeof (*newarea) + n - 1);
+ newarea->size = n;
+ /*log_debug ("reallocating area for type %d\n", type );*/
}
else {
- data[n0+2] = buflen+1;
- data[n0+3] = type;
- memcpy(data+n0+4, buffer, buflen );
+ newarea = m_alloc (sizeof (*newarea) + n - 1);
+ newarea->size = n;
+ /*log_debug ("allocating area for type %d\n", type );*/
}
-
- if( hashed ) {
- if( !realloced )
- gcry_free(sig->hashed_data);
- sig->hashed_data = data;
+ newarea->len = n;
+
+ p = newarea->data + n0;
+ if (nlen == 5) {
+ *p++ = 255;
+ *p++ = (buflen+1) >> 24;
+ *p++ = (buflen+1) >> 16;
+ *p++ = (buflen+1) >> 8;
+ *p++ = (buflen+1);
+ *p++ = type;
+ memcpy (p, buffer, buflen);
+ }
+ else if (nlen == 2) {
+ *p++ = (buflen+1-192) / 256 + 192;
+ *p++ = (buflen+1-192) % 256;
+ *p++ = type;
+ memcpy (p, buffer, buflen);
}
else {
- if( !realloced )
- gcry_free(sig->unhashed_data);
- sig->unhashed_data = data;
+ *p++ = buflen+1;
+ *p++ = type;
+ memcpy (p, buffer, buflen);
}
+
+ if (hashed)
+ sig->hashed = newarea;
+ else
+ sig->unhashed = newarea;
}
/****************
* Put all the required stuff from SIG into subpackets of sig.
+ * Hmmm, should we delete those subpackets which are in a wrong area?
*/
void
build_sig_subpkt_from_sig( PKT_signature *sig )
@@ -789,8 +852,70 @@ build_sig_subpkt_from_sig( PKT_signature *sig )
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
build_sig_subpkt( sig, SIGSUBPKT_SIG_CREATED, buf, 4 );
+
+ if(sig->expiredate)
+ {
+ u = sig->expiredate-sig->timestamp;
+ buf[0] = (u >> 24) & 0xff;
+ buf[1] = (u >> 16) & 0xff;
+ buf[2] = (u >> 8) & 0xff;
+ buf[3] = u & 0xff;
+
+ /* Mark this CRITICAL, so if any implementation doesn't
+ understand sigs that can expire, it'll just disregard this
+ sig altogether. */
+
+ build_sig_subpkt( sig, SIGSUBPKT_SIG_EXPIRE | SIGSUBPKT_FLAG_CRITICAL,
+ buf, 4 );
+ }
}
+void
+build_attribute_subpkt(PKT_user_id *uid,byte type,
+ const void *buf,int buflen,
+ const void *header,int headerlen)
+{
+ byte *attrib;
+ int idx;
+
+ if(1+headerlen+buflen>8383)
+ idx=5;
+ else if(1+headerlen+buflen>191)
+ idx=2;
+ else
+ idx=1;
+
+ /* realloc uid->attrib_data to the right size */
+
+ uid->attrib_data=m_realloc(uid->attrib_data,
+ uid->attrib_len+idx+1+headerlen+buflen);
+
+ attrib=&uid->attrib_data[uid->attrib_len];
+
+ if(idx==5)
+ {
+ attrib[0]=255;
+ attrib[1]=(1+headerlen+buflen) >> 24;
+ attrib[2]=(1+headerlen+buflen) >> 16;
+ attrib[3]=(1+headerlen+buflen) >> 8;
+ attrib[4]=1+headerlen+buflen;
+ }
+ else if(idx==2)
+ {
+ attrib[0]=(1+headerlen+buflen-192) / 256 + 192;
+ attrib[1]=(1+headerlen+buflen-192) % 256;
+ }
+ else
+ attrib[0]=1+headerlen+buflen; /* Good luck finding a JPEG this small! */
+
+ attrib[idx++]=type;
+
+ /* Tack on our data at the end */
+
+ memcpy(&attrib[idx],header,headerlen);
+ memcpy(&attrib[idx+headerlen],buf,buflen);
+ uid->attrib_len+=idx+headerlen+buflen;
+}
static int
do_signature( IOBUF out, int ctb, PKT_signature *sig )
@@ -818,16 +943,14 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
/* timestamp and keyid must have been packed into the
* subpackets prior to the call of this function, because
* these subpackets are hashed */
- nn = sig->hashed_data?((sig->hashed_data[0]<<8)
- |sig->hashed_data[1]) :0;
+ nn = sig->hashed? sig->hashed->len : 0;
write_16(a, nn);
if( nn )
- iobuf_write( a, sig->hashed_data+2, nn );
- nn = sig->unhashed_data?((sig->unhashed_data[0]<<8)
- |sig->unhashed_data[1]) :0;
+ iobuf_write( a, sig->hashed->data, nn );
+ nn = sig->unhashed? sig->unhashed->len : 0;
write_16(a, nn);
if( nn )
- iobuf_write( a, sig->unhashed_data+2, nn );
+ iobuf_write( a, sig->unhashed->data, nn );
}
iobuf_put(a, sig->digest_start[0] );
iobuf_put(a, sig->digest_start[1] );
@@ -842,7 +965,7 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
else
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
iobuf_close(a);
return rc;
@@ -865,7 +988,7 @@ do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops )
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
iobuf_close(a);
return rc;
diff --git a/g10/cipher.c b/g10/cipher.c
index cad6ff664..2af8750c8 100644
--- a/g10/cipher.c
+++ b/g10/cipher.c
@@ -1,5 +1,5 @@
/* cipher.c - En-/De-ciphering filter
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,9 +25,9 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "errors.h"
#include "iobuf.h"
+#include "memory.h"
#include "util.h"
#include "filter.h"
#include "packet.h"
@@ -45,69 +45,69 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
PACKET pkt;
PKT_encrypted ed;
byte temp[18];
- unsigned int blocksize;
- unsigned int nprefix;
- int rc;
- int use_mdc = opt.force_mdc;
+ unsigned blocksize;
+ unsigned nprefix;
+ int use_mdc;
- blocksize = gcry_cipher_get_algo_blklen( cfx->dek->algo );
+ blocksize = cipher_get_blocksize( cfx->dek->algo );
if( blocksize < 8 || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
+
+ use_mdc = cfx->dek->use_mdc;
+
if( blocksize != 8 )
- use_mdc = 1; /* enable it for all modern ciphers */
- if( opt.rfc2440 )
+ use_mdc = 1; /* Hack: enable it for all modern ciphers */
+ /* Note: We should remove this hack as soon as a reasonable number of keys
+ are carrying the MDC flag. But always keep the hack for conventional
+ encryption */
+
+ if (opt.force_mdc)
+ use_mdc = 1;
+
+ if( opt.rfc2440 || opt.rfc1991 || opt.disable_mdc )
use_mdc = 0; /* override - rfc2440 does not know about MDC */
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
+ ed.extralen = blocksize+2;
ed.new_ctb = !ed.len && !opt.rfc1991;
if( use_mdc ) {
- ed.mdc_method = GCRY_MD_SHA1;
- cfx->mdc_hash = gcry_md_open( GCRY_MD_SHA1, 0 );
- if( !cfx->mdc_hash )
- BUG();
+ ed.mdc_method = DIGEST_ALGO_SHA1;
+ cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 );
if ( DBG_HASHING )
- gcry_md_start_debug( cfx->mdc_hash, "creatmdc" );
+ md_start_debug( cfx->mdc_hash, "creatmdc" );
+ }
+
+ {
+ char buf[20];
+
+ sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
+ write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
}
+
init_packet( &pkt );
pkt.pkttype = use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n");
nprefix = blocksize;
- gcry_randomize( temp, nprefix, GCRY_STRONG_RANDOM );
+ randomize_buffer( temp, nprefix, 1 );
temp[nprefix] = temp[nprefix-2];
temp[nprefix+1] = temp[nprefix-1];
print_cipher_algo_note( cfx->dek->algo );
- if( !(cfx->cipher_hd = gcry_cipher_open( cfx->dek->algo,
- GCRY_CIPHER_MODE_CFB,
- GCRY_CIPHER_SECURE
- | ((use_mdc || cfx->dek->algo >= 100) ?
- 0 : GCRY_CIPHER_ENABLE_SYNC)))
- ) {
- /* we should never get an error here cause we already checked, that
- * the algorithm is available. */
- BUG();
- }
-
-
+ cfx->cipher_hd = cipher_open( cfx->dek->algo,
+ use_mdc? CIPHER_MODE_CFB
+ : CIPHER_MODE_AUTO_CFB, 1 );
/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
- rc = gcry_cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
- if( !rc )
- rc = gcry_cipher_setiv( cfx->cipher_hd, NULL, 0 );
- if( rc )
- log_fatal("set key or IV failed: %s\n", gcry_strerror(rc) );
+ cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
+ cipher_setiv( cfx->cipher_hd, NULL, 0 );
/* log_hexdump( "prefix", temp, nprefix+2 ); */
- if( cfx->mdc_hash )
- gcry_md_write( cfx->mdc_hash, temp, nprefix+2 );
- rc = gcry_cipher_encrypt( cfx->cipher_hd, temp, nprefix+2, NULL, 0 );
- if( !rc )
- rc = gcry_cipher_sync( cfx->cipher_hd );
- if( rc )
- log_fatal("encrypt failed: %s\n", gcry_strerror(rc) );
+ if( cfx->mdc_hash ) /* hash the "IV" */
+ md_write( cfx->mdc_hash, temp, nprefix+2 );
+ cipher_encrypt( cfx->cipher_hd, temp, temp, nprefix+2);
+ cipher_sync( cfx->cipher_hd );
iobuf_write(a, temp, nprefix+2);
cfx->header=1;
-
}
@@ -129,46 +129,39 @@ cipher_filter( void *opaque, int control,
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
assert(a);
if( !cfx->header ) {
- write_status( STATUS_BEGIN_ENCRYPTION );
write_header( cfx, a );
}
if( cfx->mdc_hash )
- gcry_md_write( cfx->mdc_hash, buf, size );
- rc = gcry_cipher_encrypt( cfx->cipher_hd, buf, size, NULL, 0);
- if( rc )
- log_fatal("encrypt failed: %s\n", gcry_strerror(rc) );
+ md_write( cfx->mdc_hash, buf, size );
+ cipher_encrypt( cfx->cipher_hd, buf, buf, size);
if( iobuf_write( a, buf, size ) )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
}
else if( control == IOBUFCTRL_FREE ) {
if( cfx->mdc_hash ) {
byte *hash;
- int hashlen = gcry_md_get_algo_dlen( gcry_md_get_algo( cfx->mdc_hash ) );
+ int hashlen = md_digest_length( md_get_algo( cfx->mdc_hash ) );
byte temp[22];
assert( hashlen == 20 );
/* we must hash the prefix of the MDC packet here */
temp[0] = 0xd3;
temp[1] = 0x14;
- gcry_md_putc( cfx->mdc_hash, temp[0] );
- gcry_md_putc( cfx->mdc_hash, temp[1] );
+ md_putc( cfx->mdc_hash, temp[0] );
+ md_putc( cfx->mdc_hash, temp[1] );
- hash = gcry_md_read( cfx->mdc_hash, 0 );
+ md_final( cfx->mdc_hash );
+ hash = md_read( cfx->mdc_hash, 0 );
memcpy(temp+2, hash, 20);
- rc = gcry_cipher_encrypt( cfx->cipher_hd, temp, 22, NULL, 0 );
- if( rc )
- log_fatal("encrypt failed: %s\n", gcry_strerror(rc) );
- gcry_md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
+ cipher_encrypt( cfx->cipher_hd, temp, temp, 22 );
+ md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
if( iobuf_write( a, temp, 22 ) )
log_error("writing MDC packet failed\n" );
}
- gcry_cipher_close(cfx->cipher_hd);
- write_status( STATUS_END_ENCRYPTION );
+ cipher_close(cfx->cipher_hd);
}
else if( control == IOBUFCTRL_DESC ) {
*(char**)buf = "cipher_filter";
}
return rc;
}
-
-
diff --git a/g10/comment.c b/g10/comment.c
index b1732a29f..6d27e481b 100644
--- a/g10/comment.c
+++ b/g10/comment.c
@@ -1,5 +1,5 @@
/* comment.c - write comment stuff
- * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,7 +29,7 @@
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "keydb.h"
@@ -45,41 +45,59 @@ write_comment( IOBUF out, const char *s )
pkt.pkttype = PKT_COMMENT;
if( *s != '#' ) {
- pkt.pkt.comment = gcry_xmalloc( sizeof *pkt.pkt.comment + n );
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n );
pkt.pkt.comment->len = n+1;
*pkt.pkt.comment->data = '#';
strcpy(pkt.pkt.comment->data+1, s);
}
else {
- pkt.pkt.comment = gcry_xmalloc( sizeof *pkt.pkt.comment + n - 1 );
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
pkt.pkt.comment->len = n;
strcpy(pkt.pkt.comment->data, s);
}
if( (rc = build_packet( out, &pkt )) )
- log_error("build_packet(comment) failed: %s\n", gpg_errstr(rc) );
+ log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
free_packet( &pkt );
return rc;
}
KBNODE
-make_comment_node_from_buffer( const char *s, size_t n )
+make_comment_node( const char *s )
{
PACKET *pkt;
+ size_t n = strlen(s);
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_COMMENT;
- pkt->pkt.comment = gcry_xmalloc( sizeof *pkt->pkt.comment + n - 1 );
+ pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n - 1 );
pkt->pkt.comment->len = n;
strcpy(pkt->pkt.comment->data, s);
return new_kbnode( pkt );
}
+
KBNODE
-make_comment_node( const char *s )
+make_mpi_comment_node( const char *s, MPI a )
{
- return make_comment_node_from_buffer ( s, strlen (s) );
-}
+ PACKET *pkt;
+ byte *buf, *p, *pp;
+ unsigned n1, nb1;
+ size_t n = strlen(s);
+ nb1 = mpi_get_nbits( a );
+ p = buf = mpi_get_buffer( a, &n1, NULL );
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_COMMENT;
+ pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n + 2 + n1 );
+ pkt->pkt.comment->len = n+1+2+n1;
+ pp = pkt->pkt.comment->data;
+ memcpy(pp, s, n+1);
+ pp[n+1] = nb1 >> 8;
+ pp[n+2] = nb1 ;
+ memcpy(pp+n+3, p, n1 );
+ m_free(buf);
+ return new_kbnode( pkt );
+}
diff --git a/g10/compress.c b/g10/compress.c
index 2666e9051..6d85e0181 100644
--- a/g10/compress.c
+++ b/g10/compress.c
@@ -1,5 +1,5 @@
/* compress.c - compress filter
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -27,10 +27,11 @@
#include <errno.h>
#include <zlib.h>
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "packet.h"
#include "filter.h"
+#include "main.h"
#include "options.h"
@@ -63,7 +64,7 @@ init_compress( compress_filter_context_t *zfx, z_stream *zs )
}
zfx->outbufsize = 8192;
- zfx->outbuf = gcry_xmalloc( zfx->outbufsize );
+ zfx->outbuf = m_alloc( zfx->outbufsize );
}
static int
@@ -73,7 +74,11 @@ do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
unsigned n;
do {
+#ifndef __riscos__
zs->next_out = zfx->outbuf;
+#else /* __riscos__ */
+ zs->next_out = (Bytef *) zfx->outbuf;
+#endif /* __riscos__ */
zs->avail_out = zfx->outbufsize;
if( DBG_FILTER )
log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
@@ -96,7 +101,7 @@ do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
if( iobuf_write( a, zfx->outbuf, n ) ) {
log_debug("deflate: iobuf_write failed\n");
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
}
} while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
return 0;
@@ -121,7 +126,7 @@ init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
}
zfx->inbufsize = 2048;
- zfx->inbuf = gcry_xmalloc( zfx->inbufsize );
+ zfx->inbuf = m_alloc( zfx->inbufsize );
zs->avail_in = 0;
}
@@ -143,7 +148,11 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
if( zs->avail_in < zfx->inbufsize && refill ) {
n = zs->avail_in;
if( !n )
+#ifndef __riscos__
zs->next_in = zfx->inbuf;
+#else /* __riscos__ */
+ zs->next_in = (Bytef *) zfx->inbuf;
+#endif /* __riscos__ */
count = zfx->inbufsize - n;
nread = iobuf_read( a, zfx->inbuf + n, count );
if( nread == -1 ) nread = 0;
@@ -196,12 +205,16 @@ compress_filter( void *opaque, int control,
if( control == IOBUFCTRL_UNDERFLOW ) {
if( !zfx->status ) {
- zs = zfx->opaque = gcry_xcalloc( 1, sizeof *zs );
+ zs = zfx->opaque = m_alloc_clear( sizeof *zs );
init_uncompress( zfx, zs );
zfx->status = 1;
}
+#ifndef __riscos__
zs->next_out = buf;
+#else /* __riscos__ */
+ zs->next_out = (Bytef *) buf;
+#endif /* __riscos__ */
zs->avail_out = size;
zfx->outbufsize = size; /* needed only for calculation */
rc = do_uncompress( zfx, zs, a, ret_len );
@@ -212,7 +225,9 @@ compress_filter( void *opaque, int control,
PKT_compressed cd;
if( !zfx->algo )
- zfx->algo = opt.def_compress_algo;
+ zfx->algo = DEFAULT_COMPRESS_ALGO;
+ if( zfx->algo != 1 && zfx->algo != 2 )
+ BUG();
memset( &cd, 0, sizeof cd );
cd.len = 0;
cd.algorithm = zfx->algo;
@@ -221,37 +236,54 @@ compress_filter( void *opaque, int control,
pkt.pkt.compressed = &cd;
if( build_packet( a, &pkt ))
log_bug("build_packet(PKT_COMPRESSED) failed\n");
- zs = zfx->opaque = gcry_xcalloc( 1, sizeof *zs );
+ zs = zfx->opaque = m_alloc_clear( sizeof *zs );
init_compress( zfx, zs );
zfx->status = 2;
}
+#ifndef __riscos__
zs->next_in = buf;
+#else /* __riscos__ */
+ zs->next_in = (Bytef *) buf;
+#endif /* __riscos__ */
zs->avail_in = size;
rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
}
else if( control == IOBUFCTRL_FREE ) {
if( zfx->status == 1 ) {
inflateEnd(zs);
- gcry_free(zs);
+ m_free(zs);
zfx->opaque = NULL;
- gcry_free(zfx->outbuf); zfx->outbuf = NULL;
+ m_free(zfx->outbuf); zfx->outbuf = NULL;
}
else if( zfx->status == 2 ) {
+#ifndef __riscos__
zs->next_in = buf;
+#else /* __riscos__ */
+ zs->next_in = (Bytef *) buf;
+#endif /* __riscos__ */
zs->avail_in = 0;
do_compress( zfx, zs, Z_FINISH, a );
deflateEnd(zs);
- gcry_free(zs);
+ m_free(zs);
zfx->opaque = NULL;
- gcry_free(zfx->outbuf); zfx->outbuf = NULL;
+ m_free(zfx->outbuf); zfx->outbuf = NULL;
}
+ if (zfx->release)
+ zfx->release (zfx);
}
else if( control == IOBUFCTRL_DESC )
*(char**)buf = "compress_filter";
return rc;
}
+
+static void
+release_context (compress_filter_context_t *ctx)
+{
+ m_free (ctx);
+}
+
/****************
* Handle a compressed packet
*/
@@ -259,26 +291,19 @@ int
handle_compressed( void *procctx, PKT_compressed *cd,
int (*callback)(IOBUF, void *), void *passthru )
{
- compress_filter_context_t cfx;
+ compress_filter_context_t *cfx;
int rc;
- memset( &cfx, 0, sizeof cfx );
if( cd->algorithm < 1 || cd->algorithm > 2 )
- return GPGERR_COMPR_ALGO;
- cfx.algo = cd->algorithm;
-
- iobuf_push_filter( cd->buf, compress_filter, &cfx );
+ return G10ERR_COMPR_ALGO;
+ cfx = m_alloc_clear (sizeof *cfx);
+ cfx->algo = cd->algorithm;
+ cfx->release = release_context;
+ iobuf_push_filter( cd->buf, compress_filter, cfx );
if( callback )
rc = callback(cd->buf, passthru );
else
rc = proc_packets(procctx, cd->buf);
- #if 0
- iobuf_pop_filter( cd->buf, compress_filter, &cfx );
- if( cd->len )
- iobuf_set_limit( cd->buf, 0 ); /* disable the readlimit */
- else
- iobuf_clear_eof( cd->buf );
- #endif
cd->buf = NULL;
return rc;
}
diff --git a/g10/dearmor.c b/g10/dearmor.c
index 937961e7f..4ec8fa012 100644
--- a/g10/dearmor.c
+++ b/g10/dearmor.c
@@ -1,5 +1,5 @@
/* dearmor.c - Armor utility
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,9 +25,9 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "errors.h"
#include "iobuf.h"
+#include "memory.h"
#include "util.h"
#include "filter.h"
#include "packet.h"
@@ -52,7 +52,7 @@ dearmor_file( const char *fname )
if( !(inp = iobuf_open(fname)) ) {
log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
@@ -94,7 +94,7 @@ enarmor_file( const char *fname )
if( !(inp = iobuf_open(fname)) ) {
log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
diff --git a/g10/decrypt.c b/g10/decrypt.c
index 981275602..297ee3418 100644
--- a/g10/decrypt.c
+++ b/g10/decrypt.c
@@ -1,5 +1,5 @@
/* decrypt.c - verify signed data
- * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,14 +25,15 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
+#include "status.h"
#include "i18n.h"
@@ -57,7 +58,7 @@ decrypt_message( const char *filename )
fp = iobuf_open(filename);
if( !fp ) {
log_error(_("can't open `%s'\n"), print_fname_stdin(filename));
- return GPGERR_OPEN_FILE;
+ return G10ERR_OPEN_FILE;
}
if( !opt.no_armor ) {
@@ -78,5 +79,60 @@ decrypt_message( const char *filename )
return rc;
}
+void
+decrypt_messages(int nfiles, char **files)
+{
+ IOBUF fp;
+ armor_filter_context_t afx;
+ char *p, *output = NULL;
+ int rc = 0;
+
+ if (opt.outfile)
+ {
+ log_error(_("--output doesn't work for this command\n"));
+ return;
+
+ }
+
+ while (nfiles--)
+ {
+ print_file_status(STATUS_FILE_START, *files, 3);
+ output = make_outfile_name(*files);
+ if (!output)
+ continue;
+ fp = iobuf_open(*files);
+ if (!fp)
+ {
+ log_error(_("can't open `%s'\n"), print_fname_stdin(*files));
+ continue;
+ }
+ if (!opt.no_armor)
+ {
+ if (use_armor_filter(fp))
+ {
+ memset(&afx, 0, sizeof afx);
+ iobuf_push_filter(fp, armor_filter, &afx);
+ }
+ }
+ rc = proc_packets(NULL, fp);
+ iobuf_close(fp);
+ if (rc)
+ log_error("%s: decryption failed: %s\n", print_fname_stdin(*files),
+ g10_errstr(rc));
+ p = get_last_passphrase();
+ set_next_passphrase(p);
+ m_free (p);
+ files++;
+ m_free(output);
+ write_status( STATUS_FILE_DONE );
+ }
+ set_next_passphrase(NULL);
+}
+
+
+
+
+
+
diff --git a/g10/delkey.c b/g10/delkey.c
index f4bfd01e4..f9d882113 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -1,5 +1,5 @@
/* delkey.c - delete keys
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -31,7 +31,7 @@
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "trustdb.h"
@@ -43,34 +43,46 @@
/****************
* Delete a public or secret key from a keyring.
+ * r_sec_avail will be set if a secret key is available and the public
+ * key can't be deleted for that reason.
*/
-int
-delete_key( const char *username, int secret )
+static int
+do_delete_key( const char *username, int secret, int *r_sec_avail )
{
int rc = 0;
KBNODE keyblock = NULL;
KBNODE node;
- KBPOS kbpos;
+ KEYDB_HANDLE hd = keydb_new (secret);
PKT_public_key *pk = NULL;
PKT_secret_key *sk = NULL;
u32 keyid[2];
int okay=0;
int yes;
+ KEYDB_SEARCH_DESC desc;
+
+ *r_sec_avail = 0;
/* search the userid */
- rc = secret? find_secret_keyblock_byname( &keyblock, username )
- : find_keyblock_byname( &keyblock, username );
- if( rc ) {
- log_error(_("%s: user not found: %s\n"), username, gpg_errstr(rc) );
+ classify_user_id (username, &desc);
+ rc = desc.mode? keydb_search (hd, &desc, 1):G10ERR_INV_USER_ID;
+ if (rc) {
+ log_error (_("key `%s' not found: %s\n"), username, g10_errstr (rc));
write_status_text( STATUS_DELETE_PROBLEM, "1" );
goto leave;
}
+ /* read the keyblock */
+ rc = keydb_get_keyblock (hd, &keyblock );
+ if (rc) {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
/* get the keyid from the keyblock */
node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY );
if( !node ) {
log_error("Oops; key not found anymore!\n");
- rc = GPGERR_GENERAL;
+ rc = G10ERR_GENERAL;
goto leave;
}
@@ -83,15 +95,12 @@ delete_key( const char *username, int secret )
keyid_from_pk( pk, keyid );
rc = seckey_available( keyid );
if( !rc ) {
- log_error(_(
- "there is a secret key for this public key!\n"));
- log_info(_(
- "use option \"--delete-secret-key\" to delete it first.\n"));
- write_status_text( STATUS_DELETE_PROBLEM, "2" );
- rc = -1;
+ *r_sec_avail = 1;
+ rc = -1;
+ goto leave;
}
- else if( rc != GPGERR_NO_SECKEY ) {
- log_error("%s: get secret key: %s\n", username, gpg_errstr(rc) );
+ else if( rc != G10ERR_NO_SECKEY ) {
+ log_error("%s: get secret key: %s\n", username, g10_errstr(rc) );
}
else
rc = 0;
@@ -113,15 +122,15 @@ delete_key( const char *username, int secret )
tty_printf("sec %4u%c/%08lX %s ",
nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
- keyid[1], datestr_from_sk(sk) );
+ (ulong)keyid[1], datestr_from_sk(sk) );
else
tty_printf("pub %4u%c/%08lX %s ",
nbits_from_pk( pk ),
pubkey_letter( pk->pubkey_algo ),
- keyid[1], datestr_from_pk(pk) );
+ (ulong)keyid[1], datestr_from_pk(pk) );
p = get_user_id( keyid, &n );
tty_print_utf8_string( p, n );
- gcry_free(p);
+ m_free(p);
tty_printf("\n\n");
yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay"
@@ -142,16 +151,59 @@ delete_key( const char *username, int secret )
if( okay ) {
- #warning MUST FIX THIS!!!
- rc = delete_keyblock( &kbpos );
- if( rc ) {
- log_error("delete_keyblock failed: %s\n", gpg_errstr(rc) );
+ rc = keydb_delete_keyblock (hd);
+ if (rc) {
+ log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) );
goto leave;
}
+
+ /* Note that the ownertrust being cleared will trigger a
+ revalidation_mark(). This makes sense - only deleting keys
+ that have ownertrust set should trigger this. */
+
+ if (!secret && pk && clear_ownertrust (pk)) {
+ if (opt.verbose)
+ log_info (_("ownertrust information cleared\n"));
+ }
}
leave:
- release_kbnode( keyblock );
+ keydb_release (hd);
+ release_kbnode (keyblock);
return rc;
}
+/****************
+ * Delete a public or secret key from a keyring.
+ */
+int
+delete_keys( STRLIST names, int secret, int allow_both )
+{
+ int rc, avail;
+
+ for(;names;names=names->next) {
+ rc = do_delete_key (names->d, secret, &avail );
+ if ( rc && avail ) {
+ if ( allow_both ) {
+ rc = do_delete_key (names->d, 1, &avail );
+ if ( !rc )
+ rc = do_delete_key (names->d, 0, &avail );
+ }
+ else {
+ log_error(_(
+ "there is a secret key for public key \"%s\"!\n"),names->d);
+ log_info(_(
+ "use option \"--delete-secret-keys\" to delete it first.\n"));
+ write_status_text( STATUS_DELETE_PROBLEM, "2" );
+ return rc;
+ }
+ }
+
+ if(rc) {
+ log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) );
+ return rc;
+ }
+ }
+
+ return 0;
+}
diff --git a/g10/encode.c b/g10/encode.c
index f033c76ae..80a9039ec 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -1,5 +1,5 @@
/* encode.c - encode data
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -30,69 +30,18 @@
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "filter.h"
#include "trustdb.h"
#include "i18n.h"
+#include "status.h"
-
-static int encode_simple( const char *filename, int mode );
+static int encode_simple( const char *filename, int mode, int compat );
static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
-static int
-pk_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
-{
- GCRY_SEXP s_ciph, s_data, s_pkey;
- int rc;
-
- /* make a sexp from pkey */
- if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_pkey, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2] );
- }
- else
- return GPGERR_PUBKEY_ALGO;
-
- if ( rc )
- BUG ();
-
- /* put the data into a simple list */
- if ( gcry_sexp_build( &s_data, NULL, "%m", data ) )
- BUG ();
-
- /* pass it to libgcrypt */
- rc = gcry_pk_encrypt( &s_ciph, s_data, s_pkey );
- gcry_sexp_release( s_data );
- gcry_sexp_release( s_pkey );
-
- if( rc )
- ;
- else { /* add better error handling or make gnupg use S-Exp directly */
- GCRY_SEXP list = gcry_sexp_find_token( s_ciph, "a" , 0 );
- assert( list );
- resarr[0] = gcry_sexp_nth_mpi( list, 1, 0 );
- assert( resarr[0] );
- gcry_sexp_release ( list );
-
- list = gcry_sexp_find_token( s_ciph, "b" , 0 );
- assert( list );
- resarr[1] = gcry_sexp_nth_mpi( list, 1, 0 );
- assert( resarr[1] );
- gcry_sexp_release ( list );
- }
-
- gcry_sexp_release( s_ciph );
- return rc;
-}
-
/****************
* Encode FILENAME with only the symmetric cipher. Take input from
@@ -101,7 +50,11 @@ pk_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
int
encode_symmetric( const char *filename )
{
- return encode_simple( filename, 1 );
+ int compat = 1;
+
+ if ( opt.expert )
+ compat = 0; /* PGP knows how to handle this mode. */
+ return encode_simple( filename, 1, compat );
}
/****************
@@ -111,19 +64,49 @@ encode_symmetric( const char *filename )
int
encode_store( const char *filename )
{
- return encode_simple( filename, 0 );
+ return encode_simple( filename, 0, 1 );
}
-
+static void
+encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey )
+{
+ CIPHER_HANDLE hd;
+ DEK *c;
+ byte buf[33];
+
+ assert ( dek->keylen < 32 );
+
+ c = m_alloc_clear( sizeof *c );
+ c->keylen = dek->keylen;
+ c->algo = dek->algo;
+ make_session_key( c );
+ /*log_hexdump( "thekey", c->key, c->keylen );*/
+
+ buf[0] = c->algo;
+ memcpy( buf + 1, c->key, c->keylen );
+
+ hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
+ cipher_setkey( hd, dek->key, dek->keylen );
+ cipher_setiv( hd, NULL, 0 );
+ cipher_encrypt( hd, buf, buf, c->keylen + 1 );
+ cipher_close( hd );
+
+ memcpy( enckey, buf, c->keylen + 1 );
+ memset( buf, 0, sizeof buf ); /* burn key */
+ *ret_dek = c;
+}
static int
-encode_simple( const char *filename, int mode )
+encode_simple( const char *filename, int mode, int compat )
{
IOBUF inp, out;
PACKET pkt;
+ DEK *dek = NULL;
PKT_plaintext *pt = NULL;
STRING2KEY *s2k = NULL;
+ byte enckey[33];
int rc = 0;
+ int seskeylen = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t afx;
@@ -136,40 +119,62 @@ encode_simple( const char *filename, int mode )
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
+
+ if (opt.compress == -1 && is_file_compressed(filename, &rc))
+ {
+ if (opt.verbose)
+ log_info(_("`%s' already compressed\n"), filename);
+ do_compress = 0;
+ }
+ if (rc)
+ return rc;
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]",
strerror(errno) );
- return GPGERR_OPEN_FILE;
+ return G10ERR_OPEN_FILE;
}
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
+ /* Due the the fact that we use don't use an IV to encrypt the
+ session key we can't use the new mode with RFC1991 because
+ it has no S2K salt. RFC1991 always uses simple S2K. */
+ if ( opt.rfc1991 && !compat )
+ compat = 1;
+
cfx.dek = NULL;
if( mode ) {
- s2k = gcry_xcalloc( 1, sizeof *s2k );
+ s2k = m_alloc_clear( sizeof *s2k );
s2k->mode = opt.rfc1991? 0:opt.s2k_mode;
s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo
: opt.s2k_digest_algo;
cfx.dek = passphrase_to_dek( NULL, 0,
- opt.def_cipher_algo ? opt.def_cipher_algo
- : opt.s2k_cipher_algo , s2k, 2 );
+ opt.def_cipher_algo ? opt.def_cipher_algo
+ : opt.s2k_cipher_algo , s2k, 2, NULL );
if( !cfx.dek || !cfx.dek->keylen ) {
- rc = GPGERR_PASSPHRASE;
- gcry_free(cfx.dek);
- gcry_free(s2k);
+ rc = G10ERR_PASSPHRASE;
+ m_free(cfx.dek);
+ m_free(s2k);
iobuf_close(inp);
- log_error(_("error creating passphrase: %s\n"), gpg_errstr(rc) );
+ log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
return rc;
}
+ if ( !compat ) {
+ seskeylen = cipher_get_keylen( opt.def_cipher_algo ?
+ opt.def_cipher_algo:
+ opt.s2k_cipher_algo ) / 8;
+ encode_sesskey( cfx.dek, &dek, enckey );
+ m_free( cfx.dek ); cfx.dek = dek;
+ }
}
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
iobuf_cancel(inp);
- gcry_free(cfx.dek);
- gcry_free(s2k);
+ m_free(cfx.dek);
+ m_free(s2k);
return rc;
}
@@ -184,15 +189,19 @@ encode_simple( const char *filename, int mode )
}
#endif
if( s2k && !opt.rfc1991 ) {
- PKT_symkey_enc *enc = gcry_xcalloc( 1, sizeof *enc );
+ PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc + seskeylen + 1 );
enc->version = 4;
enc->cipher_algo = cfx.dek->algo;
enc->s2k = *s2k;
+ if ( !compat && seskeylen ) {
+ enc->seskeylen = seskeylen + 1; /* algo id */
+ memcpy( enc->seskey, enckey, seskeylen + 1 );
+ }
pkt.pkttype = PKT_SYMKEY_ENC;
pkt.pkt.symkey_enc = enc;
if( (rc = build_packet( out, &pkt )) )
- log_error("build symkey packet failed: %s\n", gpg_errstr(rc) );
- gcry_free(enc);
+ log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
+ m_free(enc);
}
if (!opt.no_literal) {
@@ -200,30 +209,36 @@ encode_simple( const char *filename, int mode )
if( filename || opt.set_filename ) {
char *s = make_basename( opt.set_filename ? opt.set_filename
: filename );
- pt = gcry_xmalloc( sizeof *pt + strlen(s) - 1 );
+ pt = m_alloc( sizeof *pt + strlen(s) - 1 );
pt->namelen = strlen(s);
memcpy(pt->name, s, pt->namelen );
- gcry_free(s);
+ m_free(s);
}
else { /* no filename */
- pt = gcry_xmalloc( sizeof *pt - 1 );
+ pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
}
}
- /* pgp5 has problems to decrypt symmetrically encrypted data from
- * GnuPG if the filelength is in the inner packet. It works
- * when only partial length headers are use. Until we have
- * tracked this problem down. We use this temporary fix
- * (fixme: remove the && !mode )
- */
- if( filename && !opt.textmode && !mode ) {
+ /* Note that PGP 5 has problems decrypting symmetrically encrypted
+ data if the file length is in the inner packet. It works when
+ only partial length headers are use. In the past, we always
+ used partial body length here, but since PGP 2, PGP 6, and PGP
+ 7 need the file length, and nobody should be using PGP 5
+ nowadays anyway, this is now set to the file length. Note also
+ that this only applies to the RFC-1991 style symmetric
+ messages, and not the RFC-2440 style. PGP 6 and 7 work with
+ either partial length or fixed length with the new style
+ messages. */
+
+ if( filename && !opt.textmode ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
/* we can't yet encode the length of very large files,
- * so we switch to partial length encoding in this case */
+ * so we switch to partial lengthn encoding in this case */
if ( filesize >= IOBUF_FILELENGTH_LIMIT )
filesize = 0;
+
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
@@ -239,7 +254,11 @@ encode_simple( const char *filename, int mode )
cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
}
else
- cfx.datalen = filesize && !do_compress ? filesize : 0;
+ {
+ cfx.datalen = filesize && !do_compress ? filesize : 0;
+ pkt.pkttype = 0;
+ pkt.pkt.generic = NULL;
+ }
/* register the cipher filter */
if( mode )
@@ -251,7 +270,7 @@ encode_simple( const char *filename, int mode )
/* do the work */
if (!opt.no_literal) {
if( (rc = build_packet( out, &pkt )) )
- log_error("build_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
}
else {
/* user requested not to create a literal packet,
@@ -260,8 +279,8 @@ encode_simple( const char *filename, int mode )
int bytes_copied;
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
- rc = GPGERR_WRITE_FILE;
- log_error("copying input to output failed: %s\n", gpg_errstr(rc) );
+ rc = G10ERR_WRITE_FILE;
+ log_error("copying input to output failed: %s\n", g10_errstr(rc) );
break;
}
memset(copy_buffer, 0, 4096); /* burn buffer */
@@ -271,13 +290,16 @@ encode_simple( const char *filename, int mode )
iobuf_close(inp);
if (rc)
iobuf_cancel(out);
- else
+ else {
iobuf_close(out); /* fixme: check returncode */
+ if (mode)
+ write_status( STATUS_END_ENCRYPTION );
+ }
if (pt)
pt->buf = NULL;
free_packet(&pkt);
- gcry_free(cfx.dek);
- gcry_free(s2k);
+ m_free(cfx.dek);
+ m_free(s2k);
return rc;
}
@@ -291,123 +313,203 @@ encode_crypt( const char *filename, STRLIST remusr )
IOBUF inp = NULL, out = NULL;
PACKET pkt;
PKT_plaintext *pt = NULL;
- int rc = 0;
+ int rc = 0, rc2 = 0;
u32 filesize;
+ cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
text_filter_context_t tfx;
- encrypt_filter_context_t efx;
- PK_LIST pk_list;
+ PK_LIST pk_list,work_list;
int do_compress = opt.compress && !opt.rfc1991;
+
+ memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
- memset( &efx, 0, sizeof efx);
init_packet(&pkt);
- if( (rc=build_pk_list( remusr, &pk_list, GCRY_PK_USAGE_ENCR)) )
+ if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
return rc;
+ if(opt.pgp2) {
+ for(work_list=pk_list; work_list; work_list=work_list->next)
+ if(!(is_RSA(work_list->pk->pubkey_algo) &&
+ nbits_from_pk(work_list->pk)<=2048))
+ {
+ log_info(_("you can only encrypt to RSA keys of 2048 bits or "
+ "less in --pgp2 mode\n"));
+ log_info(_("this message may not be usable by PGP 2.x\n"));
+ opt.pgp2=0;
+ break;
+ }
+ }
+
+ if (opt.compress == -1 && is_file_compressed(filename, &rc2))
+ {
+ if (opt.verbose)
+ log_info(_("`%s' already compressed\n"), filename);
+ do_compress = 0;
+ }
+ if (rc2)
+ {
+ rc = rc2;
+ goto leave;
+ }
+
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]",
strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
else if( opt.verbose )
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
- /* If the user selected textmode, push the text filter onto the input */
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
- /* Now we can create the outputfile */
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
goto leave;
- /* The first thing we have to push on the output stream
- * is the armor filter */
+
if( opt.armor )
iobuf_push_filter( out, armor_filter, &afx );
+ #ifdef ENABLE_COMMENT_PACKETS
+ else {
+ write_comment( out, "#created by GNUPG v" VERSION " ("
+ PRINTABLE_OS_NAME ")");
+ if( opt.comment_string )
+ write_comment( out, opt.comment_string );
+ }
+ #endif
+ /* create a session key */
+ cfx.dek = m_alloc_secure_clear (sizeof *cfx.dek);
+ if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
+ cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
+ /* The only way select_algo_from_prefs can fail here is when
+ mixing v3 and v4 keys, as v4 keys have an implicit
+ preference entry for 3DES, and the pk_list cannot be empty.
+ In this case, use 3DES anyway as it's the safest choice -
+ perhaps the v3 key is being used in an OpenPGP
+ implementation and we know that the implementation behind
+ any v4 key can handle 3DES. */
+ if( cfx.dek->algo == -1 ) {
+ cfx.dek->algo = CIPHER_ALGO_3DES;
+
+ if( opt.pgp2 ) {
+ log_info(_("unable to use the IDEA cipher for all of the keys "
+ "you are encrypting to.\n"));
+ log_info(_("this message may not be usable by PGP 2.x\n"));
+ opt.pgp2=0;
+ }
+ }
+ }
+ else {
+ if(!opt.expert &&
+ select_algo_from_prefs(pk_list,PREFTYPE_SYM,
+ opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
+ log_info(_("forcing symmetric cipher %s (%d) "
+ "violates recipient preferences\n"),
+ cipher_algo_to_string(opt.def_cipher_algo),
+ opt.def_cipher_algo);
+
+ cfx.dek->algo = opt.def_cipher_algo;
+ }
+ cfx.dek->use_mdc = select_mdc_from_pklist (pk_list);
- /* Prepare the plaintext packet */
- {
- if (!opt.no_literal) {
- if( filename || opt.set_filename ) {
- char *s = make_basename( opt.set_filename ?
- opt.set_filename : filename );
- pt = gcry_xmalloc( sizeof *pt + strlen(s) - 1 );
- pt->namelen = strlen(s);
- memcpy(pt->name, s, pt->namelen );
- gcry_free(s);
- }
- else { /* no filename */
- pt = gcry_xmalloc( sizeof *pt - 1 );
- pt->namelen = 0;
- }
- }
-
- if( filename && !opt.textmode ) {
- if( !(filesize = iobuf_get_filelength(inp)) )
- log_info(_("%s: WARNING: empty file\n"), filename );
- /* we can't yet encode the length of very large files,
- * so we switch to partial lengthn encoding in this case */
- if ( filesize >= IOBUF_FILELENGTH_LIMIT )
- filesize = 0;
- }
- else
- filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
-
- if (!opt.no_literal) {
- pt->timestamp = make_timestamp();
- pt->mode = opt.textmode ? 't' : 'b';
- pt->len = filesize;
- pt->new_ctb = !pt->len && !opt.rfc1991;
- pt->buf = inp;
- pkt.pkttype = PKT_PLAINTEXT;
- pkt.pkt.plaintext = pt;
- efx.cfx.datalen = filesize && !do_compress?
- calc_packet_length( &pkt ) : 0;
- }
- else
- efx.cfx.datalen = filesize && !do_compress ? filesize : 0;
- } /* end preparation of plaintext packet */
-
- /* push in the actual encryption filter */
- efx.pk_list = pk_list;
- iobuf_push_filter( out, encrypt_filter, &efx );
-
- /* register the compress filter (so that it is done before encryption) */
+ make_session_key( cfx.dek );
+ if( DBG_CIPHER )
+ log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
+
+ rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
+ if( rc )
+ goto leave;
+
+ if (!opt.no_literal) {
+ /* setup the inner packet */
+ if( filename || opt.set_filename ) {
+ char *s = make_basename( opt.set_filename ? opt.set_filename : filename );
+ pt = m_alloc( sizeof *pt + strlen(s) - 1 );
+ pt->namelen = strlen(s);
+ memcpy(pt->name, s, pt->namelen );
+ m_free(s);
+ }
+ else { /* no filename */
+ pt = m_alloc( sizeof *pt - 1 );
+ pt->namelen = 0;
+ }
+ }
+
+ if( filename && !opt.textmode ) {
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info(_("%s: WARNING: empty file\n"), filename );
+ /* we can't yet encode the length of very large files,
+ * so we switch to partial length encoding in this case */
+ if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+ filesize = 0;
+ }
+ else
+ filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
+
+ if (!opt.no_literal) {
+ pt->timestamp = make_timestamp();
+ pt->mode = opt.textmode ? 't' : 'b';
+ pt->len = filesize;
+ pt->new_ctb = !pt->len && !opt.rfc1991;
+ pt->buf = inp;
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
+ }
+ else
+ cfx.datalen = filesize && !do_compress ? filesize : 0;
+
+ /* register the cipher filter */
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* register the compress filter */
if( do_compress ) {
- int compr_algo = select_algo_from_prefs( pk_list, PREFTYPE_COMPR );
- if( !compr_algo )
- ; /* don't use compression */
- else {
- if( compr_algo == 1 )
- zfx.algo = 1; /* default is 2 */
+ int compr_algo = opt.def_compress_algo;
+
+ if(compr_algo==-1)
+ {
+ if((compr_algo=
+ select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
+ compr_algo=DEFAULT_COMPRESS_ALGO;
+ }
+ else if(!opt.expert &&
+ select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
+ compr_algo,NULL)!=compr_algo)
+ log_info(_("forcing compression algorithm %s (%d) "
+ "violates recipient preferences\n"),
+ compress_algo_to_string(compr_algo),compr_algo);
+
+ /* algo 0 means no compression */
+ if( compr_algo )
+ {
+ zfx.algo = compr_algo;
iobuf_push_filter( out, compress_filter, &zfx );
- }
+ }
}
/* do the work */
if (!opt.no_literal) {
if( (rc = build_packet( out, &pkt )) )
- log_error("build_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
}
else {
- /* user requested not to create a literal packet,
- * so we copy the plain data */
+ /* user requested not to create a literal packet, so we copy the plain data */
byte copy_buffer[4096];
int bytes_copied;
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
- rc = GPGERR_WRITE_FILE;
- log_error("copying input to output failed: %s\n", gpg_errstr(rc) );
+ rc = G10ERR_WRITE_FILE;
+ log_error("copying input to output failed: %s\n", g10_errstr(rc) );
break;
}
- memset(copy_buffer, 0, DIM(copy_buffer)); /* burn buffer */
+ memset(copy_buffer, 0, 4096); /* burn buffer */
}
/* finish the stuff */
@@ -415,13 +517,14 @@ encode_crypt( const char *filename, STRLIST remusr )
iobuf_close(inp);
if( rc )
iobuf_cancel(out);
- else
+ else {
iobuf_close(out); /* fixme: check returncode */
+ write_status( STATUS_END_ENCRYPTION );
+ }
if( pt )
pt->buf = NULL;
free_packet(&pkt);
- gcry_free(efx.cfx.dek); /* Hmmm, why does the encrypt filter does not
- * take care about this? */
+ m_free(cfx.dek);
release_pk_list( pk_list );
return rc;
}
@@ -430,7 +533,7 @@ encode_crypt( const char *filename, STRLIST remusr )
/****************
- * Filter to handle the entire public key encryption.
+ * Filter to do a complete public key encryption.
*/
int
encrypt_filter( void *opaque, int control,
@@ -445,16 +548,32 @@ encrypt_filter( void *opaque, int control,
}
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
if( !efx->header_okay ) {
- efx->cfx.dek = gcry_xmalloc_secure( sizeof *efx->cfx.dek );
+ efx->cfx.dek = m_alloc_secure_clear( sizeof *efx->cfx.dek );
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
efx->cfx.dek->algo =
- select_algo_from_prefs( efx->pk_list, PREFTYPE_SYM );
- if( efx->cfx.dek->algo == -1 )
+ select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,-1,NULL);
+ if( efx->cfx.dek->algo == -1 ) {
+ /* because 3DES is implicitly in the prefs, this can only
+ * happen if we do not have any public keys in the list */
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
+ }
+ }
+ else {
+ if(!opt.expert &&
+ select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,
+ opt.def_cipher_algo,
+ NULL)!=opt.def_cipher_algo)
+ log_info(_("forcing symmetric cipher %s (%d) "
+ "violates recipient preferences\n"),
+ cipher_algo_to_string(opt.def_cipher_algo),
+ opt.def_cipher_algo);
+
+ efx->cfx.dek->algo = opt.def_cipher_algo;
}
- else
- efx->cfx.dek->algo = opt.def_cipher_algo;
+
+ efx->cfx.dek->use_mdc = select_mdc_from_pklist (efx->pk_list);
+
make_session_key( efx->cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ",
@@ -497,7 +616,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
pk = pk_list->pk;
print_pubkey_algo_note( pk->pubkey_algo );
- enc = gcry_xcalloc( 1, sizeof *enc );
+ enc = m_alloc_clear( sizeof *enc );
enc->pubkey_algo = pk->pubkey_algo;
keyid_from_pk( pk, enc->keyid );
enc->throw_keyid = opt.throw_keyid;
@@ -517,17 +636,17 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
*/
frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
pk->pkey ) );
- rc = pk_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
- mpi_release( frame );
+ rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
+ mpi_free( frame );
if( rc )
- log_error("pubkey_encrypt failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
else {
if( opt.verbose ) {
char *ustr = get_user_id_string_native( enc->keyid );
log_info(_("%s/%s encrypted for: %s\n"),
- gcry_pk_algo_name(enc->pubkey_algo),
- gcry_cipher_algo_name(dek->algo), ustr );
- gcry_free(ustr);
+ pubkey_algo_to_string(enc->pubkey_algo),
+ cipher_algo_to_string(dek->algo), ustr );
+ m_free(ustr);
}
/* and write it */
init_packet(&pkt);
@@ -535,7 +654,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
pkt.pkt.pubkey_enc = enc;
rc = build_packet( out, &pkt );
if( rc )
- log_error("build_packet(pubkey_enc) failed: %s\n", gpg_errstr(rc));
+ log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
}
free_pubkey_enc(enc);
if( rc )
@@ -544,3 +663,47 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
return 0;
}
+void
+encode_crypt_files(int nfiles, char **files, STRLIST remusr)
+{
+ int rc = 0;
+
+ if (opt.outfile)
+ {
+ log_error(_("--output doesn't work for this command\n"));
+ return;
+ }
+
+ if (!nfiles)
+ {
+ char line[2048];
+ unsigned int lno = 0;
+ while ( fgets(line, DIM(line), stdin) )
+ {
+ lno++;
+ if (!*line || line[strlen(line)-1] != '\n')
+ {
+ log_error("input line %u too long or missing LF\n", lno);
+ return;
+ }
+ line[strlen(line)-1] = '\0';
+ print_file_status(STATUS_FILE_START, line, 2);
+ if ( (rc = encode_crypt(line, remusr)) )
+ log_error("%s: encryption failed: %s\n",
+ print_fname_stdin(line), g10_errstr(rc) );
+ write_status( STATUS_FILE_DONE );
+ }
+ }
+ else
+ {
+ while (nfiles--)
+ {
+ print_file_status(STATUS_FILE_START, *files, 2);
+ if ( (rc = encode_crypt(*files, remusr)) )
+ log_error("%s: encryption failed: %s\n",
+ print_fname_stdin(*files), g10_errstr(rc) );
+ write_status( STATUS_FILE_DONE );
+ files++;
+ }
+ }
+}
diff --git a/g10/encr-data.c b/g10/encr-data.c
index 17d43e9d6..c8a8c85db 100644
--- a/g10/encr-data.c
+++ b/g10/encr-data.c
@@ -1,5 +1,5 @@
/* encr-data.c - process an encrypted data packet
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,10 +23,11 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "packet.h"
+#include "mpi.h"
+#include "cipher.h"
#include "options.h"
#include "i18n.h"
@@ -37,8 +38,8 @@ static int decode_filter( void *opaque, int control, IOBUF a,
byte *buf, size_t *ret_len);
typedef struct {
- GCRY_CIPHER_HD cipher_hd;
- GCRY_MD_HD mdc_hash;
+ CIPHER_HANDLE cipher_hd;
+ MD_HANDLE mdc_hash;
char defer[20];
int defer_filled;
int eof_seen;
@@ -55,20 +56,21 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
byte *p;
int rc=0, c, i;
byte temp[32];
- unsigned int blocksize;
- unsigned int nprefix;
+ unsigned blocksize;
+ unsigned nprefix;
memset( &dfx, 0, sizeof dfx );
- if( gcry_cipher_test_algo( dek->algo ) ) {
- if( opt.verbose )
+ if( opt.verbose && !dek->algo_info_printed ) {
+ const char *s = cipher_algo_to_string( dek->algo );
+ if( s )
+ log_info(_("%s encrypted data\n"), s );
+ else
log_info(_("encrypted with unknown algorithm %d\n"), dek->algo );
- rc = GPGERR_CIPHER_ALGO;
- goto leave;
+ dek->algo_info_printed = 1;
}
- if( opt.verbose )
- log_info(_("%s encrypted data\n"), gcry_cipher_algo_name( dek->algo ) );
-
- blocksize = gcry_cipher_get_algo_blklen( dek->algo );
+ if( (rc=check_cipher_algo(dek->algo)) )
+ goto leave;
+ blocksize = cipher_get_blocksize(dek->algo);
if( !blocksize || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
nprefix = blocksize;
@@ -76,36 +78,28 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
BUG();
if( ed->mdc_method ) {
- dfx.mdc_hash = gcry_md_open( ed->mdc_method, 0 );
+ dfx.mdc_hash = md_open( ed->mdc_method, 0 );
if ( DBG_HASHING )
- gcry_md_start_debug(dfx.mdc_hash, "checkmdc");
+ md_start_debug(dfx.mdc_hash, "checkmdc");
}
- if( !(dfx.cipher_hd = gcry_cipher_open( dek->algo,
- GCRY_CIPHER_MODE_CFB,
- GCRY_CIPHER_SECURE
- | ((ed->mdc_method || dek->algo >= 100)?
- 0 : GCRY_CIPHER_ENABLE_SYNC) ))
- ) {
- /* we should never get an error here cause we already checked, that
- * the algorithm is available. What about a flag to let the function
- * die in this case? */
- BUG();
- }
-
-
+ dfx.cipher_hd = cipher_open( dek->algo,
+ ed->mdc_method? CIPHER_MODE_CFB
+ : CIPHER_MODE_AUTO_CFB, 1 );
/* log_hexdump( "thekey", dek->key, dek->keylen );*/
- rc = gcry_cipher_setkey( dfx.cipher_hd, dek->key, dek->keylen );
- if( rc == GCRYERR_WEAK_KEY ) {
+ rc = cipher_setkey( dfx.cipher_hd, dek->key, dek->keylen );
+ if( rc == G10ERR_WEAK_KEY )
log_info(_("WARNING: message was encrypted with "
"a weak key in the symmetric cipher.\n"));
- rc = 0;
- }
else if( rc ) {
- log_error("key setup failed: %s\n", gcry_strerror(rc) );
+ log_error("key setup failed: %s\n", g10_errstr(rc) );
goto leave;
}
+ if (!ed->buf) {
+ log_error(_("problem handling encrypted packet\n"));
+ goto leave;
+ }
- gcry_cipher_setiv( dfx.cipher_hd, NULL, 0 );
+ cipher_setiv( dfx.cipher_hd, NULL, 0 );
if( ed->len ) {
for(i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) {
@@ -122,17 +116,17 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
else
temp[i] = c;
}
- gcry_cipher_decrypt( dfx.cipher_hd, temp, nprefix+2, NULL, 0 );
- gcry_cipher_sync( dfx.cipher_hd );
+ cipher_decrypt( dfx.cipher_hd, temp, temp, nprefix+2);
+ cipher_sync( dfx.cipher_hd );
p = temp;
/* log_hexdump( "prefix", temp, nprefix+2 ); */
if( p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1] ) {
- rc = GPGERR_BAD_KEY;
+ rc = G10ERR_BAD_KEY;
goto leave;
}
if( dfx.mdc_hash )
- gcry_md_write( dfx.mdc_hash, temp, nprefix+2 );
+ md_write( dfx.mdc_hash, temp, nprefix+2 );
if( ed->mdc_method )
iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx );
@@ -142,21 +136,23 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
proc_packets( procctx, ed->buf );
ed->buf = NULL;
if( ed->mdc_method && dfx.eof_seen == 2 )
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
else if( ed->mdc_method ) { /* check the mdc */
- int datalen = gcry_md_get_algo_dlen( ed->mdc_method );
+ int datalen = md_digest_length( ed->mdc_method );
- gcry_cipher_decrypt( dfx.cipher_hd, dfx.defer, 20, NULL, 0);
+ cipher_decrypt( dfx.cipher_hd, dfx.defer, dfx.defer, 20);
+ md_final( dfx.mdc_hash );
if( datalen != 20
- || memcmp(gcry_md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) )
- rc = GPGERR_BAD_SIGN;
+ || memcmp(md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) )
+ rc = G10ERR_BAD_SIGN;
/*log_hexdump("MDC calculated:", md_read( dfx.mdc_hash, 0), datalen);*/
/*log_hexdump("MDC message :", dfx.defer, 20);*/
}
+
leave:
- gcry_cipher_close(dfx.cipher_hd);
- gcry_md_close( dfx.mdc_hash );
+ cipher_close(dfx.cipher_hd);
+ md_close( dfx.mdc_hash );
return rc;
}
@@ -222,8 +218,8 @@ mdc_decode_filter( void *opaque, int control, IOBUF a,
}
if( n ) {
- gcry_cipher_decrypt( dfx->cipher_hd, buf, n, NULL, 0);
- gcry_md_write( dfx->mdc_hash, buf, n );
+ cipher_decrypt( dfx->cipher_hd, buf, buf, n);
+ md_write( dfx->mdc_hash, buf, n );
}
else {
assert( dfx->eof_seen );
@@ -249,7 +245,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
n = iobuf_read( a, buf, size );
if( n == -1 ) n = 0;
if( n )
- gcry_cipher_decrypt( fc->cipher_hd, buf, n, NULL, 0 );
+ cipher_decrypt( fc->cipher_hd, buf, buf, n);
else
rc = -1; /* eof */
*ret_len = n;
diff --git a/g10/exec.c b/g10/exec.c
new file mode 100644
index 000000000..229c968bc
--- /dev/null
+++ b/g10/exec.c
@@ -0,0 +1,579 @@
+/* exec.c - generic call-a-program code
+ * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifndef EXEC_TEMPFILE_ONLY
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_DOSISH_SYSTEM
+#include <windows.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "options.h"
+#include "memory.h"
+#include "i18n.h"
+#include "iobuf.h"
+#include "util.h"
+#include "exec.h"
+
+#ifdef NO_EXEC
+int exec_write(struct exec_info **info,const char *program,
+ const char *args_in,const char *name,int writeonly,int binary)
+{
+ log_error(_("no remote program execution supported\n"));
+ return G10ERR_GENERAL;
+}
+
+int exec_read(struct exec_info *info) { return G10ERR_GENERAL; }
+int exec_finish(struct exec_info *info) { return G10ERR_GENERAL; }
+
+#else /* ! NO_EXEC */
+
+#ifndef HAVE_MKDTEMP
+char *mkdtemp(char *template);
+#endif
+
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+/* This is a nicer system() for windows that waits for programs to
+ return before returning control to the caller. I hate helpful
+ computers. */
+static int win_system(const char *command)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ char *string;
+
+ /* We must use a copy of the command as CreateProcess modifies this
+ argument. */
+ string=m_strdup(command);
+
+ memset(&pi,0,sizeof(pi));
+ memset(&si,0,sizeof(si));
+ si.cb=sizeof(si);
+
+ if(!CreateProcess(NULL,string,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
+ return -1;
+
+ /* Wait for the child to exit */
+ WaitForSingleObject(pi.hProcess,INFINITE);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ m_free(string);
+
+ return 0;
+}
+#endif
+
+/* Makes a temp directory and filenames */
+static int make_tempdir(struct exec_info *info)
+{
+ char *tmp=opt.temp_dir,*namein=info->name,*nameout;
+
+ if(!namein)
+ namein=info->binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
+
+ nameout=info->binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
+
+ /* Make up the temp dir and files in case we need them */
+
+ if(tmp==NULL)
+ {
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ tmp=m_alloc(256);
+ if(GetTempPath(256,tmp)==0)
+ strcpy(tmp,"c:\\windows\\temp");
+ else
+ {
+ int len=strlen(tmp);
+
+ /* GetTempPath may return with \ on the end */
+ while(len>0 && tmp[len-1]=='\\')
+ {
+ tmp[len-1]='\0';
+ len--;
+ }
+ }
+#else /* More unixish systems */
+ tmp=getenv("TMPDIR");
+ if(tmp==NULL)
+ {
+ tmp=getenv("TMP");
+ if(tmp==NULL)
+ {
+#ifdef __riscos__
+ tmp="<Wimp$ScrapDir>.GnuPG";
+ mkdir(tmp,0700); /* Error checks occur later on */
+#else
+ tmp="/tmp";
+#endif
+ }
+ }
+#endif
+ }
+
+ info->tempdir=m_alloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
+
+ sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
+
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ m_free(tmp);
+#endif
+
+ if(mkdtemp(info->tempdir)==NULL)
+ log_error(_("%s: can't create directory: %s\n"),
+ info->tempdir,strerror(errno));
+ else
+ {
+ info->madedir=1;
+
+ info->tempfile_in=m_alloc(strlen(info->tempdir)+
+ strlen(DIRSEP_S)+strlen(namein)+1);
+ sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
+
+ if(!info->writeonly)
+ {
+ info->tempfile_out=m_alloc(strlen(info->tempdir)+
+ strlen(DIRSEP_S)+strlen(nameout)+1);
+ sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
+ }
+ }
+
+ return info->madedir?0:G10ERR_GENERAL;
+}
+
+/* Expands %i and %o in the args to the full temp files within the
+ temp directory. */
+static int expand_args(struct exec_info *info,const char *args_in)
+{
+ const char *ch=args_in;
+ int size,len;
+
+ info->use_temp_files=0;
+ info->keep_temp_files=0;
+
+ if(DBG_EXTPROG)
+ log_debug("expanding string \"%s\"\n",args_in);
+
+ size=100;
+ info->command=m_alloc(size);
+ len=0;
+ info->command[0]='\0';
+
+ while(*ch!='\0')
+ {
+ if(*ch=='%')
+ {
+ char *append=NULL;
+
+ ch++;
+
+ switch(*ch)
+ {
+ case 'O':
+ info->keep_temp_files=1;
+ /* fall through */
+
+ case 'o': /* out */
+ if(!info->madedir)
+ {
+ if(make_tempdir(info))
+ goto fail;
+ }
+ append=info->tempfile_out;
+ info->use_temp_files=1;
+ break;
+
+ case 'I':
+ info->keep_temp_files=1;
+ /* fall through */
+
+ case 'i': /* in */
+ if(!info->madedir)
+ {
+ if(make_tempdir(info))
+ goto fail;
+ }
+ append=info->tempfile_in;
+ info->use_temp_files=1;
+ break;
+
+ case '%':
+ append="%";
+ break;
+ }
+
+ if(append)
+ {
+ while(strlen(append)+len>size-1)
+ {
+ size+=100;
+ info->command=m_realloc(info->command,size);
+ }
+
+ strcat(info->command,append);
+ len+=strlen(append);
+ }
+ }
+ else
+ {
+ if(len==size-1) /* leave room for the \0 */
+ {
+ size+=100;
+ info->command=m_realloc(info->command,size);
+ }
+
+ info->command[len++]=*ch;
+ info->command[len]='\0';
+ }
+
+ ch++;
+ }
+
+ if(DBG_EXTPROG)
+ log_debug("args expanded to \"%s\", use %d, keep %d\n",
+ info->command,info->use_temp_files,info->keep_temp_files);
+
+ return 0;
+
+ fail:
+
+ m_free(info->command);
+ info->command=NULL;
+
+ return G10ERR_GENERAL;
+}
+
+/* Either handles the tempfile creation, or the fork/exec. If it
+ returns ok, then info->tochild is a FILE * that can be written to.
+ The rules are: if there are no args, then it's a fork/exec/pipe.
+ If there are args, but no tempfiles, then it's a fork/exec/pipe via
+ shell -c. If there are tempfiles, then it's a system. */
+
+int exec_write(struct exec_info **info,const char *program,
+ const char *args_in,const char *name,int writeonly,int binary)
+{
+ int ret=G10ERR_GENERAL;
+
+ if(opt.exec_disable && !opt.no_perm_warn)
+ {
+ log_info(_("external program calls are disabled due to unsafe "
+ "options file permissions\n"));
+
+ return ret;
+ }
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+ /* There should be no way to get to this spot while still carrying
+ setuid privs. Just in case, bomb out if we are. */
+ if(getuid()!=geteuid())
+ BUG();
+#endif
+
+ if(program==NULL && args_in==NULL)
+ BUG();
+
+ *info=m_alloc_clear(sizeof(struct exec_info));
+
+ if(name)
+ (*info)->name=m_strdup(name);
+ (*info)->binary=binary;
+ (*info)->writeonly=writeonly;
+
+ /* Expand the args, if any */
+ if(args_in && expand_args(*info,args_in))
+ goto fail;
+
+#ifdef EXEC_TEMPFILE_ONLY
+ if(!(*info)->use_temp_files)
+ {
+ log_error(_("this platform requires temp files when calling external "
+ "programs\n"));
+ goto fail;
+ }
+
+#else /* !EXEC_TEMPFILE_ONLY */
+
+ /* If there are no args, or there are args, but no temp files, we
+ can use fork/exec/pipe */
+ if(args_in==NULL || (*info)->use_temp_files==0)
+ {
+ int to[2],from[2];
+
+ if(pipe(to)==-1)
+ goto fail;
+
+ if(pipe(from)==-1)
+ {
+ close(to[0]);
+ close(to[1]);
+ goto fail;
+ }
+
+ if(((*info)->child=fork())==-1)
+ {
+ close(to[0]);
+ close(to[1]);
+ close(from[0]);
+ close(from[1]);
+ goto fail;
+ }
+
+ if((*info)->child==0)
+ {
+ char *shell=getenv("SHELL");
+
+ if(shell==NULL)
+ shell="/bin/sh";
+
+ /* I'm the child */
+
+ /* If the program isn't going to respond back, they get to
+ keep their stdout/stderr */
+ if(!(*info)->writeonly)
+ {
+ /* implied close of STDERR */
+ if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
+ _exit(1);
+
+ /* implied close of STDOUT */
+ close(from[0]);
+ if(dup2(from[1],STDOUT_FILENO)==-1)
+ _exit(1);
+ }
+
+ /* implied close of STDIN */
+ close(to[1]);
+ if(dup2(to[0],STDIN_FILENO)==-1)
+ _exit(1);
+
+ if(args_in==NULL)
+ {
+ if(DBG_EXTPROG)
+ log_debug("execlp: %s\n",program);
+
+ execlp(program,program,NULL);
+ }
+ else
+ {
+ if(DBG_EXTPROG)
+ log_debug("execlp: %s -c %s\n",shell,(*info)->command);
+
+ execlp(shell,shell,"-c",(*info)->command,NULL);
+ }
+
+ /* If we get this far the exec failed. Clean up and return. */
+
+ log_error(_("unable to execute %s \"%s\": %s\n"),
+ args_in==NULL?"program":"shell",
+ args_in==NULL?program:shell,
+ strerror(errno));
+
+ /* This mimics the POSIX sh behavior - 127 means "not found"
+ from the shell. */
+ if(errno==ENOENT)
+ _exit(127);
+
+ _exit(1);
+ }
+
+ /* I'm the parent */
+
+ close(to[0]);
+
+ (*info)->tochild=fdopen(to[1],binary?"wb":"w");
+ if((*info)->tochild==NULL)
+ {
+ close(to[1]);
+ ret=G10ERR_WRITE_FILE;
+ goto fail;
+ }
+
+ close(from[1]);
+
+ (*info)->fromchild=iobuf_fdopen(from[0],"r");
+ if((*info)->fromchild==NULL)
+ {
+ close(from[0]);
+ ret=G10ERR_READ_FILE;
+ goto fail;
+ }
+
+ /* fd iobufs are cached?! */
+ iobuf_ioctl((*info)->fromchild,3,1,NULL);
+
+ return 0;
+ }
+#endif /* !EXEC_TEMPFILE_ONLY */
+
+ if(DBG_EXTPROG)
+ log_debug("using temp file \"%s\"\n",(*info)->tempfile_in);
+
+ /* It's not fork/exec/pipe, so create a temp file */
+ (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
+ if((*info)->tochild==NULL)
+ {
+ log_error(_("%s: can't create: %s\n"),
+ (*info)->tempfile_in,strerror(errno));
+ ret=G10ERR_WRITE_FILE;
+ goto fail;
+ }
+
+ ret=0;
+
+ fail:
+ return ret;
+}
+
+int exec_read(struct exec_info *info)
+{
+ int ret=G10ERR_GENERAL;
+
+ fclose(info->tochild);
+ info->tochild=NULL;
+
+ if(info->use_temp_files)
+ {
+ if(DBG_EXTPROG)
+ log_debug("system() command is %s\n",info->command);
+
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ info->progreturn=win_system(info->command);
+#else
+ info->progreturn=system(info->command);
+#endif
+
+ if(info->progreturn==-1)
+ {
+ log_error(_("system error while calling external program: %s\n"),
+ strerror(errno));
+ info->progreturn=127;
+ goto fail;
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if(WIFEXITED(info->progreturn))
+ info->progreturn=WEXITSTATUS(info->progreturn);
+ else
+ {
+ log_error(_("unnatural exit of external program\n"));
+ info->progreturn=127;
+ goto fail;
+ }
+#else
+ /* If we don't have the macros, do the best we can. */
+ info->progreturn = (info->progreturn & 0xff00) >> 8;
+#endif
+
+ /* 127 is the magic value returned from system() to indicate
+ that the shell could not be executed, or from /bin/sh to
+ indicate that the program could not be executed. */
+
+ if(info->progreturn==127)
+ {
+ log_error(_("unable to execute external program\n"));
+ goto fail;
+ }
+
+ if(!info->writeonly)
+ {
+ info->fromchild=iobuf_open(info->tempfile_out);
+ if(info->fromchild==NULL)
+ {
+ log_error(_("unable to read external program response: %s\n"),
+ strerror(errno));
+ ret=G10ERR_READ_FILE;
+ goto fail;
+ }
+
+ /* Do not cache this iobuf on close */
+ iobuf_ioctl(info->fromchild,3,1,NULL);
+ }
+ }
+
+ ret=0;
+
+ fail:
+ return ret;
+}
+
+int exec_finish(struct exec_info *info)
+{
+ int ret=info->progreturn;
+
+ if(info->fromchild)
+ iobuf_close(info->fromchild);
+
+ if(info->tochild)
+ fclose(info->tochild);
+
+#ifndef EXEC_TEMPFILE_ONLY
+ if(info->child>0)
+ {
+ if(waitpid(info->child,&info->progreturn,0)!=0 &&
+ WIFEXITED(info->progreturn))
+ ret=WEXITSTATUS(info->progreturn);
+ else
+ {
+ log_error(_("unnatural exit of external program\n"));
+ ret=127;
+ }
+ }
+#endif
+
+ if(info->madedir && !info->keep_temp_files)
+ {
+ if(info->tempfile_in)
+ {
+ if(unlink(info->tempfile_in)==-1)
+ log_info(_("Warning: unable to remove tempfile (%s) \"%s\": %s\n"),
+ "in",info->tempfile_in,strerror(errno));
+ }
+
+ if(info->tempfile_out)
+ {
+ if(unlink(info->tempfile_out)==-1)
+ log_info(_("Warning: unable to remove tempfile (%s) \"%s\": %s\n"),
+ "out",info->tempfile_out,strerror(errno));
+ }
+
+ if(rmdir(info->tempdir)==-1)
+ log_info(_("Warning: unable to remove temp directory \"%s\": %s\n"),
+ info->tempdir,strerror(errno));
+ }
+
+ m_free(info->command);
+ m_free(info->name);
+ m_free(info->tempdir);
+ m_free(info->tempfile_in);
+ m_free(info->tempfile_out);
+ m_free(info);
+
+ return ret;
+}
+#endif /* ! NO_EXEC */
diff --git a/g10/exec.h b/g10/exec.h
new file mode 100644
index 000000000..2e0be460b
--- /dev/null
+++ b/g10/exec.h
@@ -0,0 +1,22 @@
+#ifndef _EXEC_H_
+#define _EXEC_H_
+
+#include <unistd.h>
+#include <stdio.h>
+#include "iobuf.h"
+
+struct exec_info
+{
+ int progreturn,binary,writeonly,madedir,use_temp_files,keep_temp_files;
+ pid_t child;
+ FILE *tochild;
+ IOBUF fromchild;
+ char *command,*name,*tempdir,*tempfile_in,*tempfile_out;
+};
+
+int exec_write(struct exec_info **info,const char *program,
+ const char *args_in,const char *name,int writeonly,int binary);
+int exec_read(struct exec_info *info);
+int exec_finish(struct exec_info *info);
+
+#endif /* !_EXEC_H_ */
diff --git a/g10/export.c b/g10/export.c
index 9a9cd9859..47d06e651 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -1,5 +1,5 @@
/* export.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,11 +25,11 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "i18n.h"
@@ -83,8 +83,10 @@ do_export( STRLIST users, int secret, int onlyrfc )
IOBUF out = NULL;
int any, rc;
armor_filter_context_t afx;
+ compress_filter_context_t zfx;
memset( &afx, 0, sizeof afx);
+ memset( &zfx, 0, sizeof zfx);
rc = open_outfile( NULL, 0, &out );
if( rc )
@@ -94,6 +96,8 @@ do_export( STRLIST users, int secret, int onlyrfc )
afx.what = secret?5:1;
iobuf_push_filter( out, armor_filter, &afx );
}
+ if( opt.compress_keys && opt.compress )
+ iobuf_push_filter( out, compress_filter, &zfx );
rc = do_export_stream( out, users, secret, onlyrfc, &any );
if( rc || !any )
@@ -108,54 +112,58 @@ static int
do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
{
int rc = 0;
- compress_filter_context_t zfx;
PACKET pkt;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
- KBPOS kbpos;
+ int ndesc;
+ KEYDB_SEARCH_DESC *desc = NULL;
+ KEYDB_HANDLE kdbhd;
STRLIST sl;
- int all = !users;
*any = 0;
- memset( &zfx, 0, sizeof zfx);
init_packet( &pkt );
+ kdbhd = keydb_new (secret);
- if( opt.compress_keys && opt.compress )
- iobuf_push_filter( out, compress_filter, &zfx );
+ if (!users) {
+ ndesc = 1;
+ desc = m_alloc_clear ( ndesc * sizeof *desc);
+ desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
+ }
+ else {
+ for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
+ ;
+ desc = m_alloc ( ndesc * sizeof *desc);
+
+ for (ndesc=0, sl=users; sl; sl = sl->next) {
+ if (classify_user_id (sl->d, desc+ndesc))
+ ndesc++;
+ else
+ log_error (_("key `%s' not found: %s\n"),
+ sl->d, g10_errstr (G10ERR_INV_USER_ID));
+ }
- if( all ) {
- rc = enum_keyblocks_begin( &kbpos, secret );
- if( rc ) {
- if( rc != -1 )
- log_error("enum_keyblocks_begin failed: %s\n", gpg_errstr(rc));
- goto leave;
- }
- all = 2;
+ /* it would be nice to see which of the given users did
+ actually match one in the keyring. To implement this we
+ need to have a found flag for each entry in desc and to set
+ this we must check all those entries after a match to mark
+ all matched one - currently we stop at the first match. To
+ do this we need an extra flag to enable this feature so */
}
- /* use the correct sequence. strlist_last,prev do work correctly with
- * NULL pointers :-) */
- for( sl=strlist_last(users); sl || all ; sl=strlist_prev( users, sl )) {
- if( all ) { /* get the next user */
- rc = enum_keyblocks_next( kbpos, 1, &keyblock );
- if( rc == -1 ) /* EOF */
- break;
- if( rc ) {
- log_error("enum_keyblocks_next failed: %s\n", gpg_errstr(rc));
- break;
- }
- }
- else {
- /* search the userid */
- rc = secret? find_secret_keyblock_byname( &keyblock, sl->d )
- : find_keyblock_byname( &keyblock, sl->d );
- if( rc ) {
- log_error(_("%s: user not found: %s\n"), sl->d, gpg_errstr(rc));
- rc = 0;
- continue;
- }
- }
+ while (!(rc = keydb_search (kdbhd, desc, ndesc))) {
+ int sha1_warned=0;
+ u32 sk_keyid[2];
+
+ if (!users)
+ desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
+
+ /* read the keyblock */
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
+ if( rc ) {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
/* do not export keys which are incompatible with rfc2440 */
if( onlyrfc && (node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) {
@@ -167,15 +175,29 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
}
}
- /* we can't apply GNU mode 1001 on an unprotected key */
- if( secret == 2
- && (node = find_kbnode( keyblock, PKT_SECRET_KEY ))
- && !node->pkt->pkt.secret_key->is_protected )
- {
- log_info(_("key %08lX: not protected - skipped\n"),
- (ulong)keyid_from_sk( node->pkt->pkt.secret_key, NULL) );
- continue;
- }
+ node=find_kbnode( keyblock, PKT_SECRET_KEY );
+ if(node)
+ {
+ PKT_secret_key *sk=node->pkt->pkt.secret_key;
+
+ keyid_from_sk(sk,sk_keyid);
+
+ /* we can't apply GNU mode 1001 on an unprotected key */
+ if( secret == 2 && !sk->is_protected )
+ {
+ log_info(_("key %08lX: not protected - skipped\n"),
+ (ulong)sk_keyid[1]);
+ continue;
+ }
+
+ /* no v3 keys with GNU mode 1001 */
+ if( secret == 2 && sk->version == 3 )
+ {
+ log_info(_("key %08lX: PGP 2.x style key - skipped\n"),
+ (ulong)sk_keyid[1]);
+ continue;
+ }
+ }
/* and write it */
for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
@@ -183,13 +205,30 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
* secret keyring */
if( !secret && node->pkt->pkttype == PKT_COMMENT )
continue;
- /* do not export packets which are marked as not exportable */
+ /* make sure that ring_trust packets never get exported */
+ if (node->pkt->pkttype == PKT_RING_TRUST)
+ continue;
+
if( node->pkt->pkttype == PKT_SIGNATURE ) {
- const char *p;
- p = parse_sig_subpkt2( node->pkt->pkt.signature,
- SIGSUBPKT_EXPORTABLE, NULL );
- if( p && !*p )
- continue; /* not exportable */
+ /* do not export packets which are marked as not exportable */
+ if( !node->pkt->pkt.signature->flags.exportable )
+ continue; /* not exportable */
+
+ /* do not export packets with a "sensitive" revocation
+ key. This will need revisiting when we start
+ supporting creating revocation keys and not just
+ reading them. */
+ if( node->pkt->pkt.signature->revkey ) {
+ int i;
+
+ for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
+ if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
+ continue;
+ }
+
+ /* delete our verification cache */
+ delete_sig_subpkt (node->pkt->pkt.signature->unhashed,
+ SIGSUBPKT_PRIV_VERIFY_CACHE);
}
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
@@ -202,13 +241,28 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
}
else {
+ /* Warn the user if the secret key or any of the secret
+ subkeys are protected with SHA1 and we have
+ simple_sk_checksum set. */
+ if(!sha1_warned && opt.simple_sk_checksum &&
+ (node->pkt->pkttype==PKT_SECRET_KEY ||
+ node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
+ node->pkt->pkt.secret_key->protect.sha1chk)
+ {
+ /* I hope this warning doesn't confuse people. */
+ log_info("Warning: secret key %08lX does not have a "
+ "simple SK checksum\n",(ulong)sk_keyid[1]);
+
+ sha1_warned=1;
+ }
+
rc = build_packet( out, node->pkt );
}
if( rc ) {
log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- rc = GPGERR_WRITE_FILE;
+ node->pkt->pkttype, g10_errstr(rc) );
+ rc = G10ERR_WRITE_FILE;
goto leave;
}
}
@@ -218,8 +272,8 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
rc = 0;
leave:
- if( all == 2 )
- enum_keyblocks_end( kbpos );
+ m_free(desc);
+ keydb_release (kdbhd);
release_kbnode( keyblock );
if( !*any )
log_info(_("WARNING: nothing exported\n"));
diff --git a/g10/filter.h b/g10/filter.h
index a29d2aa29..b7a99e6bc 100644
--- a/g10/filter.h
+++ b/g10/filter.h
@@ -1,5 +1,5 @@
/* filter.h
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -17,18 +17,15 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_FILTER_H
-#define GPG_FILTER_H
-
-#include <gcrypt.h>
-
-#include "basicdefs.h"
-#include "iobuf.h"
+#ifndef G10_FILTER_H
+#define G10_FILTER_H
+#include "types.h"
+#include "cipher.h"
typedef struct {
- GCRY_MD_HD md; /* catch all */
- GCRY_MD_HD md2; /* if we want to calculate an alternate hash */
+ MD_HANDLE md; /* catch all */
+ MD_HANDLE md2; /* if we want to calculate an alternate hash */
size_t maxbuf_size;
} md_filter_context_t;
@@ -67,8 +64,11 @@ typedef struct {
int pending_lf; /* used together with faked */
} armor_filter_context_t;
+struct unarmor_pump_s;
+typedef struct unarmor_pump_s *UnarmorPump;
-typedef struct {
+
+struct compress_filter_context_s {
int status;
void *opaque; /* (used for z_stream) */
byte *inbuf;
@@ -77,26 +77,22 @@ typedef struct {
unsigned outbufsize;
int algo; /* compress algo */
int algo1hack;
-} compress_filter_context_t;
+ void (*release)(struct compress_filter_context_s*);
+};
+typedef struct compress_filter_context_s compress_filter_context_t;
typedef struct {
DEK *dek;
u32 datalen;
- GCRY_CIPHER_HD cipher_hd;
+ CIPHER_HANDLE cipher_hd;
int header;
- GCRY_MD_HD mdc_hash;
+ MD_HANDLE mdc_hash;
byte enchash[20];
int create_mdc; /* flag will be set by the cipher filter */
} cipher_filter_context_t;
-typedef struct {
- int header_okay;
- PK_LIST pk_list;
- cipher_filter_context_t cfx;
-} encrypt_filter_context_t;
-
typedef struct {
byte *buffer; /* malloced buffer */
@@ -106,12 +102,14 @@ typedef struct {
int truncated; /* number of truncated lines */
int not_dash_escaped;
int escape_from;
- GCRY_MD_HD md;
+ MD_HANDLE md;
int pending_lf;
int pending_esc;
} text_filter_context_t;
+/* encrypt_filter_context_t defined in main.h */
+
/*-- mdfilter.c --*/
int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
void free_md_filter_context( md_filter_context_t *mfx );
@@ -120,6 +118,9 @@ void free_md_filter_context( md_filter_context_t *mfx );
int use_armor_filter( IOBUF a );
int armor_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
+UnarmorPump unarmor_pump_new (void);
+void unarmor_pump_release (UnarmorPump x);
+int unarmor_pump (UnarmorPump x, int c);
/*-- compress.c --*/
int compress_filter( void *opaque, int control,
@@ -132,9 +133,9 @@ int cipher_filter( void *opaque, int control,
/*-- textfilter.c --*/
int text_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
-int copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md,
+int copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
int escape_dash, int escape_from, int pgp2mode );
-#endif /*GPG_FILTER_H*/
+#endif /*G10_FILTER_H*/
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 2cc4e25e9..e760999be 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -1,5 +1,5 @@
/* free-packet.c - cleanup stuff for packets
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,17 +24,18 @@
#include <string.h>
#include <assert.h>
-#include <gcrypt.h>
#include "packet.h"
#include "iobuf.h"
+#include "mpi.h"
#include "util.h"
+#include "cipher.h"
+#include "memory.h"
#include "options.h"
-#include "main.h"
void
free_symkey_enc( PKT_symkey_enc *enc )
{
- gcry_free(enc);
+ m_free(enc);
}
void
@@ -43,24 +44,27 @@ free_pubkey_enc( PKT_pubkey_enc *enc )
int n, i;
n = pubkey_get_nenc( enc->pubkey_algo );
if( !n )
- mpi_release(enc->data[0]);
+ mpi_free(enc->data[0]);
for(i=0; i < n; i++ )
- mpi_release( enc->data[i] );
- gcry_free(enc);
+ mpi_free( enc->data[i] );
+ m_free(enc);
}
void
free_seckey_enc( PKT_signature *sig )
{
- int n, i;
- n = pubkey_get_nsig( sig->pubkey_algo );
- if( !n )
- mpi_release(sig->data[0]);
- for(i=0; i < n; i++ )
- mpi_release( sig->data[i] );
- gcry_free(sig->hashed_data);
- gcry_free(sig->unhashed_data);
- gcry_free(sig);
+ int n, i;
+
+ n = pubkey_get_nsig( sig->pubkey_algo );
+ if( !n )
+ mpi_free(sig->data[0]);
+ for(i=0; i < n; i++ )
+ mpi_free( sig->data[i] );
+
+ m_free(sig->revkey);
+ m_free(sig->hashed);
+ m_free(sig->unhashed);
+ m_free(sig);
}
@@ -71,15 +75,28 @@ release_public_key_parts( PKT_public_key *pk )
int n, i;
n = pubkey_get_npkey( pk->pubkey_algo );
if( !n )
- mpi_release(pk->pkey[0]);
+ mpi_free(pk->pkey[0]);
for(i=0; i < n; i++ ) {
- mpi_release( pk->pkey[i] );
+ mpi_free( pk->pkey[i] );
pk->pkey[i] = NULL;
}
+ if (pk->prefs) {
+ m_free (pk->prefs);
+ pk->prefs = NULL;
+ }
if( pk->namehash ) {
- gcry_free(pk->namehash);
+ m_free(pk->namehash);
pk->namehash = NULL;
}
+ if (pk->user_id) {
+ free_user_id (pk->user_id);
+ pk->user_id = NULL;
+ }
+ if (pk->revkey) {
+ m_free(pk->revkey);
+ pk->revkey=NULL;
+ pk->numrevkeys=0;
+ }
}
@@ -87,42 +104,60 @@ void
free_public_key( PKT_public_key *pk )
{
release_public_key_parts( pk );
- gcry_free(pk);
+ m_free(pk);
}
-static void *
-cp_data_block( byte *s )
+static subpktarea_t *
+cp_subpktarea (subpktarea_t *s )
{
- byte *d;
- u16 len;
+ subpktarea_t *d;
if( !s )
return NULL;
- len = (s[0] << 8) | s[1];
- d = gcry_xmalloc( len+2 );
- memcpy(d, s, len+2);
+ d = m_alloc (sizeof (*d) + s->size - 1 );
+ d->size = s->size;
+ d->len = s->len;
+ memcpy (d->data, s->data, s->len);
return d;
}
+/*
+ * Return a copy of the preferences
+ */
+prefitem_t *
+copy_prefs (const prefitem_t *prefs)
+{
+ size_t n;
+ prefitem_t *new;
+
+ if (!prefs)
+ return NULL;
+
+ for (n=0; prefs[n].type; n++)
+ ;
+ new = m_alloc ( sizeof (*new) * (n+1));
+ for (n=0; prefs[n].type; n++) {
+ new[n].type = prefs[n].type;
+ new[n].value = prefs[n].value;
+ }
+ new[n].type = PREFTYPE_NONE;
+ new[n].value = 0;
+
+ return new;
+}
+
PKT_public_key *
-copy_public_key_new_namehash( PKT_public_key *d, PKT_public_key *s,
- const byte *namehash )
+copy_public_key ( PKT_public_key *d, PKT_public_key *s)
{
int n, i;
if( !d )
- d = gcry_xmalloc(sizeof *d);
+ d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
- if( namehash ) {
- d->namehash = gcry_xmalloc( 20 );
- memcpy(d->namehash, namehash, 20 );
- }
- else if( s->namehash ) {
- d->namehash = gcry_xmalloc( 20 );
- memcpy(d->namehash, s->namehash, 20 );
- }
+ d->user_id = scopy_user_id (s->user_id);
+ d->prefs = copy_prefs (s->prefs);
n = pubkey_get_npkey( s->pubkey_algo );
if( !n )
d->pkey[0] = mpi_copy(s->pkey[0]);
@@ -130,16 +165,17 @@ copy_public_key_new_namehash( PKT_public_key *d, PKT_public_key *s,
for(i=0; i < n; i++ )
d->pkey[i] = mpi_copy( s->pkey[i] );
}
+ if( !s->revkey && s->numrevkeys )
+ BUG();
+ if( s->numrevkeys ) {
+ d->revkey = m_alloc(sizeof(struct revocation_key)*s->numrevkeys);
+ memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
+ }
+ else
+ d->revkey = NULL;
return d;
}
-PKT_public_key *
-copy_public_key( PKT_public_key *d, PKT_public_key *s )
-{
- return copy_public_key_new_namehash( d, s, NULL );
-}
-
-
/****************
* Replace all common parts of a sk by the one from the public key.
* This is a hack and a better solution will be to just store the real secret
@@ -151,7 +187,6 @@ copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
sk->expiredate = pk->expiredate;
sk->pubkey_algo = pk->pubkey_algo;
sk->pubkey_usage= pk->pubkey_usage;
- sk->created = pk->created;
sk->req_usage = pk->req_usage;
sk->req_algo = pk->req_algo;
sk->has_expired = pk->has_expired;
@@ -163,15 +198,13 @@ copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
sk->keyid[1] = pk->keyid[1];
}
-
-
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
int n, i;
if( !d )
- d = gcry_xmalloc(sizeof *d);
+ d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nsig( s->pubkey_algo );
if( !n )
@@ -180,19 +213,27 @@ copy_signature( PKT_signature *d, PKT_signature *s )
for(i=0; i < n; i++ )
d->data[i] = mpi_copy( s->data[i] );
}
- d->hashed_data = cp_data_block(s->hashed_data);
- d->unhashed_data = cp_data_block(s->unhashed_data);
+ d->hashed = cp_subpktarea (s->hashed);
+ d->unhashed = cp_subpktarea (s->unhashed);
+ if(s->numrevkeys)
+ {
+ d->revkey=NULL;
+ d->numrevkeys=0;
+ parse_revkeys(d);
+ }
return d;
}
+/*
+ * shallow copy of the user ID
+ */
PKT_user_id *
-copy_user_id( PKT_user_id *d, PKT_user_id *s )
+scopy_user_id (PKT_user_id *s)
{
- if( !d )
- d = gcry_xmalloc(sizeof *d + s->len - 1 );
- memcpy( d, s, sizeof *d + s->len - 1 );
- return d;
+ if (s)
+ s->ref++;
+ return s;
}
@@ -204,9 +245,9 @@ release_secret_key_parts( PKT_secret_key *sk )
n = pubkey_get_nskey( sk->pubkey_algo );
if( !n )
- mpi_release(sk->skey[0]);
+ mpi_free(sk->skey[0]);
for(i=0; i < n; i++ ) {
- mpi_release( sk->skey[i] );
+ mpi_free( sk->skey[i] );
sk->skey[i] = NULL;
}
}
@@ -215,7 +256,7 @@ void
free_secret_key( PKT_secret_key *sk )
{
release_secret_key_parts( sk );
- gcry_free(sk);
+ m_free(sk);
}
PKT_secret_key *
@@ -224,7 +265,7 @@ copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
int n, i;
if( !d )
- d = gcry_xmalloc(sizeof *d);
+ d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nskey( s->pubkey_algo );
if( !n )
@@ -239,15 +280,32 @@ copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
void
free_comment( PKT_comment *rem )
{
- gcry_free(rem);
+ m_free(rem);
}
void
-free_user_id( PKT_user_id *uid )
+free_attributes(PKT_user_id *uid)
{
- if( uid->photo )
- gcry_free( uid->photo );
- gcry_free(uid);
+ m_free(uid->attribs);
+ m_free(uid->attrib_data);
+
+ uid->attribs=NULL;
+ uid->attrib_data=NULL;
+ uid->attrib_len=0;
+}
+
+void
+free_user_id (PKT_user_id *uid)
+{
+ assert (uid->ref > 0);
+ if (--uid->ref)
+ return;
+
+ free_attributes(uid);
+
+ if (uid->prefs)
+ m_free (uid->prefs);
+ m_free (uid);
}
void
@@ -259,7 +317,7 @@ free_compressed( PKT_compressed *zd )
while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
;
}
- gcry_free(zd);
+ m_free(zd);
}
void
@@ -280,7 +338,7 @@ free_encrypted( PKT_encrypted *ed )
}
}
}
- gcry_free(ed);
+ m_free(ed);
}
@@ -302,7 +360,7 @@ free_plaintext( PKT_plaintext *pt )
}
}
}
- gcry_free(pt);
+ m_free(pt);
}
/****************
@@ -345,13 +403,14 @@ free_packet( PACKET *pkt )
free_compressed( pkt->pkt.compressed);
break;
case PKT_ENCRYPTED:
+ case PKT_ENCRYPTED_MDC:
free_encrypted( pkt->pkt.encrypted );
break;
case PKT_PLAINTEXT:
free_plaintext( pkt->pkt.plaintext );
break;
default:
- gcry_free( pkt->pkt.generic );
+ m_free( pkt->pkt.generic );
break;
}
pkt->pkt.generic = NULL;
@@ -460,23 +519,29 @@ cmp_signatures( PKT_signature *a, PKT_signature *b )
}
-
/****************
* Returns: true if the user ids do not match
*/
int
cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
{
- int res;
+ int res=1;
+
+ if( a == b )
+ return 0;
+
+ if( a->attrib_data && b->attrib_data )
+ {
+ res = a->attrib_len - b->attrib_len;
+ if( !res )
+ res = memcmp( a->attrib_data, b->attrib_data, a->attrib_len );
+ }
+ else if( !a->attrib_data && !b->attrib_data )
+ {
+ res = a->len - b->len;
+ if( !res )
+ res = memcmp( a->name, b->name, a->len );
+ }
- res = a->len - b->len;
- if( !res )
- res = memcmp( a->name, b->name, a->len );
return res;
}
-
-
-
-
-
-
diff --git a/g10/gpg.c b/g10/g10.c
index 6faeb0721..b8cae1b1c 100644
--- a/g10/gpg.c
+++ b/g10/g10.c
@@ -1,5 +1,5 @@
-/* gpg.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* g10.c - The GnuPG utility (main for gpg)
+ * Copyright (C) 1998,1999,2000,2001,2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,22 +29,23 @@
#include <fcntl.h> /* for setmode() */
#endif
-
-#include <gcrypt.h>
+#define INCLUDED_BY_MAIN_MODULE 1
#include "packet.h"
#include "iobuf.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "options.h"
#include "keydb.h"
#include "trustdb.h"
+#include "mpi.h"
+#include "cipher.h"
#include "filter.h"
#include "ttyio.h"
#include "i18n.h"
#include "status.h"
-#include "gnupg-defs.h"
-#include "hkp.h"
-
+#include "g10defs.h"
+#include "keyserver-internal.h"
enum cmd_and_opt_values { aNull = 0,
oArmor = 'a',
@@ -52,6 +53,7 @@ enum cmd_and_opt_values { aNull = 0,
aSym = 'c',
aDecrypt = 'd',
aEncr = 'e',
+ aEncrFiles,
oInteractive = 'i',
oKOption = 'k',
oDryRun = 'n',
@@ -65,16 +67,25 @@ enum cmd_and_opt_values { aNull = 0,
oCompress = 'z',
oNotation = 'N',
oBatch = 500,
+ oSigNotation,
+ oCertNotation,
+ oShowNotation,
+ oNoShowNotation,
+ aDecryptFiles,
aClearsign,
aStore,
aKeygen,
aSignEncr,
+ aSignSym,
aSignKey,
aLSignKey,
+ aNRSignKey,
+ aNRLSignKey,
aListPackets,
aEditKey,
- aDeleteKey,
- aDeleteSecretKey,
+ aDeleteKeys,
+ aDeleteSecretKeys,
+ aDeleteSecretAndPublicKeys,
aKMode,
aKModeC,
aImport,
@@ -86,16 +97,17 @@ enum cmd_and_opt_values { aNull = 0,
aListSecretKeys,
aSendKeys,
aRecvKeys,
+ aSearchKeys,
aExport,
aExportAll,
aExportSecret,
aExportSecretSub,
aCheckKeys,
aGenRevoke,
+ aDesigRevoke,
aPrimegen,
aPrintMD,
aPrintMDs,
- aPrintHMAC,
aCheckTrustDB,
aUpdateTrustDB,
aFixTrustDB,
@@ -106,14 +118,25 @@ enum cmd_and_opt_values { aNull = 0,
aDeArmor,
aEnArmor,
aGenRandom,
+ aPipeMode,
+ aRebuildKeydbCaches,
+ aRefreshKeys,
oTextmode,
+ oExpert,
+ oNoExpert,
+ oAskSigExpire,
+ oNoAskSigExpire,
+ oAskCertExpire,
+ oNoAskCertExpire,
oFingerprint,
oWithFingerprint,
oAnswerYes,
oAnswerNo,
+ oDefCertCheckLevel,
oKeyring,
oSecretKeyring,
+ oShowKeyring,
oDefaultKey,
oDefRecipient,
oDefRecipientSelf,
@@ -122,7 +145,15 @@ enum cmd_and_opt_values { aNull = 0,
oDebug,
oDebugAll,
oStatusFD,
- oNoComment,
+#ifdef __riscos__
+ oStatusFile,
+#endif /* __riscos__ */
+ oAttributeFD,
+#ifdef __riscos__
+ oAttributeFile,
+#endif /* __riscos__ */
+ oSKComments,
+ oNoSKComments,
oNoVersion,
oEmitVersion,
oCompletesNeeded,
@@ -131,14 +162,29 @@ enum cmd_and_opt_values { aNull = 0,
oLoadExtension,
oRFC1991,
oOpenPGP,
+ oPGP2,
+ oNoPGP2,
+ oPGP6,
+ oNoPGP6,
+ oPGP7,
+ oNoPGP7,
oCipherAlgo,
oDigestAlgo,
+ oCertDigestAlgo,
oCompressAlgo,
oPasswdFD,
+#ifdef __riscos__
+ oPasswdFile,
+#endif /* __riscos__ */
oCommandFD,
+#ifdef __riscos__
+ oCommandFile,
+#endif /* __riscos__ */
+ oQuickRandom,
oNoVerbose,
oTrustDBName,
oNoSecmemWarn,
+ oNoPermissionWarn,
oNoArmor,
oNoDefKeyring,
oNoGreeting,
@@ -152,47 +198,100 @@ enum cmd_and_opt_values { aNull = 0,
oCompressKeys,
oCompressSigs,
oAlwaysTrust,
+ oEmuChecksumBug,
oRunAsShmCP,
oSetFilename,
+ oForYourEyesOnly,
+ oNoForYourEyesOnly,
oSetPolicyURL,
+ oSigPolicyURL,
+ oCertPolicyURL,
+ oShowPolicyURL,
+ oNoShowPolicyURL,
oUseEmbeddedFilename,
oComment,
oDefaultComment,
oThrowKeyid,
+ oShowPhotos,
+ oNoShowPhotos,
+ oPhotoViewer,
oForceV3Sigs,
+ oNoForceV3Sigs,
+ oForceV4Certs,
+ oNoForceV4Certs,
oForceMDC,
+ oNoForceMDC,
+ oDisableMDC,
+ oNoDisableMDC,
oS2KMode,
oS2KDigest,
oS2KCipher,
+ oSimpleSKChecksum,
oCharset,
oNotDashEscaped,
oEscapeFrom,
+ oNoEscapeFrom,
oLockOnce,
oLockMultiple,
oLockNever,
oKeyServer,
+ oKeyServerOptions,
+ oTempDir,
+ oExecPath,
oEncryptTo,
oNoEncryptTo,
oLoggerFD,
+#ifdef __riscos__
+ oLoggerFile,
+#endif /* __riscos__ */
oUtf8Strings,
oNoUtf8Strings,
oDisableCipherAlgo,
oDisablePubkeyAlgo,
oAllowNonSelfsignedUID,
+ oNoAllowNonSelfsignedUID,
oAllowFreeformUID,
+ oNoAllowFreeformUID,
+ oAllowSecretKeyImport,
+ oEnableSpecialFilenames,
oNoLiteral,
oSetFilesize,
oHonorHttpProxy,
oFastListMode,
oListOnly,
oIgnoreTimeConflict,
+ oIgnoreValidFrom,
+ oIgnoreCrcError,
+ oShowSessionKey,
+ oOverrideSessionKey,
oNoRandomSeedFile,
+ oAutoKeyRetrieve,
oNoAutoKeyRetrieve,
oUseAgent,
+ oNoUseAgent,
+ oGpgAgentInfo,
oMergeOnly,
oTryAllSecrets,
oTrustedKey,
+ oNoExpensiveTrustChecks,
+ oFixedListMode,
+ oNoSigCache,
+ oNoSigCreateCheck,
+ oAutoCheckTrustDB,
+ oNoAutoCheckTrustDB,
+ oPreservePermissions,
+ oDefaultPreferenceList,
+ oPersonalCipherPreferences,
+ oPersonalDigestPreferences,
+ oPersonalCompressPreferences,
+ oEmu3DESS2KBug, /* will be removed in 1.1 */
oEmuMDEncodeBug,
+ oDisplay,
+ oTTYname,
+ oTTYtype,
+ oLCctype,
+ oLCmessages,
+ oGroup,
aTest };
@@ -204,9 +303,11 @@ static ARGPARSE_OPTS opts[] = {
{ aClearsign, "clearsign", 256, N_("|[file]|make a clear text signature") },
{ aDetachedSign, "detach-sign", 256, N_("make a detached signature")},
{ aEncr, "encrypt", 256, N_("encrypt data")},
+ { aEncrFiles, "encrypt-files", 256, N_("|[files]|encrypt files")},
{ aSym, "symmetric", 256, N_("encryption only with symmetric cipher")},
{ aStore, "store", 256, N_("store only")},
{ aDecrypt, "decrypt", 256, N_("decrypt data (default)")},
+ { aDecryptFiles, "decrypt-files", 256, N_("|[files]|decrypt files")},
{ aVerify, "verify" , 256, N_("verify a signature")},
{ aVerifyFiles, "verify-files" , 256, "@" },
{ aListKeys, "list-keys", 256, N_("list keys")},
@@ -216,16 +317,23 @@ static ARGPARSE_OPTS opts[] = {
{ oFingerprint, "fingerprint", 256, N_("list keys and fingerprints")},
{ aListSecretKeys, "list-secret-keys", 256, N_("list secret keys")},
{ aKeygen, "gen-key", 256, N_("generate a new key pair")},
- { aDeleteKey, "delete-key",256, N_("remove key from the public keyring")},
- { aDeleteSecretKey, "delete-secret-key",256,
- N_("remove key from the secret keyring")},
+ { aDeleteKeys,"delete-keys",256,N_("remove keys from the public keyring")},
+ { aDeleteSecretKeys, "delete-secret-keys",256,
+ N_("remove keys from the secret keyring")},
{ aSignKey, "sign-key" ,256, N_("sign a key")},
{ aLSignKey, "lsign-key" ,256, N_("sign a key locally")},
+ { aNRSignKey, "nrsign-key" ,256, N_("sign a key non-revocably")},
+ { aNRLSignKey, "nrlsign-key" ,256, N_("sign a key locally and non-revocably")},
{ aEditKey, "edit-key" ,256, N_("sign or edit a key")},
{ aGenRevoke, "gen-revoke",256, N_("generate a revocation certificate")},
+ { aDesigRevoke, "desig-revoke",256, "@" },
{ aExport, "export" , 256, N_("export keys") },
{ aSendKeys, "send-keys" , 256, N_("export keys to a key server") },
{ aRecvKeys, "recv-keys" , 256, N_("import keys from a key server") },
+ { aSearchKeys, "search-keys" , 256,
+ N_("search for keys on a key server") },
+ { aRefreshKeys, "refresh-keys", 256,
+ N_("update all keys from a keyserver")},
{ aExportAll, "export-all" , 256, "@" },
{ aExportSecret, "export-secret-keys" , 256, "@" },
{ aExportSecretSub, "export-secret-subkeys" , 256, "@" },
@@ -239,14 +347,13 @@ static ARGPARSE_OPTS opts[] = {
{ aUpdateTrustDB,
"update-trustdb",0 , N_("update the trust database")},
{ aCheckTrustDB,
- "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
+ "check-trustdb",0 , N_("unattended trust database update")},
{ aFixTrustDB, "fix-trustdb",0 , N_("fix a corrupted trust database")},
{ aDeArmor, "dearmor", 256, N_("De-Armor a file or stdin") },
{ aDeArmor, "dearmour", 256, "@" },
{ aEnArmor, "enarmor", 256, N_("En-Armor a file or stdin") },
{ aEnArmor, "enarmour", 256, "@" },
{ aPrintMD, "print-md" , 256, N_("|algo [files]|print message digests")},
- { aPrintHMAC, "print-hmac" , 256, "@"},
{ aPrimegen, "gen-prime" , 256, "@" },
{ aGenRandom, "gen-random" , 256, "@" },
@@ -261,52 +368,92 @@ static ARGPARSE_OPTS opts[] = {
{ oDefRecipientSelf, "default-recipient-self" ,0,
N_("use the default key as default recipient")},
{ oNoDefRecipient, "no-default-recipient", 0, "@" },
+ { oTempDir, "temp-directory", 2, "@" },
+ { oExecPath, "exec-path", 2, "@" },
{ oEncryptTo, "encrypt-to", 2, "@" },
{ oNoEncryptTo, "no-encrypt-to", 0, "@" },
{ oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
{ oCompress, NULL, 1, N_("|N|set compress level N (0 disables)") },
{ oTextmodeShort, NULL, 0, "@"},
{ oTextmode, "textmode", 0, N_("use canonical text mode")},
+ { oExpert, "expert", 0, "@"},
+ { oNoExpert, "no-expert", 0, "@"},
+ { oAskSigExpire, "ask-sig-expire", 0, "@"},
+ { oNoAskSigExpire, "no-ask-sig-expire", 0, "@"},
+ { oAskCertExpire, "ask-cert-expire", 0, "@"},
+ { oNoAskCertExpire, "no-ask-cert-expire", 0, "@"},
{ oOutput, "output", 2, N_("use as output file")},
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
{ oNoTTY, "no-tty", 0, N_("don't use the terminal at all") },
{ oForceV3Sigs, "force-v3-sigs", 0, N_("force v3 signatures") },
+ { oNoForceV3Sigs, "no-force-v3-sigs", 0, N_("do not force v3 signatures") },
+ { oForceV4Certs, "force-v4-certs", 0, N_("force v4 key signatures") },
+ { oNoForceV4Certs, "no-force-v4-certs", 0, N_("do not force v4 key signatures") },
{ oForceMDC, "force-mdc", 0, N_("always use a MDC for encryption") },
+ { oNoForceMDC, "no-force-mdc", 0, "@" },
+ { oDisableMDC, "disable-mdc", 0, N_("never use a MDC for encryption") },
+ { oNoDisableMDC, "no-disable-mdc", 0, "@" },
{ oDryRun, "dry-run", 0, N_("do not make any changes") },
/*{ oInteractive, "interactive", 0, N_("prompt before overwriting") }, */
{ oUseAgent, "use-agent",0, N_("use the gpg-agent")},
+ { oNoUseAgent, "no-use-agent",0, "@"},
+ { oGpgAgentInfo, "gpg-agent-info",2, "@"},
{ oBatch, "batch", 0, N_("batch mode: never ask")},
{ oAnswerYes, "yes", 0, N_("assume yes on most questions")},
{ oAnswerNo, "no", 0, N_("assume no on most questions")},
{ oKeyring, "keyring" ,2, N_("add this keyring to the list of keyrings")},
{ oSecretKeyring, "secret-keyring" ,2, N_("add this secret keyring to the list")},
+ { oShowKeyring, "show-keyring", 0, N_("show which keyring a listed key is on")},
{ oDefaultKey, "default-key" ,2, N_("|NAME|use NAME as default secret key")},
{ oKeyServer, "keyserver",2, N_("|HOST|use this keyserver to lookup keys")},
+ { oKeyServerOptions, "keyserver-options",2,"@"},
{ oCharset, "charset" , 2, N_("|NAME|set terminal charset to NAME") },
{ oOptions, "options" , 2, N_("read options from file")},
{ oDebug, "debug" ,4|16, "@"},
{ oDebugAll, "debug-all" ,0, "@"},
{ oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
- { oNoComment, "no-comment", 0, "@"},
+#ifdef __riscos__
+ { oStatusFile, "status-file" ,2, N_("|[file]|write status info to file") },
+#endif /* __riscos__ */
+ { oAttributeFD, "attribute-fd" ,1, "@" },
+#ifdef __riscos__
+ { oAttributeFile, "attribute-file" ,2, "@" },
+#endif /* __riscos__ */
+ { oNoSKComments, "no-comment", 0, "@"},
+ { oNoSKComments, "no-sk-comments", 0, "@"},
+ { oSKComments, "sk-comments", 0, "@"},
{ oCompletesNeeded, "completes-needed", 1, "@"},
{ oMarginalsNeeded, "marginals-needed", 1, "@"},
{ oMaxCertDepth, "max-cert-depth", 1, "@" },
- { oTrustedKey, "trusted-key", 2, N_("|KEYID|ulimately trust this key")},
+ { oTrustedKey, "trusted-key", 2, N_("|KEYID|ultimately trust this key")},
{ oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
{ oRFC1991, "rfc1991", 0, N_("emulate the mode described in RFC1991")},
{ oOpenPGP, "openpgp", 0, N_("set all packet, cipher and digest options to OpenPGP behavior")},
+ { oPGP2, "pgp2", 0, N_("set all packet, cipher and digest options to PGP 2.x behavior")},
+ { oNoPGP2, "no-pgp2", 0, "@"},
+ { oPGP6, "pgp6", 0, "@"},
+ { oNoPGP6, "no-pgp6", 0, "@"},
+ { oPGP7, "pgp7", 0, "@"},
+ { oNoPGP7, "no-pgp7", 0, "@"},
{ oS2KMode, "s2k-mode", 1, N_("|N|use passphrase mode N")},
{ oS2KDigest, "s2k-digest-algo",2,
N_("|NAME|use message digest algorithm NAME for passphrases")},
{ oS2KCipher, "s2k-cipher-algo",2,
N_("|NAME|use cipher algorithm NAME for passphrases")},
+ { oSimpleSKChecksum, "simple-sk-checksum", 0, "@"},
{ oCipherAlgo, "cipher-algo", 2 , N_("|NAME|use cipher algorithm NAME")},
{ oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")},
+ { oCertDigestAlgo, "cert-digest-algo", 2 , "@" },
{ oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
{ oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")},
- { oNotation, "notation-data", 2, N_("|NAME=VALUE|use this notation data")},
+ { oShowPhotos, "show-photos", 0, N_("Show Photo IDs")},
+ { oNoShowPhotos, "no-show-photos", 0, N_("Don't show Photo IDs")},
+ { oPhotoViewer, "photo-viewer", 2, N_("Set command line to view Photo IDs")},
+ { oNotation, "notation-data", 2, "@" },
+ { oSigNotation, "sig-notation", 2, "@" },
+ { oCertNotation, "cert-notation", 2, "@" },
{ 302, NULL, 0, N_(
"@\n(See the man page for a complete listing of all commands and options)\n"
@@ -324,12 +471,21 @@ static ARGPARSE_OPTS opts[] = {
{ aPrintMDs, "print-mds" , 256, "@"}, /* old */
{ aListTrustDB, "list-trustdb",0 , "@"},
{ aListTrustPath, "list-trust-path",0, "@"},
+ { aPipeMode, "pipemode", 0, "@" },
{ oKOption, NULL, 0, "@"},
{ oPasswdFD, "passphrase-fd",1, "@" },
+#ifdef __riscos__
+ { oPasswdFile, "passphrase-file",2, "@" },
+#endif /* __riscos__ */
{ oCommandFD, "command-fd",1, "@" },
+#ifdef __riscos__
+ { oCommandFile, "command-file",2, "@" },
+#endif /* __riscos__ */
+ { oQuickRandom, "quick-random", 0, "@"},
{ oNoVerbose, "no-verbose", 0, "@"},
{ oTrustDBName, "trustdb-name", 2, "@" },
{ oNoSecmemWarn, "no-secmem-warning", 0, "@" }, /* used only by regression tests */
+ { oNoPermissionWarn, "no-permission-warning", 0, "@" },
{ oNoArmor, "no-armor", 0, "@"},
{ oNoArmor, "no-armour", 0, "@"},
{ oNoDefKeyring, "no-default-keyring", 0, "@" },
@@ -345,20 +501,34 @@ static ARGPARSE_OPTS opts[] = {
{ oSkipVerify, "skip-verify",0, "@" },
{ oCompressKeys, "compress-keys",0, "@"},
{ oCompressSigs, "compress-sigs",0, "@"},
+ { oDefCertCheckLevel, "default-cert-check-level", 1, "@"},
{ oAlwaysTrust, "always-trust", 0, "@"},
+ { oEmuChecksumBug, "emulate-checksum-bug", 0, "@"},
{ oRunAsShmCP, "run-as-shm-coprocess", 4, "@" },
{ oSetFilename, "set-filename", 2, "@" },
+ { oForYourEyesOnly, "for-your-eyes-only", 0, "@" },
+ { oNoForYourEyesOnly, "no-for-your-eyes-only", 0, "@" },
{ oSetPolicyURL, "set-policy-url", 2, "@" },
+ { oSigPolicyURL, "sig-policy-url", 2, "@" },
+ { oCertPolicyURL, "cert-policy-url", 2, "@" },
+ { oShowPolicyURL, "show-policy-url", 0, "@" },
+ { oNoShowPolicyURL, "no-show-policy-url", 0, "@" },
+ { oShowNotation, "show-notation", 0, "@" },
+ { oNoShowNotation, "no-show-notation", 0, "@" },
{ oComment, "comment", 2, "@" },
{ oDefaultComment, "default-comment", 0, "@" },
{ oNoVersion, "no-version", 0, "@"},
{ oEmitVersion, "emit-version", 0, "@"},
{ oNotDashEscaped, "not-dash-escaped", 0, "@" },
{ oEscapeFrom, "escape-from-lines", 0, "@" },
+ { oNoEscapeFrom, "no-escape-from-lines", 0, "@" },
{ oLockOnce, "lock-once", 0, "@" },
{ oLockMultiple, "lock-multiple", 0, "@" },
{ oLockNever, "lock-never", 0, "@" },
{ oLoggerFD, "logger-fd",1, "@" },
+#ifdef __riscos__
+ { oLoggerFile, "logger-file",2, "@" },
+#endif /* __riscos__ */
{ oUseEmbeddedFilename, "use-embedded-filename", 0, "@" },
{ oUtf8Strings, "utf8-strings", 0, "@" },
{ oNoUtf8Strings, "no-utf8-strings", 0, "@" },
@@ -366,47 +536,73 @@ static ARGPARSE_OPTS opts[] = {
{ oDisableCipherAlgo, "disable-cipher-algo", 2, "@" },
{ oDisablePubkeyAlgo, "disable-pubkey-algo", 2, "@" },
{ oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", 0, "@" },
+ { oNoAllowNonSelfsignedUID, "no-allow-non-selfsigned-uid", 0, "@" },
{ oAllowFreeformUID, "allow-freeform-uid", 0, "@" },
+ { oNoAllowFreeformUID, "no-allow-freeform-uid", 0, "@" },
{ oNoLiteral, "no-literal", 0, "@" },
{ oSetFilesize, "set-filesize", 20, "@" },
{ oHonorHttpProxy,"honor-http-proxy", 0, "@" },
{ oFastListMode,"fast-list-mode", 0, "@" },
+ { oFixedListMode,"fixed-list-mode", 0, "@" },
{ oListOnly, "list-only", 0, "@"},
{ oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
+ { oIgnoreValidFrom, "ignore-valid-from", 0, "@" },
+ { oIgnoreCrcError, "ignore-crc-error", 0,"@" },
+ { oShowSessionKey, "show-session-key", 0, "@" },
+ { oOverrideSessionKey, "override-session-key", 2, "@" },
{ oNoRandomSeedFile, "no-random-seed-file", 0, "@" },
+ { oAutoKeyRetrieve, "auto-key-retrieve", 0, "@" },
{ oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" },
+ { oNoSigCache, "no-sig-cache", 0, "@" },
+ { oNoSigCreateCheck, "no-sig-create-check", 0, "@" },
+ { oAutoCheckTrustDB, "auto-check-trustdb", 0, "@"},
+ { oNoAutoCheckTrustDB, "no-auto-check-trustdb", 0, "@"},
{ oMergeOnly, "merge-only", 0, "@" },
+ { oAllowSecretKeyImport, "allow-secret-key-import", 0, "@" },
{ oTryAllSecrets, "try-all-secrets", 0, "@" },
+ { oEnableSpecialFilenames, "enable-special-filenames", 0, "@" },
+ { oNoExpensiveTrustChecks, "no-expensive-trust-checks", 0, "@" },
+ { aDeleteSecretAndPublicKeys, "delete-secret-and-public-keys",256, "@" },
+ { aRebuildKeydbCaches, "rebuild-keydb-caches", 256, "@"},
+ { oPreservePermissions, "preserve-permissions", 0, "@"},
+ { oDefaultPreferenceList, "default-preference-list", 2, "@"},
+ { oPersonalCipherPreferences, "personal-cipher-preferences", 2, "@"},
+ { oPersonalDigestPreferences, "personal-digest-preferences", 2, "@"},
+ { oPersonalCompressPreferences, "personal-compress-preferences", 2, "@"},
+ { oEmu3DESS2KBug, "emulate-3des-s2k-bug", 0, "@"},
{ oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
+ { oDisplay, "display", 2, "@" },
+ { oTTYname, "ttyname", 2, "@" },
+ { oTTYtype, "ttytype", 2, "@" },
+ { oLCctype, "lc-ctype", 2, "@" },
+ { oLCmessages, "lc-messages", 2, "@" },
+ { oGroup, "group", 2, "@" },
{0} };
-int gpg_errors_seen = 0;
+int g10_errors_seen = 0;
static int utf8_strings = 0;
static int maybe_setuid = 1;
-static char *build_list( const char *text,
+static char *build_list( const char *text, char letter,
const char *(*mapf)(int), int (*chkf)(int) );
static void set_cmd( enum cmd_and_opt_values *ret_cmd,
enum cmd_and_opt_values new_cmd );
static void print_hex( byte *p, size_t n );
-static void print_mds( const char *fname, int algo, const char *key );
-static void add_notation_data( const char *string );
-static int check_policy_url( const char *s );
-
+static void print_mds( const char *fname, int algo );
+static void add_notation_data( const char *string, int which );
+static void add_policy_url( const char *string, int which );
-static int
-our_pk_test_algo( int algo )
-{
- return openpgp_pk_test_algo( algo, 0 );
-}
+#ifdef __riscos__
+RISCOS_GLOBAL_STATICS("GnuPG Heap")
+#endif /* __riscos__ */
-static const char *
-my_strusage( int level )
+const char *
+strusage( int level )
{
- static char *digests, *pubkeys, *ciphers;
+ static char *digests, *pubkeys, *ciphers, *zips;
const char *p;
switch( level ) {
case 11: p = "gpg (GnuPG)";
@@ -427,56 +623,90 @@ my_strusage( int level )
break;
case 31: p = "\nHome: "; break;
+#ifndef __riscos__
case 32: p = opt.homedir; break;
+#else /* __riscos__ */
+ case 32: p = make_filename(opt.homedir, NULL); break;
+#endif /* __riscos__ */
case 33: p = _("\nSupported algorithms:\n"); break;
case 34:
- if( !ciphers )
- ciphers = build_list("Cipher: ", gcry_cipher_algo_name,
- openpgp_cipher_test_algo );
- p = ciphers;
- break;
- case 35:
if( !pubkeys )
- pubkeys = build_list("Pubkey: ", gcry_pk_algo_name,
- our_pk_test_algo );
+ pubkeys = build_list("Pubkey: ", 0, pubkey_algo_to_string,
+ check_pubkey_algo );
p = pubkeys;
break;
+ case 35:
+ if( !ciphers )
+ ciphers = build_list("Cipher: ", 'S', cipher_algo_to_string,
+ check_cipher_algo );
+ p = ciphers;
+ break;
case 36:
if( !digests )
- digests = build_list("Hash: ", gcry_md_algo_name,
- openpgp_md_test_algo );
+ digests = build_list("Hash: ", 'H', digest_algo_to_string,
+ check_digest_algo );
p = digests;
break;
+ case 37:
+ if( !zips )
+ zips = build_list("Compress: ",'Z',compress_algo_to_string,
+ check_compress_algo);
+ p = zips;
+ break;
-
- default: p = NULL;
+ default: p = default_strusage(level);
}
return p;
}
static char *
-build_list( const char *text, const char * (*mapf)(int), int (*chkf)(int) )
+build_list( const char *text, char letter,
+ const char * (*mapf)(int), int (*chkf)(int) )
{
int i;
+ const char *s;
size_t n=strlen(text)+2;
- char *list, *p;
-
- if( maybe_setuid ) {
- gcry_control( GCRYCTL_DROP_PRIVS ); /* drop setuid */
- }
-
- for(i=1; i < 110; i++ )
- if( !chkf(i) )
- n += strlen(mapf(i)) + 2;
- list = gcry_xmalloc( 21 + n ); *list = 0;
- for(p=NULL, i=1; i < 110; i++ ) {
- if( !chkf(i) ) {
- if( !p )
+ char *list, *p, *line=NULL;
+
+ if( maybe_setuid )
+ secmem_init( 0 ); /* drop setuid */
+
+ for(i=0; i <= 110; i++ )
+ if( !chkf(i) && (s=mapf(i)) )
+ n += strlen(s) + 7 + 2;
+ list = m_alloc( 21 + n ); *list = 0;
+ for(p=NULL, i=0; i <= 110; i++ ) {
+ if( !chkf(i) && (s=mapf(i)) ) {
+ if( !p ) {
p = stpcpy( list, text );
+ line=p;
+ }
else
p = stpcpy( p, ", ");
- p = stpcpy(p, mapf(i) );
+
+ if(strlen(line)>60) {
+ int spaces=strlen(text);
+
+ list=m_realloc(list,n+spaces+1);
+ /* realloc could move the block, so find the end again */
+ p=list;
+ while(*p)
+ p++;
+
+ p=stpcpy(p, "\n");
+ line=p;
+ for(;spaces;spaces--)
+ p=stpcpy(p, " ");
+ }
+
+ p = stpcpy(p, s );
+ if(opt.verbose && letter)
+ {
+ char num[8];
+ sprintf(num," (%c%d)",letter,i);
+ p = stpcpy(p,num);
+ }
}
}
if( p )
@@ -492,52 +722,20 @@ i18n_init(void)
set_gettext_file( PACKAGE );
#else
#ifdef ENABLE_NLS
- #ifdef HAVE_LC_MESSAGES
- setlocale( LC_TIME, "" );
- setlocale( LC_MESSAGES, "" );
- #else
- setlocale( LC_ALL, "" );
- #endif
- bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
+ setlocale( LC_ALL, "" );
+ bindtextdomain( PACKAGE, G10_LOCALEDIR );
textdomain( PACKAGE );
#endif
#endif
}
-
-static void
-register_extension( const char *mainpgm, const char *fname )
-{
- #warning fixme add register cipher extension
- /* Before we do so, we should design a beter API for this.
- * I am currently thinking about using S-Exp to pass everything we
- * need from the module to gcrypt. I hope we are not going to
- * implement my-own-lisp-library-no-17000 */
- #if 0
- if( *fname != '/' ) { /* do tilde expansion etc */
- char *tmp;
-
- if( strchr(fname, '/') )
- tmp = make_filename(fname, NULL);
- else
- tmp = make_filename(GNUPG_LIBDIR, fname, NULL);
- register_cipher_extension( mainpgm, tmp );
- gcry_free(tmp);
- }
- else
- register_cipher_extension( mainpgm, fname );
- #endif
-}
-
-
-
static void
wrong_args( const char *text)
{
fputs(_("usage: gpg [options] "),stderr);
fputs(text,stderr);
putc('\n',stderr);
- gpg_exit(2);
+ g10_exit(2);
}
@@ -546,7 +744,7 @@ make_username( const char *string )
{
char *p;
if( utf8_strings )
- p = gcry_xstrdup(string);
+ p = m_strdup(string);
else
p = native_to_utf8( string );
return p;
@@ -556,19 +754,14 @@ make_username( const char *string )
static void
set_debug(void)
{
- #if 0
- #warning memory debugging not enabled
if( opt.debug & DBG_MEMORY_VALUE )
memory_debug_mode = 1;
if( opt.debug & DBG_MEMSTAT_VALUE )
memory_stat_debug_mode = 1;
- #endif
-
if( opt.debug & DBG_MPI_VALUE )
- gcry_control( GCRYCTL_SET_DEBUG_FLAGS, 2 );
+ mpi_debug_mode = 1;
if( opt.debug & DBG_CIPHER_VALUE )
- gcry_control( GCRYCTL_SET_DEBUG_FLAGS, 1 );
-
+ g10c_debug_mode = 1;
if( opt.debug & DBG_IOBUF_VALUE )
iobuf_debug_mode = 1;
@@ -586,6 +779,10 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
cmd = aSignEncr;
else if( cmd == aEncr && new_cmd == aSign )
cmd = aSignEncr;
+ else if( cmd == aSign && new_cmd == aSym )
+ cmd = aSignSym;
+ else if( cmd == aSym && new_cmd == aSign )
+ cmd = aSignSym;
else if( cmd == aKMode && new_cmd == aSym )
cmd = aKModeC;
else if( ( cmd == aSign && new_cmd == aClearsign )
@@ -593,13 +790,39 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
cmd = aClearsign;
else {
log_error(_("conflicting commands\n"));
- gpg_exit(2);
+ g10_exit(2);
}
*ret_cmd = cmd;
}
+static void add_group(char *string)
+{
+ char *name,*value;
+ struct groupitem *item;
+ STRLIST values=NULL;
+
+ /* Break off the group name */
+ name=strsep(&string," ");
+ if(string==NULL)
+ {
+ log_error(_("no values for group \"%s\"\n"),name);
+ return;
+ }
+
+ /* Break apart the values */
+ while((value=strsep(&string," ")) && *value!='\0')
+ add_to_strlist2(&values,value,utf8_strings);
+
+ item=m_alloc(sizeof(struct groupitem));
+ item->name=name;
+ item->values=values;
+ item->next=opt.grouplist;
+
+ opt.grouplist=item;
+}
+
int
main( int argc, char **argv )
@@ -611,6 +834,8 @@ main( int argc, char **argv )
char **orig_argv;
const char *fname;
char *username;
+ STRLIST unsafe_files=NULL;
+ STRLIST extensions=NULL;
int may_coredump;
STRLIST sl, remusr= NULL, locusr=NULL;
STRLIST nrings=NULL, sec_nrings=NULL;
@@ -620,7 +845,7 @@ main( int argc, char **argv )
char *configname = NULL;
unsigned configlineno;
int parse_debug = 0;
- int default_config =1;
+ int default_config = 1;
int default_keyring = 1;
int greeting = 0;
int nogreeting = 0;
@@ -629,30 +854,33 @@ main( int argc, char **argv )
const char *trustdb_name = NULL;
char *def_cipher_string = NULL;
char *def_digest_string = NULL;
+ char *cert_digest_string = NULL;
char *s2k_cipher_string = NULL;
char *s2k_digest_string = NULL;
+ char *pers_cipher_list = NULL;
+ char *pers_digest_list = NULL;
+ char *pers_compress_list = NULL;
+ int eyes_only=0;
int pwfd = -1;
int with_fpr = 0; /* make an option out of --fingerprint */
+ int any_explicit_recipient = 0;
#ifdef USE_SHM_COPROCESSING
ulong requested_shm_size=0;
#endif
+ #ifdef __riscos__
+ riscos_global_defaults();
+ opt.lock_once = 1;
+ #endif /* __riscos__ */
+
trap_unaligned();
- set_strusage( my_strusage );
- gcry_control( GCRYCTL_SUSPEND_SECMEM_WARN );
+ secmem_set_flags( secmem_get_flags() | 2 ); /* suspend warnings */
/* Please note that we may running SUID(ROOT), so be very CAREFUL
* when adding any stuff between here and the call to
* secmem_init() somewhere after the option parsing
*/
log_set_name("gpg");
- /* check that the libraries are suitable. Do it here because
- * the option parse may need services of the library */
- if ( !gcry_check_version ( "1.1.0a" ) ) {
- log_fatal(_("libgcrypt is too old (need %s, have %s)\n"),
- VERSION, gcry_check_version(NULL) );
- }
-
- gcry_control( GCRYCTL_USE_SECURE_RNDPOOL );
+ secure_random_alloc(); /* put random number into secure memory */
may_coredump = disable_core_dumps();
init_signals();
create_dotlock(NULL); /* register locking cleanup */
@@ -662,20 +890,23 @@ main( int argc, char **argv )
/* note: if you change these lines, look at oOpenPGP */
opt.def_cipher_algo = 0;
opt.def_digest_algo = 0;
- opt.def_compress_algo = 2;
+ opt.cert_digest_algo = 0;
+ opt.def_compress_algo = -1;
opt.s2k_mode = 3; /* iterated+salted */
- opt.s2k_digest_algo = GCRY_MD_SHA1;
- opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
+ opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
+ opt.s2k_cipher_algo = CIPHER_ALGO_CAST5;
opt.completes_needed = 1;
opt.marginals_needed = 3;
opt.max_cert_depth = 5;
opt.pgp2_workarounds = 1;
- opt.auto_key_retrieve = 1;
- #ifdef __MINGW32__
+ opt.force_v3_sigs = 1;
+ opt.escape_from = 1;
+ opt.keyserver_options.include_subkeys=1;
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
- #else
+#else
opt.homedir = getenv("GNUPGHOME");
- #endif
+#endif
if( !opt.homedir || !*opt.homedir ) {
opt.homedir = GNUPG_HOMEDIR;
}
@@ -709,19 +940,28 @@ main( int argc, char **argv )
else if ( pargs.r_opt == oStatusFD ) {
/* this is needed to ensure that the status-fd filedescriptor is
* initialized when init_shm_coprocessing() is called */
- set_status_fd( pargs.r.ret_int );
+ set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
}
#endif
}
-
- #ifdef USE_SHM_COPROCESSING
+#ifdef HAVE_DOSISH_SYSTEM
+ if ( strchr (opt.homedir,'\\') ) {
+ char *d, *buf = m_alloc (strlen (opt.homedir)+1);
+ const char *s = opt.homedir;
+ for (d=buf,s=opt.homedir; *s; s++)
+ *d++ = *s == '\\'? '/': *s;
+ *d = 0;
+ opt.homedir = buf;
+ }
+#endif
+#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess ) {
init_shm_coprocessing(requested_shm_size, 1 );
}
- #endif
+#endif
/* initialize the secure memory. */
- gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 );
+ secmem_init( 16384 );
maybe_setuid = 0;
/* Okay, we are now working under our real uid */
@@ -735,6 +975,20 @@ main( int argc, char **argv )
pargs.flags= 1; /* do not remove the args */
next_pass:
if( configname ) {
+
+ if(check_permissions(configname,0,1))
+ {
+ add_to_strlist(&unsafe_files,configname);
+
+ /* If any options file is unsafe, then disable any external
+ programs for keyserver calls or photo IDs. Since the
+ external program to call is set in the options file, a
+ unsafe options file can lead to an arbitrary program
+ being run. */
+
+ opt.exec_disable=1;
+ }
+
configlineno = 0;
configfp = fopen( configname, "r" );
if( !configfp ) {
@@ -746,9 +1000,9 @@ main( int argc, char **argv )
else {
log_error(_("option file `%s': %s\n"),
configname, strerror(errno) );
- gpg_exit(2);
+ g10_exit(2);
}
- gcry_free(configname); configname = NULL;
+ m_free(configname); configname = NULL;
}
if( parse_debug && configname )
log_info(_("reading options from `%s'\n"), configname );
@@ -764,37 +1018,47 @@ main( int argc, char **argv )
case aFastImport: set_cmd( &cmd, aFastImport); break;
case aSendKeys: set_cmd( &cmd, aSendKeys); break;
case aRecvKeys: set_cmd( &cmd, aRecvKeys); break;
+ case aSearchKeys: set_cmd( &cmd, aSearchKeys); break;
+ case aRefreshKeys: set_cmd( &cmd, aRefreshKeys); break;
case aExport: set_cmd( &cmd, aExport); break;
case aExportAll: set_cmd( &cmd, aExportAll); break;
case aListKeys: set_cmd( &cmd, aListKeys); break;
case aListSigs: set_cmd( &cmd, aListSigs); break;
case aExportSecret: set_cmd( &cmd, aExportSecret); break;
case aExportSecretSub: set_cmd( &cmd, aExportSecretSub); break;
- case aDeleteSecretKey: set_cmd( &cmd, aDeleteSecretKey);
+ case aDeleteSecretKeys: set_cmd( &cmd, aDeleteSecretKeys);
greeting=1; break;
- case aDeleteKey: set_cmd( &cmd, aDeleteKey); greeting=1; break;
+ case aDeleteSecretAndPublicKeys:
+ set_cmd( &cmd, aDeleteSecretAndPublicKeys);
+ greeting=1;
+ break;
+ case aDeleteKeys: set_cmd( &cmd, aDeleteKeys); greeting=1; break;
case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
case aSym: set_cmd( &cmd, aSym); break;
case aDecrypt: set_cmd( &cmd, aDecrypt); break;
+ case aDecryptFiles: set_cmd( &cmd, aDecryptFiles); break;
case aEncr: set_cmd( &cmd, aEncr); break;
+ case aEncrFiles: set_cmd( &cmd, aEncrFiles ); break;
case aSign: set_cmd( &cmd, aSign ); break;
case aKeygen: set_cmd( &cmd, aKeygen); greeting=1; break;
case aSignKey: set_cmd( &cmd, aSignKey); break;
case aLSignKey: set_cmd( &cmd, aLSignKey); break;
+ case aNRSignKey: set_cmd( &cmd, aNRSignKey); break;
+ case aNRLSignKey: set_cmd( &cmd, aNRLSignKey); break;
case aStore: set_cmd( &cmd, aStore); break;
case aEditKey: set_cmd( &cmd, aEditKey); greeting=1; break;
case aClearsign: set_cmd( &cmd, aClearsign); break;
case aGenRevoke: set_cmd( &cmd, aGenRevoke); break;
+ case aDesigRevoke: set_cmd( &cmd, aDesigRevoke); break;
case aVerify: set_cmd( &cmd, aVerify); break;
case aVerifyFiles: set_cmd( &cmd, aVerifyFiles); break;
case aPrimegen: set_cmd( &cmd, aPrimegen); break;
case aGenRandom: set_cmd( &cmd, aGenRandom); break;
case aPrintMD: set_cmd( &cmd, aPrintMD); break;
case aPrintMDs: set_cmd( &cmd, aPrintMDs); break;
- case aPrintHMAC: set_cmd( &cmd, aPrintHMAC); break;
case aListTrustDB: set_cmd( &cmd, aListTrustDB); break;
case aCheckTrustDB: set_cmd( &cmd, aCheckTrustDB); break;
case aUpdateTrustDB: set_cmd( &cmd, aUpdateTrustDB); break;
@@ -804,6 +1068,8 @@ main( int argc, char **argv )
case aEnArmor: set_cmd( &cmd, aEnArmor); break;
case aExportOwnerTrust: set_cmd( &cmd, aExportOwnerTrust); break;
case aImportOwnerTrust: set_cmd( &cmd, aImportOwnerTrust); break;
+ case aPipeMode: set_cmd( &cmd, aPipeMode); break;
+ case aRebuildKeydbCaches: set_cmd( &cmd, aRebuildKeydbCaches); break;
case oArmor: opt.armor = 1; opt.no_armor=0; break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
@@ -811,41 +1077,75 @@ main( int argc, char **argv )
case oNoTTY: tty_no_terminal(1); break;
case oDryRun: opt.dry_run = 1; break;
case oInteractive: opt.interactive = 1; break;
- case oVerbose:
- opt.verbose++; opt.list_sigs=1;
- gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );
- break;
+ case oVerbose: g10_opt_verbose++;
+ opt.verbose++; opt.list_sigs=1; break;
case oKOption: set_cmd( &cmd, aKMode ); break;
- case oBatch: opt.batch = 1; greeting = 0; break;
- case oUseAgent: opt.use_agent = 1; break;
+ case oBatch: opt.batch = 1; nogreeting = 1; break;
+ case oUseAgent:
+#ifndef __riscos__
+ opt.use_agent = 1;
+#else /* __riscos__ */
+ opt.use_agent = 0;
+ not_implemented("use-agent");
+#endif /* __riscos__ */
+ break;
+ case oNoUseAgent: opt.use_agent = 0; break;
+ case oGpgAgentInfo: opt.gpg_agent_info = pargs.r.ret_str; break;
case oAnswerYes: opt.answer_yes = 1; break;
case oAnswerNo: opt.answer_no = 1; break;
case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
+ case oShowKeyring: opt.show_keyring = 1; break;
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
case oDebugAll: opt.debug = ~0; break;
- case oStatusFD: set_status_fd( pargs.r.ret_int ); break;
- case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break;
+ case oStatusFD:
+ set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) );
+ break;
+#ifdef __riscos__
+ case oStatusFile:
+ set_status_fd( iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+ break;
+#endif /* __riscos__ */
+ case oAttributeFD:
+ set_attrib_fd(iobuf_translate_file_handle (pargs.r.ret_int, 1));
+ break;
+#ifdef __riscos__
+ case oAttributeFile:
+ set_attrib_fd(iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+ break;
+#endif /* __riscos__ */
+ case oLoggerFD:
+ log_set_logfile( NULL,
+ iobuf_translate_file_handle (pargs.r.ret_int, 1) );
+ break;
+#ifdef __riscos__
+ case oLoggerFile:
+ log_set_logfile( NULL,
+ iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 1), 1) );
+ break;
+#endif /* __riscos__ */
case oWithFingerprint:
- with_fpr=1; /*fall thru*/
+ opt.with_fingerprint = 1;
+ with_fpr=1; /*fall thru*/
case oFingerprint: opt.fingerprint++; break;
case oSecretKeyring: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if( !configfp ) {
- gcry_free(configname);
- configname = gcry_xstrdup(pargs.r.ret_str);
+ m_free(configname);
+ configname = m_strdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoArmor: opt.no_armor=1; opt.armor=0; break;
case oNoDefKeyring: default_keyring = 0; break;
+ case oDefCertCheckLevel: opt.def_cert_check_level=pargs.r.ret_int; break;
case oNoGreeting: nogreeting = 1; break;
- case oNoVerbose:
- opt.verbose = 0; opt.list_sigs=0;
- gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );
- break;
- case oNoComment: opt.no_comment=1; break;
+ case oNoVerbose: g10_opt_verbose = 0;
+ opt.verbose = 0; opt.list_sigs=0; break;
+ case oQuickRandom: quick_random_gen(1); break;
+ case oSKComments: opt.sk_comments=1; break;
+ case oNoSKComments: opt.sk_comments=0; break;
case oNoVersion: opt.no_version=1; break;
case oEmitVersion: opt.no_version=0; break;
case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break;
@@ -858,15 +1158,15 @@ main( int argc, char **argv )
opt.def_recipient = make_username(pargs.r.ret_str);
break;
case oDefRecipientSelf:
- gcry_free(opt.def_recipient); opt.def_recipient = NULL;
+ m_free(opt.def_recipient); opt.def_recipient = NULL;
opt.def_recipient_self = 1;
break;
case oNoDefRecipient:
- gcry_free(opt.def_recipient); opt.def_recipient = NULL;
+ m_free(opt.def_recipient); opt.def_recipient = NULL;
opt.def_recipient_self = 0;
break;
- case oNoOptions: break; /* no-options */
- case oHomedir: opt.homedir = pargs.r.ret_str; break;
+ case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
+ case oHomedir: break;
case oNoBatch: opt.batch = 0; break;
case oWithKeyData: opt.with_key_data=1; /* fall thru */
case oWithColons: opt.with_colons=':'; break;
@@ -877,17 +1177,26 @@ main( int argc, char **argv )
case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break;
case oAlwaysTrust: opt.always_trust = 1; break;
case oLoadExtension:
- register_extension(orig_argc? *orig_argv:NULL, pargs.r.ret_str);
+#ifndef __riscos__
+ add_to_strlist(&extensions,pargs.r.ret_str);
+ register_cipher_extension(orig_argc? *orig_argv:NULL,
+ pargs.r.ret_str);
+#else /* __riscos__ */
+ not_implemented("load-extension");
+#endif /* __riscos__ */
break;
case oRFC1991:
opt.rfc1991 = 1;
opt.rfc2440 = 0;
- opt.no_comment = 1;
+ opt.force_v4_certs = 0;
+ opt.sk_comments = 0;
opt.escape_from = 1;
break;
case oOpenPGP:
opt.rfc1991 = 0;
opt.rfc2440 = 1;
+ opt.allow_non_selfsigned_uid = 1;
+ opt.allow_freeform_uid = 1;
opt.pgp2_workarounds = 0;
opt.escape_from = 0;
opt.force_v3_sigs = 0;
@@ -896,32 +1205,63 @@ main( int argc, char **argv )
opt.not_dash_escaped = 0;
opt.def_cipher_algo = 0;
opt.def_digest_algo = 0;
+ opt.cert_digest_algo = 0;
opt.def_compress_algo = 1;
- opt.s2k_mode = 3; /* iterated+salted */
- opt.s2k_digest_algo = GCRY_MD_SHA1;
- opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
+ opt.s2k_mode = 3; /* iterated+salted */
+ opt.s2k_digest_algo = DIGEST_ALGO_SHA1;
+ opt.s2k_cipher_algo = CIPHER_ALGO_CAST5;
break;
+ case oPGP2: opt.pgp2 = 1; break;
+ case oNoPGP2: opt.pgp2 = 0; break;
+ case oPGP6: opt.pgp6 = 1; break;
+ case oNoPGP6: opt.pgp6 = 0; break;
+ case oPGP7: opt.pgp7 = 1; break;
+ case oNoPGP7: opt.pgp7 = 0; break;
+ case oEmuChecksumBug: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
+ case oEmu3DESS2KBug: opt.emulate_bugs |= EMUBUG_3DESS2K; break;
case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
case oCompressSigs: opt.compress_sigs = 1; break;
case oRunAsShmCP:
+#ifndef __riscos__
#ifndef USE_SHM_COPROCESSING
/* not possible in the option file,
* but we print the warning here anyway */
log_error("shared memory coprocessing is not available\n");
#endif
+#else /* __riscos__ */
+ not_implemented("run-as-shm-coprocess");
+#endif /* __riscos__ */
break;
case oSetFilename: opt.set_filename = pargs.r.ret_str; break;
- case oSetPolicyURL: opt.set_policy_url = pargs.r.ret_str; break;
+ case oForYourEyesOnly: eyes_only = 1; break;
+ case oNoForYourEyesOnly: eyes_only = 0; break;
+ case oSetPolicyURL:
+ add_policy_url(pargs.r.ret_str,0);
+ add_policy_url(pargs.r.ret_str,1);
+ break;
+ case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break;
+ case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break;
+ case oShowPolicyURL: opt.show_policy_url=1; break;
+ case oNoShowPolicyURL: opt.show_policy_url=0; break;
case oUseEmbeddedFilename: opt.use_embedded_filename = 1; break;
case oComment: opt.comment_string = pargs.r.ret_str; break;
case oDefaultComment: opt.comment_string = NULL; break;
case oThrowKeyid: opt.throw_keyid = 1; break;
+ case oShowPhotos: opt.show_photos = 1; break;
+ case oNoShowPhotos: opt.show_photos = 0; break;
+ case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break;
case oForceV3Sigs: opt.force_v3_sigs = 1; break;
+ case oNoForceV3Sigs: opt.force_v3_sigs = 0; break;
+ case oForceV4Certs: opt.force_v4_certs = 1; break;
+ case oNoForceV4Certs: opt.force_v4_certs = 0; break;
case oForceMDC: opt.force_mdc = 1; break;
+ case oNoForceMDC: opt.force_mdc = 0; break;
+ case oDisableMDC: opt.disable_mdc = 1; break;
+ case oNoDisableMDC: opt.disable_mdc = 0; break;
case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break;
- case oS2KDigest: s2k_digest_string = gcry_xstrdup(pargs.r.ret_str); break;
- case oS2KCipher: s2k_cipher_string = gcry_xstrdup(pargs.r.ret_str); break;
-
+ case oS2KDigest: s2k_digest_string = m_strdup(pargs.r.ret_str); break;
+ case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break;
+ case oSimpleSKChecksum: opt.simple_sk_checksum = 1; break;
case oNoEncryptTo: opt.no_encrypt_to = 1; break;
case oEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
@@ -929,18 +1269,41 @@ main( int argc, char **argv )
break;
case oRecipient: /* store the recipient */
add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
+ any_explicit_recipient = 1;
break;
case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break;
+ case oExpert: opt.expert = 1; break;
+ case oNoExpert: opt.expert = 0; break;
+ case oAskSigExpire: opt.ask_sig_expire = 1; break;
+ case oNoAskSigExpire: opt.ask_sig_expire = 0; break;
+ case oAskCertExpire: opt.ask_cert_expire = 1; break;
+ case oNoAskCertExpire: opt.ask_cert_expire = 0; break;
case oUser: /* store the local users */
add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
break;
case oCompress: opt.compress = pargs.r.ret_int; break;
- case oPasswdFD: pwfd = pargs.r.ret_int; break;
- case oCommandFD: opt.command_fd = pargs.r.ret_int; break;
- case oCipherAlgo: def_cipher_string = gcry_xstrdup(pargs.r.ret_str); break;
- case oDigestAlgo: def_digest_string = gcry_xstrdup(pargs.r.ret_str); break;
- case oNoSecmemWarn: gcry_control( GCRYCTL_DISABLE_SECMEM_WARN ); break;
+ case oPasswdFD:
+ pwfd = iobuf_translate_file_handle (pargs.r.ret_int, 0);
+ break;
+#ifdef __riscos__
+ case oPasswdFile:
+ pwfd = iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 0), 0);
+ break;
+#endif /* __riscos__ */
+ case oCommandFD:
+ opt.command_fd = iobuf_translate_file_handle (pargs.r.ret_int, 0);
+ break;
+#ifdef __riscos__
+ case oCommandFile:
+ opt.command_fd = iobuf_translate_file_handle ( fdopenfile (pargs.r.ret_str, 0), 0);
+ break;
+#endif /* __riscos__ */
+ case oCipherAlgo: def_cipher_string = m_strdup(pargs.r.ret_str); break;
+ case oDigestAlgo: def_digest_string = m_strdup(pargs.r.ret_str); break;
+ case oCertDigestAlgo: cert_digest_string = m_strdup(pargs.r.ret_str); break;
+ case oNoSecmemWarn: secmem_set_flags( secmem_get_flags() | 1 ); break;
+ case oNoPermissionWarn: opt.no_perm_warn=1; break;
case oCharset:
if( set_native_charset( pargs.r.ret_str ) )
log_error(_("%s is not a valid character set\n"),
@@ -948,54 +1311,129 @@ main( int argc, char **argv )
break;
case oNotDashEscaped: opt.not_dash_escaped = 1; break;
case oEscapeFrom: opt.escape_from = 1; break;
+ case oNoEscapeFrom: opt.escape_from = 0; break;
case oLockOnce: opt.lock_once = 1; break;
- #if 0
- #warning no disable_dotlock() yet
case oLockNever: disable_dotlock(); break;
- #endif
- case oLockMultiple: opt.lock_once = 0; break;
- case oKeyServer: opt.keyserver_name = pargs.r.ret_str; break;
- case oNotation: add_notation_data( pargs.r.ret_str ); break;
+ case oLockMultiple:
+#ifndef __riscos__
+ opt.lock_once = 0;
+#else /* __riscos__ */
+ not_implemented("lock-multiple");
+#endif /* __riscos__ */
+ break;
+ case oKeyServer:
+ if(parse_keyserver_uri(pargs.r.ret_str,configname,configlineno))
+ log_error(_("could not parse keyserver URI\n"));
+ break;
+ case oKeyServerOptions:
+ parse_keyserver_options(pargs.r.ret_str);
+ break;
+ case oTempDir: opt.temp_dir=pargs.r.ret_str; break;
+ case oExecPath:
+ {
+ /* Notice that path is never freed. That is
+ intentional due to the way putenv() works. */
+ char *path=m_alloc(5+strlen(pargs.r.ret_str)+1);
+ strcpy(path,"PATH=");
+ strcat(path,pargs.r.ret_str);
+ if(putenv(path)!=0)
+ log_error(_("unable to set exec-path to %s\n"),path);
+ }
+ break;
+ case oNotation:
+ add_notation_data( pargs.r.ret_str, 0 );
+ add_notation_data( pargs.r.ret_str, 1 );
+ break;
+ case oSigNotation: add_notation_data( pargs.r.ret_str, 0 ); break;
+ case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break;
+ case oShowNotation: opt.show_notation=1; break;
+ case oNoShowNotation: opt.show_notation=0; break;
case oUtf8Strings: utf8_strings = 1; break;
case oNoUtf8Strings: utf8_strings = 0; break;
- case oDisableCipherAlgo: {
- int algo = gcry_cipher_map_name(pargs.r.ret_str);
- gcry_cipher_ctl( NULL, GCRYCTL_DISABLE_ALGO,
- &algo, sizeof algo );
- }
+ case oDisableCipherAlgo:
+ disable_cipher_algo( string_to_cipher_algo(pargs.r.ret_str) );
break;
- case oDisablePubkeyAlgo: {
- int algo = gcry_pk_map_name(pargs.r.ret_str);
- gcry_pk_ctl( GCRYCTL_DISABLE_ALGO,
- &algo, sizeof algo );
- }
+ case oDisablePubkeyAlgo:
+ disable_pubkey_algo( string_to_pubkey_algo(pargs.r.ret_str) );
break;
+ case oNoSigCache: opt.no_sig_cache = 1; break;
+ case oNoSigCreateCheck: opt.no_sig_create_check = 1; break;
case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
+ case oNoAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid=0; break;
case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
+ case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break;
case oNoLiteral: opt.no_literal = 1; break;
case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
- case oHonorHttpProxy: opt.honor_http_proxy = 1; break;
+ case oHonorHttpProxy:
+ opt.keyserver_options.honor_http_proxy = 1;
+ deprecated_warning(configname,configlineno,
+ "--honor-http-proxy",
+ "--keyserver-options ",
+ "honor-http-proxy");
+ break;
case oFastListMode: opt.fast_list_mode = 1; break;
+ case oFixedListMode: opt.fixed_list_mode = 1; break;
case oListOnly: opt.list_only=1; break;
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
+ case oIgnoreValidFrom: opt.ignore_valid_from = 1; break;
+ case oIgnoreCrcError: opt.ignore_crc_error = 1; break;
case oNoRandomSeedFile: use_random_seed = 0; break;
- case oNoAutoKeyRetrieve: opt.auto_key_retrieve = 0; break;
+ case oAutoKeyRetrieve:
+ case oNoAutoKeyRetrieve:
+ opt.keyserver_options.auto_key_retrieve=
+ (pargs.r_opt==oAutoKeyRetrieve);
+ deprecated_warning(configname,configlineno,
+ pargs.r_opt==oAutoKeyRetrieve?"--auto-key-retrieve":
+ "--no-auto-key-retrieve","--keyserver-options ",
+ pargs.r_opt==oAutoKeyRetrieve?"auto-key-retrieve":
+ "no-auto-key-retrieve");
+ break;
+ case oShowSessionKey: opt.show_session_key = 1; break;
+ case oOverrideSessionKey:
+ opt.override_session_key = pargs.r.ret_str;
+ break;
case oMergeOnly: opt.merge_only = 1; break;
+ case oAllowSecretKeyImport: /* obsolete */ break;
case oTryAllSecrets: opt.try_all_secrets = 1; break;
case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
-
+ case oEnableSpecialFilenames:
+ iobuf_enable_special_filenames (1);
+ break;
+ case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break;
+ case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break;
+ case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break;
+ case oPreservePermissions: opt.preserve_permissions=1; break;
+ case oDefaultPreferenceList:
+ opt.def_preference_list = pargs.r.ret_str;
+ break;
+ case oPersonalCipherPreferences:
+ pers_cipher_list=pargs.r.ret_str;
+ break;
+ case oPersonalDigestPreferences:
+ pers_digest_list=pargs.r.ret_str;
+ break;
+ case oPersonalCompressPreferences:
+ pers_compress_list=pargs.r.ret_str;
+ break;
+ case oDisplay: opt.display = pargs.r.ret_str; break;
+ case oTTYname: opt.ttyname = pargs.r.ret_str; break;
+ case oTTYtype: opt.ttytype = pargs.r.ret_str; break;
+ case oLCctype: opt.lc_ctype = pargs.r.ret_str; break;
+ case oLCmessages: opt.lc_messages = pargs.r.ret_str; break;
+ case oGroup: add_group(pargs.r.ret_str); break;
default : pargs.err = configfp? 1:2; break;
}
}
+
if( configfp ) {
fclose( configfp );
configfp = NULL;
- gcry_free(configname); configname = NULL;
+ m_free(configname); configname = NULL;
goto next_pass;
}
- gcry_free( configname ); configname = NULL;
+ m_free( configname ); configname = NULL;
if( log_get_errorcount(0) )
- gpg_exit(2);
+ g10_exit(2);
if( nogreeting )
greeting = 0;
@@ -1012,9 +1450,39 @@ main( int argc, char **argv )
}
#endif
+ check_permissions(opt.homedir,0,0);
+
+ if(unsafe_files)
+ {
+ STRLIST tmp;
+
+ for(tmp=unsafe_files;tmp;tmp=tmp->next)
+ check_permissions(tmp->d,0,0);
+
+ free_strlist(unsafe_files);
+ }
+
+ if(extensions)
+ {
+ STRLIST tmp;
+
+ for(tmp=extensions;tmp;tmp=tmp->next)
+ check_permissions(tmp->d,1,0);
+
+ free_strlist(extensions);
+ }
+
if( may_coredump && !opt.quiet )
log_info(_("WARNING: program may create a core file!\n"));
+ if (eyes_only) {
+ if (opt.set_filename)
+ log_info(_("WARNING: %s overrides %s\n"),
+ "--for-your-eyes-only","--set-filename");
+
+ opt.set_filename="_CONSOLE";
+ }
+
if (opt.no_literal) {
log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal");
if (opt.textmode)
@@ -1022,51 +1490,142 @@ main( int argc, char **argv )
"--textmode", "--no-literal" );
if (opt.set_filename)
log_error(_("%s makes no sense with %s!\n"),
- "--set-filename", "--no-literal" );
+ eyes_only?"--for-your-eyes-only":"--set-filename",
+ "--no-literal" );
}
+
if (opt.set_filesize)
log_info(_("NOTE: %s is not for normal use!\n"), "--set-filesize");
if( opt.batch )
tty_batchmode( 1 );
- gcry_control( GCRYCTL_RESUME_SECMEM_WARN );
+ secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
set_debug();
- /* FIXME: should set filenames of libgcrypt explicitly
- * gpg_opt_homedir = opt.homedir; */
+ g10_opt_homedir = opt.homedir;
+
+ /* Do these after the switch(), so they can override settings. */
+ if(opt.pgp2 && (opt.pgp6 || opt.pgp7))
+ log_error(_("%s not allowed with %s!\n"),
+ "--pgp2",opt.pgp6?"--pgp6":"--pgp7");
+ else
+ {
+ if(opt.pgp2)
+ {
+ int unusable=0;
+
+ if(cmd==aSign && !detached_sig)
+ {
+ log_info(_("you can only make detached or clear signatures "
+ "while in --pgp2 mode\n"));
+ unusable=1;
+ }
+ else if(cmd==aSignEncr || cmd==aSignSym)
+ {
+ log_info(_("you can't sign and encrypt at the "
+ "same time while in --pgp2 mode\n"));
+ unusable=1;
+ }
+ else if(argc==0 && (cmd==aSign || cmd==aEncr || cmd==aSym))
+ {
+ log_info(_("you must use files (and not a pipe) when "
+ "working with --pgp2 enabled.\n"));
+ unusable=1;
+ }
+ else if(cmd==aEncr || cmd==aSym)
+ {
+ /* Everything else should work without IDEA (except using
+ a secret key encrypted with IDEA and setting an IDEA
+ preference, but those have their own error
+ messages). */
+
+ if(check_cipher_algo(CIPHER_ALGO_IDEA))
+ {
+ log_info(_("encrypting a message in --pgp2 mode requires "
+ "the IDEA cipher\n"));
+ idea_cipher_warn(1);
+ unusable=1;
+ }
+ else if(cmd==aSym)
+ {
+ m_free(def_cipher_string);
+ def_cipher_string = m_strdup("idea");
+ }
+ }
+
+ if(unusable)
+ {
+ log_info(_("this message may not be usable by PGP 2.x\n"));
+ opt.pgp2=0;
+ }
+ else
+ {
+ opt.rfc1991 = 1;
+ opt.rfc2440 = 0;
+ opt.force_mdc = 0;
+ opt.disable_mdc = 1;
+ opt.force_v4_certs = 0;
+ opt.sk_comments = 0;
+ opt.escape_from = 1;
+ opt.force_v3_sigs = 1;
+ opt.pgp2_workarounds = 1;
+ opt.ask_sig_expire = 0;
+ opt.ask_cert_expire = 0;
+ m_free(def_digest_string);
+ def_digest_string = m_strdup("md5");
+ opt.def_compress_algo = 1;
+ }
+ }
+
+ if(opt.pgp6 || opt.pgp7)
+ {
+ opt.force_mdc=0;
+ opt.disable_mdc=1;
+ opt.sk_comments=0;
+ opt.escape_from=1;
+ opt.force_v3_sigs=1;
+ opt.ask_sig_expire=0;
+ opt.def_compress_algo=1;
+ }
+ }
/* must do this after dropping setuid, because string_to...
* may try to load an module */
if( def_cipher_string ) {
- opt.def_cipher_algo = gcry_cipher_map_name(def_cipher_string);
- gcry_free(def_cipher_string); def_cipher_string = NULL;
- if( openpgp_cipher_test_algo(opt.def_cipher_algo) )
+ opt.def_cipher_algo = string_to_cipher_algo(def_cipher_string);
+ if(opt.def_cipher_algo==0 &&
+ ascii_strcasecmp(def_cipher_string,"idea")==0)
+ idea_cipher_warn(1);
+ m_free(def_cipher_string); def_cipher_string = NULL;
+ if( check_cipher_algo(opt.def_cipher_algo) )
log_error(_("selected cipher algorithm is invalid\n"));
}
if( def_digest_string ) {
- opt.def_digest_algo = gcry_md_map_name(def_digest_string);
- gcry_free(def_digest_string); def_digest_string = NULL;
- if( openpgp_md_test_algo(opt.def_digest_algo) )
+ opt.def_digest_algo = string_to_digest_algo(def_digest_string);
+ m_free(def_digest_string); def_digest_string = NULL;
+ if( check_digest_algo(opt.def_digest_algo) )
log_error(_("selected digest algorithm is invalid\n"));
}
+ if( cert_digest_string ) {
+ opt.cert_digest_algo = string_to_digest_algo(cert_digest_string);
+ m_free(cert_digest_string); cert_digest_string = NULL;
+ if( check_digest_algo(opt.cert_digest_algo) )
+ log_error(_("selected certification digest algorithm is invalid\n"));
+ }
if( s2k_cipher_string ) {
- opt.s2k_cipher_algo = gcry_cipher_map_name(s2k_cipher_string);
- gcry_free(s2k_cipher_string); s2k_cipher_string = NULL;
- if( openpgp_cipher_test_algo(opt.s2k_cipher_algo) )
+ opt.s2k_cipher_algo = string_to_cipher_algo(s2k_cipher_string);
+ m_free(s2k_cipher_string); s2k_cipher_string = NULL;
+ if( check_cipher_algo(opt.s2k_cipher_algo) )
log_error(_("selected cipher algorithm is invalid\n"));
}
if( s2k_digest_string ) {
- opt.s2k_digest_algo = gcry_md_map_name(s2k_digest_string);
- gcry_free(s2k_digest_string); s2k_digest_string = NULL;
- if( openpgp_md_test_algo(opt.s2k_digest_algo) )
+ opt.s2k_digest_algo = string_to_digest_algo(s2k_digest_string);
+ m_free(s2k_digest_string); s2k_digest_string = NULL;
+ if( check_digest_algo(opt.s2k_digest_algo) )
log_error(_("selected digest algorithm is invalid\n"));
}
- if( opt.set_policy_url ) {
- if( check_policy_url( opt.set_policy_url ) )
- log_error(_("the given policy URL is invalid\n"));
- }
- if( opt.def_compress_algo < 1 || opt.def_compress_algo > 2 )
- log_error(_("compress algorithm must be in range %d..%d\n"), 1, 2);
+ if( opt.def_compress_algo < -1 || opt.def_compress_algo > 2 )
+ log_error(_("compress algorithm must be in range %d..%d\n"), 0, 2);
if( opt.completes_needed < 1 )
log_error(_("completes-needed must be greater than 0\n"));
if( opt.marginals_needed < 2 )
@@ -1082,18 +1641,40 @@ main( int argc, char **argv )
log_error(_("invalid S2K mode; must be 0, 1 or 3\n"));
}
+ if(opt.def_cert_check_level<0 || opt.def_cert_check_level>3)
+ log_error(_("invalid default-check-level; must be 0, 1, 2, or 3\n"));
+
+ /* This isn't actually needed, but does serve to error out if the
+ string is invalid. */
+ if(opt.def_preference_list &&
+ keygen_set_std_prefs(opt.def_preference_list,0))
+ log_error(_("invalid default preferences\n"));
+
+ /* We provide defaults for the personal digest list */
+ if(!pers_digest_list)
+ pers_digest_list="h2";
+
+ if(pers_cipher_list &&
+ keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM))
+ log_error(_("invalid personal cipher preferences\n"));
+
+ if(pers_digest_list &&
+ keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH))
+ log_error(_("invalid personal digest preferences\n"));
+
+ if(pers_compress_list &&
+ keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP))
+ log_error(_("invalid personal compress preferences\n"));
if( log_get_errorcount(0) )
- gpg_exit(2);
+ g10_exit(2);
/* set the random seed file */
if( use_random_seed ) {
char *p = make_filename(opt.homedir, "random_seed", NULL );
- #if 0
- #warning set_random_seed_file missing
+ check_permissions(p,0,0);
set_random_seed_file(p);
- #endif
- gcry_free(p);
+ m_free(p);
}
if( !cmd && opt.fingerprint && !with_fpr ) {
@@ -1112,9 +1693,12 @@ main( int argc, char **argv )
opt.list_sigs++;
opt.verbose = opt.verbose > 1;
- gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );
+ g10_opt_verbose = opt.verbose;
}
+ /* Compression algorithm 0 means no compression at all */
+ if( opt.def_compress_algo == 0)
+ opt.compress = 0;
/* kludge to let -sat generate a clear text signature */
if( opt.textmode == 2 && !detached_sig && opt.armor && cmd == aSign )
@@ -1123,20 +1707,27 @@ main( int argc, char **argv )
if( opt.verbose > 1 )
set_packet_list_mode(1);
- /* add the keyrings, but not for some special commands and
- * not in case of "-kvv userid keyring" */
+ /* Add the keyrings, but not for some special commands and not in
+ case of "-kvv userid keyring". Also avoid adding the secret
+ keyring for a couple of commands to avoid unneeded access in
+ case the secrings are stored on a floppy */
if( cmd != aDeArmor && cmd != aEnArmor
- && !(cmd == aKMode && argc == 2 ) ) {
-
- if( !sec_nrings && default_keyring ) /* add default secret rings */
- add_keyblock_resource("secring.gpg", 0, 1);
- for(sl = sec_nrings; sl; sl = sl->next )
- add_keyblock_resource( sl->d, 0, 1 );
- if( !nrings && default_keyring ) /* add default ring */
- add_keyblock_resource("pubring.gpg", 0, 0);
+ && !(cmd == aKMode && argc == 2 ) )
+ {
+ if (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys
+ && cmd != aVerify && cmd != aVerifyFiles
+ && cmd != aSym)
+ {
+ if (!sec_nrings || default_keyring) /* add default secret rings */
+ keydb_add_resource ("secring" EXTSEP_S "gpg", 0, 1);
+ for (sl = sec_nrings; sl; sl = sl->next)
+ keydb_add_resource ( sl->d, 0, 1 );
+ }
+ if( !nrings || default_keyring ) /* add default ring */
+ keydb_add_resource ("pubring" EXTSEP_S "gpg", 0, 0);
for(sl = nrings; sl; sl = sl->next )
- add_keyblock_resource( sl->d, 0, 0 );
- }
+ keydb_add_resource ( sl->d, 0, 0 );
+ }
FREE_STRLIST(nrings);
FREE_STRLIST(sec_nrings);
@@ -1150,7 +1741,6 @@ main( int argc, char **argv )
case aPrimegen:
case aPrintMD:
case aPrintMDs:
- case aPrintHMAC:
case aGenRandom:
case aDeArmor:
case aEnArmor:
@@ -1168,8 +1758,22 @@ main( int argc, char **argv )
default: rc = setup_trustdb(1, trustdb_name ); break;
}
if( rc )
- log_error(_("failed to initialize the TrustDB: %s\n"), gpg_errstr(rc));
-
+ log_error(_("failed to initialize the TrustDB: %s\n"), g10_errstr(rc));
+
+
+ switch (cmd) {
+ case aStore:
+ case aSym:
+ case aSign:
+ case aSignSym:
+ case aClearsign:
+ if (!opt.quiet && any_explicit_recipient)
+ log_info (_("WARNING: recipients (-r) given "
+ "without using public key encryption\n"));
+ break;
+ default:
+ break;
+ }
switch( cmd ) {
case aStore: /* only store the file */
@@ -1177,23 +1781,27 @@ main( int argc, char **argv )
wrong_args(_("--store [filename]"));
if( (rc = encode_store(fname)) )
log_error_f( print_fname_stdin(fname),
- "store failed: %s\n", gpg_errstr(rc) );
+ "store failed: %s\n", g10_errstr(rc) );
break;
case aSym: /* encrypt the given file only with the symmetric cipher */
if( argc > 1 )
wrong_args(_("--symmetric [filename]"));
if( (rc = encode_symmetric(fname)) )
log_error_f(print_fname_stdin(fname),
- "symmetric encryption failed: %s\n",gpg_errstr(rc) );
+ "symmetric encryption failed: %s\n",g10_errstr(rc) );
break;
case aEncr: /* encrypt the given file */
if( argc > 1 )
wrong_args(_("--encrypt [filename]"));
if( (rc = encode_crypt(fname,remusr)) )
- log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), gpg_errstr(rc) );
+ log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
+ case aEncrFiles: /* encrypt the given files */
+ encode_crypt_files(argc, argv, remusr);
+ break;
+
case aSign: /* sign the given file */
sl = NULL;
if( detached_sig ) { /* sign all files */
@@ -1204,12 +1812,12 @@ main( int argc, char **argv )
if( argc > 1 )
wrong_args(_("--sign [filename]"));
if( argc ) {
- sl = gcry_xcalloc( 1, sizeof *sl + strlen(fname));
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
strcpy(sl->d, fname);
}
}
if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
- log_error("signing failed: %s\n", gpg_errstr(rc) );
+ log_error("signing failed: %s\n", g10_errstr(rc) );
free_strlist(sl);
break;
@@ -1217,47 +1825,60 @@ main( int argc, char **argv )
if( argc > 1 )
wrong_args(_("--sign --encrypt [filename]"));
if( argc ) {
- sl = gcry_xcalloc( 1, sizeof *sl + strlen(fname));
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
strcpy(sl->d, fname);
}
else
sl = NULL;
if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
- log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), gpg_errstr(rc) );
+ log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
free_strlist(sl);
break;
+ case aSignSym: /* sign and conventionally encrypt the given file */
+ if (argc > 1)
+ wrong_args(_("--sign --symmetric [filename]"));
+ rc = sign_symencrypt_file (fname, locusr);
+ if (rc)
+ log_error("%s: sign+symmetric failed: %s\n",
+ print_fname_stdin(fname), g10_errstr(rc) );
+ break;
+
case aClearsign: /* make a clearsig */
if( argc > 1 )
wrong_args(_("--clearsign [filename]"));
if( (rc = clearsign_file(fname, locusr, NULL)) )
- log_error("%s: clearsign failed: %s\n", print_fname_stdin(fname), gpg_errstr(rc) );
+ log_error("%s: clearsign failed: %s\n",
+ print_fname_stdin(fname), g10_errstr(rc) );
break;
case aVerify:
if( (rc = verify_signatures( argc, argv ) ))
- log_error("verify signatures failed: %s\n", gpg_errstr(rc) );
+ log_error("verify signatures failed: %s\n", g10_errstr(rc) );
break;
case aVerifyFiles:
if( (rc = verify_files( argc, argv ) ))
- log_error("verify files failed: %s\n", gpg_errstr(rc) );
+ log_error("verify files failed: %s\n", g10_errstr(rc) );
break;
case aDecrypt:
if( argc > 1 )
wrong_args(_("--decrypt [filename]"));
if( (rc = decrypt_message( fname ) ))
- log_error("decrypt_message failed: %s\n", gpg_errstr(rc) );
+ log_error("decrypt_message failed: %s\n", g10_errstr(rc) );
break;
-
+ case aDecryptFiles:
+ decrypt_messages(argc, argv);
+ break;
+
case aSignKey: /* sign the key given as argument */
if( argc != 1 )
wrong_args(_("--sign-key user-id"));
username = make_username( fname );
keyedit_menu(fname, locusr, NULL, 1 );
- gcry_free(username);
+ m_free(username);
break;
case aLSignKey:
@@ -1265,9 +1886,25 @@ main( int argc, char **argv )
wrong_args(_("--lsign-key user-id"));
username = make_username( fname );
keyedit_menu(fname, locusr, NULL, 2 );
- gcry_free(username);
+ m_free(username);
break;
+ case aNRSignKey:
+ if( argc != 1 )
+ wrong_args(_("--nrsign-key user-id"));
+ username = make_username( fname );
+ keyedit_menu(fname, locusr, NULL, 3 );
+ m_free(username);
+ break;
+
+ case aNRLSignKey:
+ if( argc != 1 )
+ wrong_args(_("--nrlsign-key user-id"));
+ username = make_username( fname );
+ keyedit_menu(fname, locusr, NULL, 4 );
+ m_free(username);
+ break;
+
case aEditKey: /* Edit a key signature */
if( !argc )
wrong_args(_("--edit-key user-id [commands]"));
@@ -1281,22 +1918,22 @@ main( int argc, char **argv )
}
else
keyedit_menu(username, locusr, NULL, 0 );
- gcry_free(username);
+ m_free(username);
break;
- case aDeleteSecretKey:
- if( argc != 1 )
- wrong_args(_("--delete-secret-key user-id"));
- case aDeleteKey:
- if( argc != 1 )
- wrong_args(_("--delete-key user-id"));
- username = make_username( fname );
- if( (rc = delete_key(username, cmd==aDeleteSecretKey)) )
- log_error("%s: delete key failed: %s\n", username, gpg_errstr(rc) );
- gcry_free(username);
+ case aDeleteKeys:
+ case aDeleteSecretKeys:
+ case aDeleteSecretAndPublicKeys:
+ sl = NULL;
+ /* I'm adding these in reverse order as add_to_strlist2
+ reverses them again, and it's easier to understand in the
+ proper order :) */
+ for( ; argc; argc-- )
+ add_to_strlist2( &sl, argv[argc-1], utf8_strings );
+ delete_keys(sl,cmd==aDeleteSecretKeys,cmd==aDeleteSecretAndPublicKeys);
+ free_strlist(sl);
break;
-
case aCheckKeys:
opt.check_sigs = 1;
case aListSigs:
@@ -1332,7 +1969,7 @@ main( int argc, char **argv )
else {
/* add keyring (default keyrings are not registered in this
* special case */
- add_keyblock_resource( argv[1], 0, 0 );
+ keydb_add_resource( argv[1], 0, 0 );
sl = NULL;
if (**argv)
add_to_strlist2( &sl, *argv, utf8_strings );
@@ -1359,7 +1996,7 @@ main( int argc, char **argv )
case aFastImport:
case aImport:
- import_keys( argc? argv:NULL, argc, (cmd == aFastImport) );
+ import_keys( argc? argv:NULL, argc, (cmd == aFastImport), NULL );
break;
case aExport:
@@ -1370,14 +2007,31 @@ main( int argc, char **argv )
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
if( cmd == aSendKeys )
- hkp_export( sl );
+ keyserver_export( sl );
else if( cmd == aRecvKeys )
- hkp_import( sl );
+ keyserver_import( sl );
else
export_pubkeys( sl, (cmd == aExport) );
free_strlist(sl);
break;
+ case aSearchKeys:
+ sl = NULL;
+ for( ; argc; argc--, argv++ )
+ append_to_strlist2( &sl, *argv, utf8_strings );
+
+ keyserver_search( sl );
+ free_strlist(sl);
+ break;
+
+ case aRefreshKeys:
+ sl = NULL;
+ for( ; argc; argc--, argv++ )
+ add_to_strlist2( &sl, *argv, utf8_strings );
+ keyserver_refresh(sl);
+ free_strlist(sl);
+ break;
+
case aExportSecret:
sl = NULL;
for( ; argc; argc--, argv++ )
@@ -1399,7 +2053,15 @@ main( int argc, char **argv )
wrong_args("--gen-revoke user-id");
username = make_username(*argv);
gen_revoke( username );
- gcry_free( username );
+ m_free( username );
+ break;
+
+ case aDesigRevoke:
+ if( argc != 1 )
+ wrong_args("--desig-revoke user-id");
+ username = make_username(*argv);
+ gen_desig_revoke( username );
+ m_free( username );
break;
case aDeArmor:
@@ -1407,7 +2069,7 @@ main( int argc, char **argv )
wrong_args("--dearmor [file]");
rc = dearmor_file( argc? *argv: NULL );
if( rc )
- log_error(_("dearmoring failed: %s\n"), gpg_errstr(rc));
+ log_error(_("dearmoring failed: %s\n"), g10_errstr(rc));
break;
case aEnArmor:
@@ -1415,17 +2077,12 @@ main( int argc, char **argv )
wrong_args("--enarmor [file]");
rc = enarmor_file( argc? *argv: NULL );
if( rc )
- log_error(_("enarmoring failed: %s\n"), gpg_errstr(rc));
+ log_error(_("enarmoring failed: %s\n"), g10_errstr(rc));
break;
case aPrimegen:
- {
- #if 1
- log_error( "command is currently not implemented\n");
- #else
- /* FIXME: disabled until we have an API to create primes */
- int mode = argc < 2 ? 0 : atoi(*argv);
+ { int mode = argc < 2 ? 0 : atoi(*argv);
if( mode == 1 && argc == 2 ) {
mpi_print( stdout, generate_public_prime( atoi(argv[1]) ), 1);
@@ -1450,12 +2107,11 @@ main( int argc, char **argv )
atoi(argv[2]), g, NULL ), 1);
putchar('\n');
mpi_print( stdout, g, 1 );
- mpi_release(g);
+ mpi_free(g);
}
else
wrong_args("--gen-prime mode bits [qbits] ");
putchar('\n');
- #endif
}
break;
@@ -1470,17 +2126,33 @@ main( int argc, char **argv )
while( endless || count ) {
byte *p;
- size_t n = !endless && count < 100? count : 100;
+ /* Wee need a multiple of 3, so that in case of
+ armored output we get a correct string. No
+ linefolding is done, as it is best to levae this to
+ other tools */
+ size_t n = !endless && count < 99? count : 99;
- p = gcry_random_bytes( n, level );
+ p = get_random_bits( n*8, level, 0);
#ifdef HAVE_DOSISH_SYSTEM
setmode ( fileno(stdout), O_BINARY );
#endif
- fwrite( p, n, 1, stdout );
- gcry_free(p);
+ if (opt.armor) {
+ char *tmp = make_radix64_string (p, n);
+ fputs (tmp, stdout);
+ m_free (tmp);
+ if (n%3 == 1)
+ putchar ('=');
+ if (n%3)
+ putchar ('=');
+ } else {
+ fwrite( p, n, 1, stdout );
+ }
+ m_free(p);
if( !endless )
count -= n;
}
+ if (opt.armor)
+ putchar ('\n');
}
break;
@@ -1489,53 +2161,28 @@ main( int argc, char **argv )
wrong_args("--print-md algo [files]");
{
int all_algos = (**argv=='*' && !(*argv)[1]);
- int algo = all_algos? 0 : gcry_md_map_name(*argv);
-
- if( !algo && !all_algos )
- log_error(_("invalid hash algorithm `%s'\n"), *argv );
- else {
- argc--; argv++;
- if( !argc )
- print_mds(NULL, algo, NULL);
- else {
- for(; argc; argc--, argv++ )
- print_mds(*argv, algo, NULL);
- }
- }
- }
- break;
-
- case aPrintHMAC:
- if( argc < 2 )
- wrong_args("--print-hmac hash-algo key [files]");
- {
- int all_algos = (**argv=='*' && !(*argv)[1]);
- int algo = all_algos? 0 : gcry_md_map_name(*argv);
+ int algo = all_algos? 0 : string_to_digest_algo(*argv);
if( !algo && !all_algos )
log_error(_("invalid hash algorithm `%s'\n"), *argv );
else {
- const char *key;
- argc--; argv++;
- key = *argv;
argc--; argv++;
if( !argc )
- print_mds(NULL, algo, key );
+ print_mds(NULL, algo);
else {
for(; argc; argc--, argv++ )
- print_mds(*argv, algo, key );
+ print_mds(*argv, algo);
}
}
}
break;
-
case aPrintMDs: /* old option */
if( !argc )
- print_mds(NULL,0,NULL);
+ print_mds(NULL,0);
else {
for(; argc; argc--, argv++ )
- print_mds(*argv,0,NULL);
+ print_mds(*argv,0);
}
break;
@@ -1555,15 +2202,8 @@ main( int argc, char **argv )
break;
case aCheckTrustDB:
- if( !argc )
- check_trustdb(NULL);
- else {
- for( ; argc; argc--, argv++ ) {
- username = make_username( *argv );
- check_trustdb( username );
- gcry_free(username);
- }
- }
+ /* Old versions allowed for arguments - ignore them */
+ check_trustdb();
break;
case aFixTrustDB:
@@ -1578,7 +2218,7 @@ main( int argc, char **argv )
for( ; argc; argc--, argv++ ) {
username = make_username( *argv );
list_trust_path( username );
- gcry_free(username);
+ m_free(username);
}
break;
@@ -1593,9 +2233,21 @@ main( int argc, char **argv )
wrong_args("--import-ownertrust [file]");
import_ownertrust( argc? *argv:NULL );
break;
+
+ case aPipeMode:
+ if ( argc )
+ wrong_args ("--pipemode");
+ run_in_pipemode ();
+ break;
+
+ case aRebuildKeydbCaches:
+ if (argc)
+ wrong_args ("--rebuild-keydb-caches");
+ keydb_rebuild_caches ();
+ break;
case aListPackets:
- opt.list_packets=1;
+ opt.list_packets=2;
default:
if( argc > 1 )
wrong_args(_("[filename]"));
@@ -1620,7 +2272,7 @@ main( int argc, char **argv )
}
rc = proc_packets(NULL, a );
if( rc )
- log_error("processing message failed: %s\n", gpg_errstr(rc) );
+ log_error("processing message failed: %s\n", g10_errstr(rc) );
iobuf_close(a);
}
break;
@@ -1629,28 +2281,24 @@ main( int argc, char **argv )
/* cleanup */
FREE_STRLIST(remusr);
FREE_STRLIST(locusr);
- gpg_exit(0);
+ g10_exit(0);
return 8; /*NEVER REACHED*/
}
void
-gpg_exit( int rc )
+g10_exit( int rc )
{
- #if 0
- #warning no update_random_seed_file
update_random_seed_file();
- #endif
if( opt.debug & DBG_MEMSTAT_VALUE ) {
- gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
- gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
+ m_print_stats("on exit");
+ random_dump_stats();
}
if( opt.debug )
- gcry_control( GCRYCTL_DUMP_SECMEM_STATS );
- gcry_control( GCRYCTL_TERM_SECMEM );
+ secmem_dump_stats();
+ secmem_term();
rc = rc? rc : log_get_errorcount(0)? 2 :
- gpg_errors_seen? 1 : 0;
- /*write_status( STATUS_LEAVE );*/
+ g10_errors_seen? 1 : 0;
exit(rc );
}
@@ -1692,71 +2340,106 @@ print_hex( byte *p, size_t n )
}
static void
-print_mds( const char *fname, int algo, const char *key )
+print_hashline( MD_HANDLE md, int algo, const char *fname )
+{
+ int i, n;
+ const byte *p;
+
+ if ( fname ) {
+ for (p = fname; *p; p++ ) {
+ if ( *p <= 32 || *p > 127 || *p == ':' || *p == '%' )
+ printf("%%%02X", *p );
+ else
+ putchar( *p );
+ }
+ }
+ putchar(':');
+ printf("%d:", algo );
+ p = md_read( md, algo );
+ n = md_digest_length(algo);
+ for(i=0; i < n ; i++, p++ )
+ printf("%02X", *p );
+ putchar(':');
+ putchar('\n');
+}
+
+static void
+print_mds( const char *fname, int algo )
{
FILE *fp;
char buf[1024];
size_t n;
- GCRY_MD_HD md;
+ MD_HANDLE md;
char *pname;
- int have_tiger = 0;
if( !fname ) {
fp = stdin;
#ifdef HAVE_DOSISH_SYSTEM
setmode ( fileno(fp) , O_BINARY );
#endif
- pname = gcry_xstrdup("[stdin]: ");
+ pname = m_strdup("[stdin]: ");
}
else {
- pname = gcry_xmalloc(strlen(fname)+3);
+ pname = m_alloc(strlen(fname)+3);
strcpy(stpcpy(pname,fname),": ");
fp = fopen( fname, "rb" );
}
if( !fp ) {
log_error("%s%s\n", pname, strerror(errno) );
- gcry_free(pname);
+ m_free(pname);
return;
}
- md = gcry_md_open( 0, key? GCRY_MD_FLAG_HMAC : 0 );
+ md = md_open( 0, 0 );
if( algo )
- gcry_md_enable( md, algo );
+ md_enable( md, algo );
else {
- /* Fixme: this does not work with hmac */
- gcry_md_enable( md, GCRY_MD_MD5 );
- gcry_md_enable( md, GCRY_MD_SHA1 );
- gcry_md_enable( md, GCRY_MD_RMD160 );
- have_tiger = !gcry_md_enable( md, GCRY_MD_TIGER );
+ md_enable( md, DIGEST_ALGO_MD5 );
+ md_enable( md, DIGEST_ALGO_SHA1 );
+ md_enable( md, DIGEST_ALGO_RMD160 );
+ if( !check_digest_algo(DIGEST_ALGO_TIGER) )
+ md_enable( md, DIGEST_ALGO_TIGER );
}
- if( key )
- gcry_md_setkey( md, key, strlen(key) );
while( (n=fread( buf, 1, DIM(buf), fp )) )
- gcry_md_write( md, buf, n );
+ md_write( md, buf, n );
if( ferror(fp) )
log_error("%s%s\n", pname, strerror(errno) );
else {
- if( algo ) {
- if( fname )
- fputs( pname, stdout );
- print_hex(gcry_md_read(md, algo), gcry_md_get_algo_dlen(algo) );
- }
- else {
- printf( "%s MD5 = ", fname?pname:"" );
- print_hex(gcry_md_read(md, GCRY_MD_MD5), 16 );
- printf("\n%s SHA1 = ", fname?pname:"" );
- print_hex(gcry_md_read(md, GCRY_MD_SHA1), 20 );
- printf("\n%sRMD160 = ", fname?pname:"" );
- print_hex(gcry_md_read(md, GCRY_MD_RMD160), 20 );
- if( have_tiger ) {
- printf("\n%s TIGER = ", fname?pname:"" );
- print_hex(gcry_md_read(md, GCRY_MD_TIGER), 24 );
- }
- }
- putchar('\n');
+ md_final(md);
+ if ( opt.with_colons ) {
+ if ( algo )
+ print_hashline( md, algo, fname );
+ else {
+ print_hashline( md, DIGEST_ALGO_MD5, fname );
+ print_hashline( md, DIGEST_ALGO_SHA1, fname );
+ print_hashline( md, DIGEST_ALGO_RMD160, fname );
+ if( !check_digest_algo(DIGEST_ALGO_TIGER) )
+ print_hashline( md, DIGEST_ALGO_TIGER, fname );
+ }
+ }
+ else {
+ if( algo ) {
+ if( fname )
+ fputs( pname, stdout );
+ print_hex(md_read(md, algo), md_digest_length(algo) );
+ }
+ else {
+ printf( "%s MD5 = ", fname?pname:"" );
+ print_hex(md_read(md, DIGEST_ALGO_MD5), 16 );
+ printf("\n%s SHA1 = ", fname?pname:"" );
+ print_hex(md_read(md, DIGEST_ALGO_SHA1), 20 );
+ printf("\n%sRMD160 = ", fname?pname:"" );
+ print_hex(md_read(md, DIGEST_ALGO_RMD160), 20 );
+ if( !check_digest_algo(DIGEST_ALGO_TIGER) ) {
+ printf("\n%s TIGER = ", fname?pname:"" );
+ print_hex(md_read(md, DIGEST_ALGO_TIGER), 24 );
+ }
+ }
+ putchar('\n');
+ }
}
- gcry_md_close(md);
+ md_close(md);
if( fp != stdin )
fclose(fp);
@@ -1765,41 +2448,35 @@ print_mds( const char *fname, int algo, const char *key )
/****************
* Check the supplied name,value string and add it to the notation
- * data to be used for signatures.
- */
+ * data to be used for signatures. which==0 for sig notations, and 1
+ * for cert notations.
+*/
static void
-add_notation_data( const char *string )
+add_notation_data( const char *string, int which )
{
const char *s;
- const char *s2;
- STRLIST sl;
+ STRLIST sl,*notation_data;
int critical=0;
int highbit=0;
+ if(which)
+ notation_data=&opt.cert_notation_data;
+ else
+ notation_data=&opt.sig_notation_data;
+
if( *string == '!' ) {
critical = 1;
string++;
}
- s = string;
- if( !*s || (*s & 0x80) || (!isalpha(*s) && *s != '_') ) {
- log_error(_("the first character of a notation name "
- "must be a letter or an underscore\n") );
- return;
- }
- for(s++; *s != '='; s++ ) {
- if( !*s || (*s & 0x80) || (!isalnum(*s) && *s != '_' && *s != '.' ) ) {
- log_error(_("a notation name must have only letters, "
- "digits, dots or underscores and end with an '='\n") );
+ for( s=string ; *s != '='; s++ ) {
+ if( !*s || (*s & 0x80) || (!isgraph(*s) && !isspace(*s)) ) {
+ log_error(_("a notation name must have only printable characters "
+ "or spaces, and end with an '='\n") );
return;
}
}
- if( s[-1] == '.' || ((s2=strstr(string, "..")) && s2 < s ) ) {
- log_error(_("dots in a notation name must be surrounded "
- "by other characters\n") );
- return;
- }
- /* we do only support printabe text - therefore we enforce the use
+ /* we only support printable text - therefore we enforce the use
* of only printable characters (an empty value is valid) */
for( s++; *s ; s++ ) {
if( iscntrl(*s) ) {
@@ -1812,26 +2489,44 @@ add_notation_data( const char *string )
}
if( highbit ) /* must use UTF8 encoding */
- sl = add_to_strlist2( &opt.notation_data, string, utf8_strings );
+ sl = add_to_strlist2( notation_data, string, utf8_strings );
else
- sl = add_to_strlist( &opt.notation_data, string );
+ sl = add_to_strlist( notation_data, string );
if( critical )
sl->flags |= 1;
}
-static int
-check_policy_url( const char *s )
+static void
+add_policy_url( const char *string, int which )
{
- if( *s == '!' )
- s++;
- if( !*s )
- return -1;
- for(; *s ; s++ ) {
- if( (*s & 0x80) || iscntrl(*s) )
- return -1;
+ int i,critical=0;
+ STRLIST sl;
+
+ if(*string=='!')
+ {
+ string++;
+ critical=1;
}
- return 0;
-}
+ for(i=0;i<strlen(string);i++)
+ if(string[i]&0x80 || iscntrl(string[i]))
+ break;
+
+ if(i==0 || i<strlen(string))
+ {
+ if(which)
+ log_error(_("the given certification policy URL is invalid\n"));
+ else
+ log_error(_("the given signature policy URL is invalid\n"));
+ }
+
+ if(which)
+ sl=add_to_strlist( &opt.cert_policy_url, string );
+ else
+ sl=add_to_strlist( &opt.sig_policy_url, string );
+
+ if(critical)
+ sl->flags |= 1;
+}
diff --git a/g10/getkey.c b/g10/getkey.c
index 8f38c4a34..87680502a 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,5 +1,5 @@
/* getkey.c - Get a key from the database
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,10 +24,9 @@
#include <string.h>
#include <assert.h>
#include <ctype.h>
-
#include "util.h"
#include "packet.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "iobuf.h"
#include "keydb.h"
#include "options.h"
@@ -35,81 +34,26 @@
#include "trustdb.h"
#include "i18n.h"
+#define MAX_PK_CACHE_ENTRIES 200
+#define MAX_UID_CACHE_ENTRIES 200
-#if 0
-#define MAX_UNK_CACHE_ENTRIES 1000 /* we use a linked list - so I guess
- * this is a reasonable limit */
-#define MAX_PK_CACHE_ENTRIES 50
+#if MAX_PK_CACHE_ENTRIES < 2
+ #error We need the cache for key creation
#endif
-#define MAX_UID_CACHE_ENTRIES 50
-
-/* A map of the all characters valid used for word_match()
- * Valid characters are in in this table converted to uppercase.
- * because the upper 128 bytes have special meaning, we assume
- * that they are all valid.
- * Note: We must use numerical values here in case that this program
- * will be converted to those little blue HAL9000s with their strange
- * EBCDIC character set (user ids are UTF-8).
- * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
- * we can run gpg now on a S/390 running GNU/Linux, where the code
- * translation is done by the device drivers?
- */
-static const byte word_match_chars[256] = {
- /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- /* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- /* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- /* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- /* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- /* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- /* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- /* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- /* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- /* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- /* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- /* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- /* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- /* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- /* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- /* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- /* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- /* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- /* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- /* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-};
-typedef struct {
- int mode;
- u32 keyid[2];
- byte fprint[20];
- char *namebuf;
- const char *name;
-} getkey_item_t;
struct getkey_ctx_s {
- /* make an array or a linked list from dome fields */
- int primary;
+ int exact;
KBNODE keyblock;
- KBPOS kbpos;
+ KBPOS kbpos;
KBNODE found_key; /* pointer into some keyblock */
int last_rc;
int req_usage;
int req_algo;
- ulong count;
+ KEYDB_HANDLE kr_handle;
int not_allocated;
int nitems;
- getkey_item_t items[1];
+ KEYDB_SEARCH_DESC items[1];
};
#if 0
@@ -127,12 +71,6 @@ typedef struct keyid_list {
} *keyid_list_t;
-#if MAX_UNK_CACHE_ENTRIES
- static keyid_list_t unknown_keyids;
- static int unk_cache_entries; /* number of entries in unknown keys cache */
- static int unk_cache_disabled;
-#endif
-
#if MAX_PK_CACHE_ENTRIES
typedef struct pk_cache_entry {
struct pk_cache_entry *next;
@@ -156,11 +94,9 @@ typedef struct user_id_db {
static user_id_db_t user_id_db;
static int uid_cache_entries; /* number of entries in uid cache */
-
-
-static char* prepare_word_match( const byte *name );
-static int lookup( GETKEY_CTX ctx, KBNODE *ret_kb, int secmode );
-
+static void merge_selfsigs( KBNODE keyblock );
+static int lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode );
+static int check_revocation_keys(PKT_public_key *pk,PKT_signature *sig);
#if 0
static void
@@ -180,7 +116,7 @@ print_stats()
#endif
-static void
+void
cache_public_key( PKT_public_key *pk )
{
#if MAX_PK_CACHE_ENTRIES
@@ -190,8 +126,11 @@ cache_public_key( PKT_public_key *pk )
if( pk_cache_disabled )
return;
+ if( pk->dont_cache )
+ return;
+
if( is_ELGAMAL(pk->pubkey_algo)
- || pk->pubkey_algo == GCRY_PK_DSA
+ || pk->pubkey_algo == PUBKEY_ALGO_DSA
|| is_RSA(pk->pubkey_algo) ) {
keyid_from_pk( pk, keyid );
}
@@ -213,7 +152,7 @@ cache_public_key( PKT_public_key *pk )
return;
}
pk_cache_entries++;
- ce = gcry_xmalloc( sizeof *ce );
+ ce = m_alloc( sizeof *ce );
ce->next = pk_cache;
pk_cache = ce;
ce->pk = copy_public_key( NULL, pk );
@@ -222,6 +161,7 @@ cache_public_key( PKT_public_key *pk )
#endif
}
+
/*
* Return the user ID from the given keyblock.
* We use the primary uid flag which has been set by the merge_selfsigs
@@ -232,16 +172,21 @@ static const char *
get_primary_uid ( KBNODE keyblock, size_t *uidlen )
{
KBNODE k;
+ const char *s;
for (k=keyblock; k; k=k->next ) {
if ( k->pkt->pkttype == PKT_USER_ID
+ && !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->is_primary ) {
*uidlen = k->pkt->pkt.user_id->len;
return k->pkt->pkt.user_id->name;
}
}
- *uidlen = 12;
- return "[No user ID]";
+ /* fixme: returning translatable constants instead of a user ID is
+ * not good because they are probably not utf-8 encoded. */
+ s = _("[User id not found]");
+ *uidlen = strlen (s);
+ return s;
}
@@ -250,7 +195,7 @@ release_keyid_list ( keyid_list_t k )
{
while ( k ) {
keyid_list_t k2 = k->next;
- gcry_free (k);
+ m_free (k);
k = k2;
}
}
@@ -259,7 +204,7 @@ release_keyid_list ( keyid_list_t k )
* Store the association of keyid and userid
* Feed only public keys to this function.
*/
-void
+static void
cache_user_id( KBNODE keyblock )
{
user_id_db_t r;
@@ -271,7 +216,7 @@ cache_user_id( KBNODE keyblock )
for (k=keyblock; k; k = k->next ) {
if ( k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- keyid_list_t a = gcry_xcalloc ( 1, sizeof *a );
+ keyid_list_t a = m_alloc_clear ( sizeof *a );
/* Hmmm: For a long list of keyids it might be an advantage
* to append the keys */
keyid_from_pk( k->pkt->pkt.public_key, a->keyid );
@@ -284,7 +229,7 @@ cache_user_id( KBNODE keyblock )
if( DBG_CACHE )
log_debug("cache_user_id: already in cache\n");
release_keyid_list ( keyids );
- gcry_free ( a );
+ m_free ( a );
return;
}
}
@@ -305,10 +250,10 @@ cache_user_id( KBNODE keyblock )
r = user_id_db;
user_id_db = r->next;
release_keyid_list ( r->keyids );
- gcry_free(r);
+ m_free(r);
uid_cache_entries--;
}
- r = gcry_xmalloc( sizeof *r + uidlen-1 );
+ r = m_alloc( sizeof *r + uidlen-1 );
r->keyids = keyids;
r->len = uidlen;
memcpy(r->name, uid, r->len);
@@ -321,17 +266,6 @@ cache_user_id( KBNODE keyblock )
void
getkey_disable_caches()
{
- #if MAX_UNK_CACHE_ENTRIES
- {
- keyid_list_t kl, kl2;
- for( kl = unknown_keyids; kl; kl = kl2 ) {
- kl2 = kl->next;
- gcry_free(kl);
- }
- unknown_keyids = NULL;
- unk_cache_disabled = 1;
- }
- #endif
#if MAX_PK_CACHE_ENTRIES
{
pk_cache_entry_t ce, ce2;
@@ -339,7 +273,7 @@ getkey_disable_caches()
for( ce = pk_cache; ce; ce = ce2 ) {
ce2 = ce->next;
free_public_key( ce->pk );
- gcry_free( ce );
+ m_free( ce );
}
pk_cache_disabled=1;
pk_cache_entries = 0;
@@ -351,15 +285,14 @@ getkey_disable_caches()
static void
-pk_from_block ( GETKEY_CTX ctx,
- PKT_public_key *pk, KBNODE keyblock, const char *namehash )
+pk_from_block ( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE keyblock )
{
KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
assert ( a->pkt->pkttype == PKT_PUBLIC_KEY
|| a->pkt->pkttype == PKT_PUBLIC_SUBKEY );
- copy_public_key_new_namehash( pk, a->pkt->pkt.public_key, namehash);
+ copy_public_key ( pk, a->pkt->pkt.public_key );
}
static void
@@ -386,15 +319,6 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
int internal = 0;
int rc = 0;
- #if MAX_UNK_CACHE_ENTRIES
- { /* let's see whether we checked the keyid already */
- keyid_list_t kl;
- for( kl = unknown_keyids; kl; kl = kl->next )
- if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
- return GPGERR_NO_PUBKEY; /* already checked and not found */
- }
- #endif
-
#if MAX_PK_CACHE_ENTRIES
{ /* Try to get it from the cache */
pk_cache_entry_t ce;
@@ -409,7 +333,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
#endif
/* more init stuff */
if( !pk ) {
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
internal++;
}
@@ -418,16 +342,18 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
{ struct getkey_ctx_s ctx;
KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
+ ctx.exact = 1; /* use the key ID exactly as given */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
ctx.req_algo = pk->req_algo;
ctx.req_usage = pk->req_usage;
rc = lookup( &ctx, &kb, 0 );
if ( !rc ) {
- pk_from_block ( &ctx, pk, kb, NULL );
+ pk_from_block ( &ctx, pk, kb );
}
get_pubkey_end( &ctx );
release_kbnode ( kb );
@@ -435,26 +361,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
if( !rc )
goto leave;
- #if MAX_UNK_CACHE_ENTRIES
- /* not found: store it for future reference */
- if( unk_cache_disabled )
- ;
- else if( ++unk_cache_entries > MAX_UNK_CACHE_ENTRIES ) {
- unk_cache_disabled = 1;
- if( opt.verbose > 1 )
- log_info(_("too many entries in unk cache - disabled\n"));
- }
- else {
- keyid_list_t kl;
-
- kl = gcry_xmalloc( sizeof *kl );
- kl->keyid[0] = keyid[0];
- kl->keyid[1] = keyid[1];
- kl->next = unknown_keyids;
- unknown_keyids = kl;
- }
- #endif
- rc = GPGERR_NO_PUBKEY;
+ rc = G10ERR_NO_PUBKEY;
leave:
if( !rc )
@@ -473,11 +380,13 @@ get_pubkeyblock( u32 *keyid )
KBNODE keyblock = NULL;
memset( &ctx, 0, sizeof ctx );
+ /* no need to set exact here because we want the entire block */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
rc = lookup( &ctx, &keyblock, 0 );
get_pubkey_end( &ctx );
@@ -498,11 +407,13 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
+ ctx.exact = 1; /* use the key ID exactly as given */
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (1);
ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
+ ctx.items[0].u.kid[0] = keyid[0];
+ ctx.items[0].u.kid[1] = keyid[1];
ctx.req_algo = sk->req_algo;
ctx.req_usage = sk->req_usage;
rc = lookup( &ctx, &kb, 1 );
@@ -524,61 +435,30 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
/****************
- * Check whether the secret key is available
+ * Check whether the secret key is available. This is just a fast
+ * check and does not tell us whether the secret key is valid. It
+ * merely tells other whether there is some secret key.
* Returns: 0 := key is available
- * GPGERR_NO_SECKEY := not availabe
+ * G10ERR_NO_SECKEY := not availabe
*/
int
seckey_available( u32 *keyid )
{
int rc;
- struct getkey_ctx_s ctx;
- KBNODE kb = NULL;
+ KEYDB_HANDLE hd = keydb_new (1);
- memset( &ctx, 0, sizeof ctx );
- ctx.not_allocated = 1;
- ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
- rc = lookup( &ctx, &kb, 1 );
- get_seckey_end( &ctx );
- release_kbnode ( kb );
+ rc = keydb_search_kid (hd, keyid);
+ if ( rc == -1 )
+ rc = G10ERR_NO_SECKEY;
+ keydb_release (hd);
return rc;
}
-
-static int
-hextobyte( const byte *s )
-{
- int c;
-
- if( *s >= '0' && *s <= '9' )
- c = 16 * (*s - '0');
- else if( *s >= 'A' && *s <= 'F' )
- c = 16 * (10 + *s - 'A');
- else if( *s >= 'a' && *s <= 'f' )
- c = 16 * (10 + *s - 'a');
- else
- return -1;
- s++;
- if( *s >= '0' && *s <= '9' )
- c += *s - '0';
- else if( *s >= 'A' && *s <= 'F' )
- c += 10 + *s - 'A';
- else if( *s >= 'a' && *s <= 'f' )
- c += 10 + *s - 'a';
- else
- return -1;
- return c;
-}
-
-
-
/****************
* Return the type of the user id:
*
+ * Please use the constants KEYDB_SERCH_MODE_xxx
* 0 = Invalid user ID
* 1 = exact match
* 2 = match a substring
@@ -594,8 +474,6 @@ hextobyte( const byte *s )
* 21 = Unified fingerprint :fpr:pk_algo:
* (We don't use pk_algo yet)
*
- * if fprint is not NULL, it should be an array of at least 20 bytes.
- *
* Rules used:
* - If the username starts with 8,9,16 or 17 hex-digits (the first one
* must be in the range 0..9), this is considered a keyid; depending
@@ -620,16 +498,21 @@ hextobyte( const byte *s )
* is not case sensitive.
*/
-int
-classify_user_id( const char *name, u32 *keyid, byte *fprint,
- const char **retstr, size_t *retlen )
+static int
+classify_user_id2( const char *name,
+ KEYDB_SEARCH_DESC *desc,
+ int *force_exact )
{
- const char * s;
- int mode = 0;
- int hexprefix = 0;
- int hexlength;
-
- /* skip leading spaces. FIXME: what is with leading spaces? */
+ const char *s;
+ int hexprefix = 0;
+ int hexlength;
+ int mode = 0;
+
+ /* clear the structure so that the mode field is set to zero unless
+ * we set it to the correct value right at the end of this function */
+ memset (desc, 0, sizeof *desc);
+ *force_exact = 0;
+ /* skip leading spaces. Fixme: what is with trailing spaces? */
for(s = name; *s && isspace(*s); s++ )
;
@@ -638,42 +521,42 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
return 0;
case '.': /* an email address, compare from end */
- mode = 5;
+ mode = KEYDB_SEARCH_MODE_MAILEND;
s++;
+ desc->u.name = s;
break;
case '<': /* an email address */
- mode = 3;
+ mode = KEYDB_SEARCH_MODE_MAIL;
+ desc->u.name = s;
break;
case '@': /* part of an email address */
- mode = 4;
+ mode = KEYDB_SEARCH_MODE_MAILSUB;
s++;
+ desc->u.name = s;
break;
case '=': /* exact compare */
- mode = 1;
+ mode = KEYDB_SEARCH_MODE_EXACT;
s++;
+ desc->u.name = s;
break;
case '*': /* case insensitive substring search */
- mode = 2;
+ mode = KEYDB_SEARCH_MODE_SUBSTR;
s++;
+ desc->u.name = s;
break;
case '+': /* compare individual words */
- mode = 6;
+ mode = KEYDB_SEARCH_MODE_WORDS;
s++;
+ desc->u.name = s;
break;
case '#': /* local user id */
- mode = 12;
- s++;
- if (keyid) {
- if (keyid_from_lid(strtoul(s, NULL, 10), keyid))
- keyid[0] = keyid[1] = 0;
- }
- break;
+ return 0; /* This is now obsolete and van't not be used anymore*/
case ':': /*Unified fingerprint */
{
@@ -689,14 +572,12 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
}
if (i != 32 && i != 40)
return 0; /* invalid length of fpr*/
- if (fprint) {
- for (i=0,si=s; si < se; i++, si +=2)
- fprint[i] = hextobyte(si);
- for ( ; i < 20; i++)
- fprint[i]= 0;
- }
+ for (i=0,si=s; si < se; i++, si +=2)
+ desc->u.fpr[i] = hextobyte(si);
+ for ( ; i < 20; i++)
+ desc->u.fpr[i]= 0;
s = se + 1;
- mode = 21;
+ mode = KEYDB_SEARCH_MODE_FPR;
}
break;
@@ -707,6 +588,10 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
}
hexlength = strspn(s, "0123456789abcdefABCDEF");
+ if (hexlength >= 8 && s[hexlength] =='!') {
+ *force_exact = 1;
+ hexlength++; /* just for the following check */
+ }
/* check if a hexadecimal number is terminated by EOS or blank */
if (hexlength && s[hexlength] && !isspace(s[hexlength])) {
@@ -716,16 +601,17 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
hexlength = 0; /* a hex number, but really were not. */
}
+ if (*force_exact)
+ hexlength--;
+
if (hexlength == 8
|| (!hexprefix && hexlength == 9 && *s == '0')){
/* short keyid */
if (hexlength == 9)
s++;
- if (keyid) {
- keyid[0] = 0;
- keyid[1] = strtoul( s, NULL, 16 );
- }
- mode = 10;
+ desc->u.kid[0] = 0;
+ desc->u.kid[1] = strtoul( s, NULL, 16 );
+ mode = KEYDB_SEARCH_MODE_SHORT_KID;
}
else if (hexlength == 16
|| (!hexprefix && hexlength == 17 && *s == '0')) {
@@ -734,9 +620,9 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
if (hexlength == 17)
s++;
mem2str(buf, s, 9 );
- keyid[0] = strtoul( buf, NULL, 16 );
- keyid[1] = strtoul( s+8, NULL, 16 );
- mode = 11;
+ desc->u.kid[0] = strtoul( buf, NULL, 16 );
+ desc->u.kid[1] = strtoul( s+8, NULL, 16 );
+ mode = KEYDB_SEARCH_MODE_LONG_KID;
}
else if (hexlength == 32 || (!hexprefix && hexlength == 33
&& *s == '0')) {
@@ -744,16 +630,14 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
int i;
if (hexlength == 33)
s++;
- if (fprint) {
- memset(fprint+16, 4, 0);
- for (i=0; i < 16; i++, s+=2) {
- int c = hextobyte(s);
- if (c == -1)
- return 0;
- fprint[i] = c;
- }
- }
- mode = 16;
+ memset(desc->u.fpr+16, 0, 4);
+ for (i=0; i < 16; i++, s+=2) {
+ int c = hextobyte(s);
+ if (c == -1)
+ return 0;
+ desc->u.fpr[i] = c;
+ }
+ mode = KEYDB_SEARCH_MODE_FPR16;
}
else if (hexlength == 40 || (!hexprefix && hexlength == 41
&& *s == '0')) {
@@ -761,131 +645,140 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
int i;
if (hexlength == 41)
s++;
- if (fprint) {
- for (i=0; i < 20; i++, s+=2) {
- int c = hextobyte(s);
- if (c == -1)
- return 0;
- fprint[i] = c;
- }
- }
- mode = 20;
+ for (i=0; i < 20; i++, s+=2) {
+ int c = hextobyte(s);
+ if (c == -1)
+ return 0;
+ desc->u.fpr[i] = c;
+ }
+ mode = KEYDB_SEARCH_MODE_FPR20;
}
else {
if (hexprefix) /* This was a hex number with a prefix */
return 0; /* and a wrong length */
- mode = 2; /* Default is case insensitive substring search */
+ *force_exact = 0;
+ desc->u.name = s;
+ mode = KEYDB_SEARCH_MODE_SUBSTR; /* default mode */
}
}
- if( retstr )
- *retstr = s;
- if( retlen )
- *retlen = strlen(s);
-
+ desc->mode = mode;
return mode;
}
+int
+classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc)
+{
+ int dummy;
+ KEYDB_SEARCH_DESC dummy_desc;
+ if (!desc)
+ desc = &dummy_desc;
+ return classify_user_id2 (name, desc, &dummy);
+}
/****************
* Try to get the pubkey by the userid. This function looks for the
* first pubkey certificate which has the given name in a user_id.
* if pk/sk has the pubkey algo set, the function will only return
* a pubkey with that algo.
- * The caller must provide provide storage for either the pk or the sk.
- * If ret_kb is not NULL the funtion will return the keyblock there.
+ * The caller should provide storage for either the pk or the sk.
+ * If ret_kb is not NULL the function will return the keyblock there.
*/
static int
key_byname( GETKEY_CTX *retctx, STRLIST namelist,
- PKT_public_key *pk, PKT_secret_key *sk, KBNODE *ret_kb )
+ PKT_public_key *pk, PKT_secret_key *sk, int secmode,
+ KBNODE *ret_kb, KEYDB_HANDLE *ret_kdbhd )
{
int rc = 0;
int n;
STRLIST r;
GETKEY_CTX ctx;
KBNODE help_kb = NULL;
+ int exact;
- if( retctx ) /* reset the returned context in case of error */
+ if( retctx ) {/* reset the returned context in case of error */
+ assert (!ret_kdbhd); /* not allowed because the handle is
+ stored in the context */
*retctx = NULL;
+ }
+ if (ret_kdbhd)
+ *ret_kdbhd = NULL;
/* build the search context */
- /* Performance hint: Use a static buffer if there is only one name */
- /* and we don't have mode 6 */
for(n=0, r=namelist; r; r = r->next )
n++;
- ctx = gcry_xcalloc( 1, sizeof *ctx + (n-1)*sizeof ctx->items );
+ ctx = m_alloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items );
ctx->nitems = n;
for(n=0, r=namelist; r; r = r->next, n++ ) {
- int mode = classify_user_id( r->d,
- ctx->items[n].keyid,
- ctx->items[n].fprint,
- &ctx->items[n].name,
- NULL );
-
- /* if we don't use one of the exact key specifications, we assume that
- * the primary key is requested */
- if ( mode != 10 && mode != 11
- && mode != 16 && mode == 20 && mode != 21 )
- ctx->primary = 1;
-
- ctx->items[n].mode = mode;
- if( !ctx->items[n].mode ) {
- gcry_free( ctx );
- return GPGERR_INV_USER_ID;
- }
- if( ctx->items[n].mode == 6 ) {
- ctx->items[n].namebuf = prepare_word_match(ctx->items[n].name);
- ctx->items[n].name = ctx->items[n].namebuf;
+ classify_user_id2 (r->d, &ctx->items[n], &exact);
+
+ if (exact)
+ ctx->exact = 1;
+ if (!ctx->items[n].mode) {
+ m_free (ctx);
+ return G10ERR_INV_USER_ID;
}
}
-
-
+ ctx->kr_handle = keydb_new (secmode);
if ( !ret_kb )
ret_kb = &help_kb;
- if( sk ) {
+ if( secmode ) {
+ if (sk) {
+ ctx->req_algo = sk->req_algo;
+ ctx->req_usage = sk->req_usage;
+ }
rc = lookup( ctx, ret_kb, 1 );
if ( !rc && sk ) {
sk_from_block ( ctx, sk, *ret_kb );
}
}
else {
-
+ if (pk) {
+ ctx->req_algo = pk->req_algo;
+ ctx->req_usage = pk->req_usage;
+ }
rc = lookup( ctx, ret_kb, 0 );
if ( !rc && pk ) {
- pk_from_block ( ctx, pk, *ret_kb, NULL /* FIXME need to get the namehash*/ );
+ pk_from_block ( ctx, pk, *ret_kb );
}
}
release_kbnode ( help_kb );
- if( retctx ) /* caller wants the context */
+ if (retctx) /* caller wants the context */
*retctx = ctx;
else {
- /* Hmmm, why not get_pubkey-end here?? */
- enum_keyblocks_end( ctx->kbpos ); ctx->kbpos = NULL;
- for(n=0; n < ctx->nitems; n++ )
- gcry_free( ctx->items[n].namebuf );
- gcry_free( ctx );
+ if (ret_kdbhd) {
+ *ret_kdbhd = ctx->kr_handle;
+ ctx->kr_handle = NULL;
+ }
+ get_pubkey_end (ctx);
}
return rc;
}
+/*
+ * Find a public key from NAME and returh the keyblock or the key.
+ * If ret_kdb is not NULL, the KEYDB handle used to locate this keyblock is
+ * returned and the caller is responsible for closing it.
+ */
int
-get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
- const char *name, KBNODE *ret_keyblock )
+get_pubkey_byname (PKT_public_key *pk,
+ const char *name, KBNODE *ret_keyblock,
+ KEYDB_HANDLE *ret_kdbhd )
{
int rc;
STRLIST namelist = NULL;
add_to_strlist( &namelist, name );
- rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
+ rc = key_byname( NULL, namelist, pk, NULL, 0, ret_keyblock, ret_kdbhd);
free_strlist( namelist );
return rc;
}
@@ -894,7 +787,7 @@ int
get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock )
{
- return key_byname( retctx, names, pk, NULL, ret_keyblock );
+ return key_byname( retctx, names, pk, NULL, 0, ret_keyblock, NULL);
}
int
@@ -904,7 +797,7 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
rc = lookup( ctx, ret_keyblock, 0 );
if ( !rc && pk && ret_keyblock )
- pk_from_block ( ctx, pk, *ret_keyblock, NULL );
+ pk_from_block ( ctx, pk, *ret_keyblock );
return rc;
}
@@ -914,70 +807,15 @@ void
get_pubkey_end( GETKEY_CTX ctx )
{
if( ctx ) {
- int n;
-
- enum_keyblocks_end( ctx->kbpos ); ctx->kbpos = NULL;
- for(n=0; n < ctx->nitems; n++ )
- gcry_free( ctx->items[n].namebuf );
+ memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
+ keydb_release (ctx->kr_handle);
if( !ctx->not_allocated )
- gcry_free( ctx );
+ m_free( ctx );
}
}
-/****************
- * Combined function to search for a username and get the position
- * of the keyblock.
- */
-int
-find_keyblock_byname( KBNODE *retblock, const char *username )
-{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- int rc;
-
- rc = get_pubkey_byname( NULL, pk, username, retblock );
- free_public_key(pk);
- return rc;
-}
-
-
-/****************
- * Combined function to search for a key and get the position
- * of the keyblock. Used for merging while importing keys.
- */
-int
-find_keyblock_bypk( KBNODE *retblock, PKT_public_key *pk )
-{
- char ufpr[50];
-
- unified_fingerprint_from_pk( pk, ufpr, sizeof ufpr );
- return find_keyblock_byname( retblock, ufpr );
-}
-
-int
-find_kblocation_bypk( void *re_opaque, PKT_public_key *pk )
-{
- PKT_public_key *dummy_pk = gcry_xcalloc( 1, sizeof *pk );
- char ufpr[50];
- GETKEY_CTX ctx;
- int rc;
-
- unified_fingerprint_from_pk( pk, ufpr, sizeof ufpr );
- /* FIXME: There is no need to return any informaton, we just
- * wnat to know the location. Using the general lookup function
- * has the problem that we might not get the key becuase it has expired
- * or due to some similar probelm. A solotion would be a locate-only
- * flag in the ctx */
- rc = get_pubkey_byname( &ctx, dummy_pk, ufpr, NULL );
- free_public_key(dummy_pk);
- if ( !rc )
- ringedit_copy_kbpos( re_opaque, ctx->kbpos );
- get_pubkey_end( ctx );
-
- return rc;
-}
-
/****************
* Search for a key with the given fingerprint.
@@ -996,18 +834,21 @@ get_pubkey_byfprint( PKT_public_key *pk,
KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
+ ctx.exact = 1 ;
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = fprint_len;
- memcpy( ctx.items[0].fprint, fprint, fprint_len );
+ ctx.items[0].mode = fprint_len==16? KEYDB_SEARCH_MODE_FPR16
+ : KEYDB_SEARCH_MODE_FPR20;
+ memcpy( ctx.items[0].u.fpr, fprint, fprint_len );
rc = lookup( &ctx, &kb, 0 );
if (!rc && pk )
- pk_from_block ( &ctx, pk, kb, NULL );
+ pk_from_block ( &ctx, pk, kb );
release_kbnode ( kb );
get_pubkey_end( &ctx );
}
else
- rc = GPGERR_GENERAL; /* Oops */
+ rc = G10ERR_GENERAL; /* Oops */
return rc;
}
@@ -1026,54 +867,27 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (0);
ctx.nitems = 1;
- ctx.items[0].mode = fprint_len;
- memcpy( ctx.items[0].fprint, fprint, fprint_len );
+ ctx.items[0].mode = fprint_len==16? KEYDB_SEARCH_MODE_FPR16
+ : KEYDB_SEARCH_MODE_FPR20;
+ memcpy( ctx.items[0].u.fpr, fprint, fprint_len );
rc = lookup( &ctx, ret_keyblock, 0 );
get_pubkey_end( &ctx );
}
else
- rc = GPGERR_GENERAL; /* Oops */
+ rc = G10ERR_GENERAL; /* Oops */
return rc;
}
-
-/****************
- * Search for a key with the given lid and return the entire keyblock
- */
-int
-get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
-{
- int rc;
- struct getkey_ctx_s ctx;
- u32 kid[2];
-
- if( keyid_from_lid( lid, kid ) )
- kid[0] = kid[1] = 0;
- memset( &ctx, 0, sizeof ctx );
- ctx.not_allocated = 1;
- ctx.nitems = 1;
- ctx.items[0].mode = 12;
- ctx.items[0].keyid[0] = kid[0];
- ctx.items[0].keyid[1] = kid[1];
- rc = lookup( &ctx, ret_keyblock, 0 );
- get_pubkey_end( &ctx );
-
- return rc;
-}
-
-
-
-
-
/****************
* Get a secret key by name and store it into sk
* If NAME is NULL use the default key
*/
-int
-get_seckey_byname( GETKEY_CTX *retctx,
+static int
+get_seckey_byname2( GETKEY_CTX *retctx,
PKT_secret_key *sk, const char *name, int unprotect,
KBNODE *retblock )
{
@@ -1082,7 +896,7 @@ get_seckey_byname( GETKEY_CTX *retctx,
if( !name && opt.def_secret_key && *opt.def_secret_key ) {
add_to_strlist( &namelist, opt.def_secret_key );
- rc = key_byname( retctx, namelist, NULL, sk, retblock );
+ rc = key_byname( retctx, namelist, NULL, sk, 1, retblock, NULL );
}
else if( !name ) { /* use the first one as default key */
struct getkey_ctx_s ctx;
@@ -1092,9 +906,9 @@ get_seckey_byname( GETKEY_CTX *retctx,
assert (!retblock);
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
- ctx.primary = 1;
+ ctx.kr_handle = keydb_new (1);
ctx.nitems = 1;
- ctx.items[0].mode = 15;
+ ctx.items[0].mode = KEYDB_SEARCH_MODE_FIRST;
rc = lookup( &ctx, &kb, 1 );
if (!rc && sk )
sk_from_block ( &ctx, sk, kb );
@@ -1103,7 +917,7 @@ get_seckey_byname( GETKEY_CTX *retctx,
}
else {
add_to_strlist( &namelist, name );
- rc = key_byname( retctx, namelist, NULL, sk, retblock );
+ rc = key_byname( retctx, namelist, NULL, sk, 1, retblock, NULL );
}
free_strlist( namelist );
@@ -1114,11 +928,18 @@ get_seckey_byname( GETKEY_CTX *retctx,
return rc;
}
+int
+get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock )
+{
+ return get_seckey_byname2 ( NULL, sk, name, unlock, NULL );
+}
+
+
int
get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
STRLIST names, KBNODE *ret_keyblock )
{
- return key_byname( retctx, names, NULL, sk, ret_keyblock );
+ return key_byname( retctx, names, NULL, sk, 1, ret_keyblock, NULL );
}
@@ -1142,200 +963,41 @@ get_seckey_end( GETKEY_CTX ctx )
}
-
-/****************
- * Combined function to search for a username and get the position
- * of the keyblock. This function does not unprotect the secret key.
- */
-int
-find_secret_keyblock_byname( KBNODE *retblock, const char *username )
-{
- PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk );
- int rc;
-
- rc = get_seckey_byname( NULL, sk, username, 0, retblock );
- free_secret_key(sk);
- return rc;
-}
-
-
-
/****************
- * Combined function to search for a key and get the position
- * of the keyblock.
+ * Search for a key with the given fingerprint.
+ * FIXME:
+ * We should replace this with the _byname function. Thiscsan be done
+ * by creating a userID conforming to the unified fingerprint style.
*/
int
-find_keyblock_bysk( KBNODE *retblock, PKT_secret_key *sk )
-{
- char ufpr[50];
-
- unified_fingerprint_from_sk( sk, ufpr, sizeof ufpr );
- return find_secret_keyblock_byname( retblock, ufpr );
-}
-
-int
-find_kblocation_bysk( void *re_opaque, PKT_secret_key *sk )
+get_seckey_byfprint( PKT_secret_key *sk,
+ const byte *fprint, size_t fprint_len)
{
- PKT_secret_key *dummy_sk = gcry_xcalloc( 1, sizeof *sk );
- char ufpr[50];
- GETKEY_CTX ctx;
int rc;
-
- unified_fingerprint_from_sk( sk, ufpr, sizeof ufpr );
- rc = get_seckey_byname( &ctx, dummy_sk, ufpr, 0, NULL );
- free_secret_key(dummy_sk);
- if ( !rc )
- ringedit_copy_kbpos( re_opaque, &ctx->kbpos );
- get_seckey_end( ctx );
-
- return rc;
-}
-
-
-
-
-/*******************************************************
- ************** compare functions **********************
- *******************************************************/
-
-/****************
- * Do a word match (original user id starts with a '+').
- * The pattern is already tokenized to a more suitable format:
- * There are only the real words in it delimited by one space
- * and all converted to uppercase.
- *
- * Returns: 0 if all words match.
- *
- * Note: This algorithm is a straightforward one and not very
- * fast. It works for UTF-8 strings. The uidlen should
- * be removed but due to the fact that old versions of
- * pgp don't use UTF-8 we still use the length; this should
- * be fixed in parse-packet (and replace \0 by some special
- * UTF-8 encoding)
- */
-static int
-word_match( const byte *uid, size_t uidlen, const byte *pattern )
-{
- size_t wlen, n;
- const byte *p;
- const byte *s;
-
- for( s=pattern; *s; ) {
- do {
- /* skip leading delimiters */
- while( uidlen && !word_match_chars[*uid] )
- uid++, uidlen--;
- /* get length of the word */
- n = uidlen; p = uid;
- while( n && word_match_chars[*p] )
- p++, n--;
- wlen = p - uid;
- /* and compare against the current word from pattern */
- for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
- if( word_match_chars[*p] != s[n] )
- break;
- }
- if( n == wlen && (s[n] == ' ' || !s[n]) )
- break; /* found */
- uid += wlen;
- uidlen -= wlen;
- } while( uidlen );
- if( !uidlen )
- return -1; /* not found */
-
- /* advance to next word in pattern */
- for(; *s != ' ' && *s ; s++ )
- ;
- if( *s )
- s++ ;
- }
- return 0; /* found */
-}
-
-/****************
- * prepare word word_match; that is parse the name and
- * build the pattern.
- * caller has to free the returned pattern
- */
-static char*
-prepare_word_match( const byte *name )
-{
- byte *pattern, *p;
- int c;
-
- /* the original length is always enough for the pattern */
- p = pattern = gcry_xmalloc(strlen(name)+1);
- do {
- /* skip leading delimiters */
- while( *name && !word_match_chars[*name] )
- name++;
- /* copy as long as we don't have a delimiter and convert
- * to uppercase.
- * fixme: how can we handle utf8 uppercasing */
- for( ; *name && (c=word_match_chars[*name]); name++ )
- *p++ = c;
- *p++ = ' '; /* append pattern delimiter */
- } while( *name );
- p[-1] = 0; /* replace last pattern delimiter by EOS */
-
- return pattern;
-}
-
+ if( fprint_len == 20 || fprint_len == 16 ) {
+ struct getkey_ctx_s ctx;
+ KBNODE kb = NULL;
-
-
-static int
-compare_name( const char *uid, size_t uidlen, const char *name, int mode )
-{
- int i;
- const char *s, *se;
-
- if( mode == 1 ) { /* exact match */
- for(i=0; name[i] && uidlen; i++, uidlen-- )
- if( uid[i] != name[i] )
- break;
- if( !uidlen && !name[i] )
- return 0; /* found */
- }
- else if( mode == 2 ) { /* case insensitive substring */
- if( memistr( uid, uidlen, name ) )
- return 0;
- }
- else if( mode >= 3 && mode <= 5 ) { /* look at the email address */
- for( i=0, s= uid; i < uidlen && *s != '<'; s++, i++ )
- ;
- if( i < uidlen ) {
- /* skip opening delim and one char and look for the closing one*/
- s++; i++;
- for( se=s+1, i++; i < uidlen && *se != '>'; se++, i++ )
- ;
- if( i < uidlen ) {
- i = se - s;
- if( mode == 3 ) { /* exact email address */
- if( strlen(name)-2 == i && !memicmp( s, name+1, i) )
- return 0;
- }
- else if( mode == 4 ) { /* email substring */
- if( memistr( s, i, name ) )
- return 0;
- }
- else { /* email from end */
- /* nyi */
- }
- }
- }
+ memset( &ctx, 0, sizeof ctx );
+ ctx.exact = 1 ;
+ ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (1);
+ ctx.nitems = 1;
+ ctx.items[0].mode = fprint_len==16? KEYDB_SEARCH_MODE_FPR16
+ : KEYDB_SEARCH_MODE_FPR20;
+ memcpy( ctx.items[0].u.fpr, fprint, fprint_len );
+ rc = lookup( &ctx, &kb, 1 );
+ if (!rc && sk )
+ sk_from_block ( &ctx, sk, kb );
+ release_kbnode ( kb );
+ get_pubkey_end( &ctx );
}
- else if( mode == 6 )
- return word_match( uid, uidlen, name );
else
- BUG();
-
- return -1; /* not found */
+ rc = G10ERR_GENERAL; /* Oops */
+ return rc;
}
-
-
/************************************************
************* Merging stuff ********************
@@ -1344,7 +1006,11 @@ compare_name( const char *uid, size_t uidlen, const char *name, int mode )
/****************
* merge all selfsignatures with the keys.
* FIXME: replace this at least for the public key parts
- * by merge_selfsigs
+ * by merge_selfsigs.
+ * It is still used in keyedit.c and
+ * at 2 or 3 other places - check whether it is really needed.
+ * It might be needed by the key edit and import stuff because
+ * the keylock is changed.
*/
void
merge_keys_and_selfsig( KBNODE keyblock )
@@ -1356,6 +1022,13 @@ merge_keys_and_selfsig( KBNODE keyblock )
u32 kid[2] = { 0, 0 };
u32 sigdate = 0;
+ if (keyblock && keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ /* divert to our new function */
+ merge_selfsigs (keyblock);
+ return;
+ }
+ /* still need the old one because the new one can't handle secret keys */
+
for(k=keyblock; k; k = k->next ) {
if( k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
@@ -1394,7 +1067,7 @@ merge_keys_and_selfsig( KBNODE keyblock )
const byte *p;
u32 ed;
- p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
+ p = parse_sig_subpkt( sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL );
if( pk ) {
ed = p? pk->timestamp + buffer_to_u32(p):0;
if( sig->timestamp > sigdate ) {
@@ -1410,49 +1083,71 @@ merge_keys_and_selfsig( KBNODE keyblock )
}
}
}
+
+ if(pk && (pk->expiredate==0 ||
+ (pk->max_expiredate && pk->expiredate>pk->max_expiredate)))
+ pk->expiredate=pk->max_expiredate;
+
+ if(sk && (sk->expiredate==0 ||
+ (sk->max_expiredate && sk->expiredate>sk->max_expiredate)))
+ sk->expiredate=sk->max_expiredate;
}
}
-
+/*
+ * Apply information from SIGNODE (which is the valid self-signature
+ * associated with that UID) to the UIDNODE:
+ * - wether the UID has been revoked
+ * - assumed creation date of the UID
+ * - temporary store the keyflags here
+ * - temporary store the key expiration time here
+ * - mark whether the primary user ID flag hat been set.
+ * - store the preferences
+ */
static void
-fixup_uidnode ( KBNODE uidnode, KBNODE signode )
+fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
{
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
PKT_signature *sig = signode->pkt->pkt.signature;
- const byte *p;
- size_t n;
+ const byte *p, *sym, *hash, *zip;
+ size_t n, nsym, nhash, nzip;
uid->created = 0; /* not created == invalid */
- if ( !signode )
- return; /* no self-signature */
- if ( IS_UID_REV ( sig ) )
+ if ( IS_UID_REV ( sig ) ) {
+ uid->is_revoked = 1;
return; /* has been revoked */
+ }
+
+ uid->created = sig->timestamp; /* this one is okay */
+ uid->selfsigversion = sig->version;
+ /* If we got this far, it's not expired :) */
+ uid->is_expired = 0;
+ uid->expiredate = sig->expiredate;
- uid->created = sig->timestamp; /* this one is okay */
-
-
/* store the key flags in the helper variable for later processing */
uid->help_key_usage = 0;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
if ( p && n ) {
/* first octet of the keyflags */
if ( (*p & 3) )
- uid->help_key_usage |= GCRY_PK_USAGE_SIGN;
+ uid->help_key_usage |= PUBKEY_USAGE_SIG;
if ( (*p & 12) )
- uid->help_key_usage |= GCRY_PK_USAGE_ENCR;
+ uid->help_key_usage |= PUBKEY_USAGE_ENC;
+ /* Note: we do not set the CERT flag here because it can be assumed
+ * that thre is no real policy to set it. */
}
/* ditto or the key expiration */
uid->help_key_expire = 0;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
- if ( p ) {
- uid->help_key_expire = sig->timestamp + buffer_to_u32(p);
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if ( p ) {
+ uid->help_key_expire = keycreated + buffer_to_u32(p);
}
/* Set the primary user ID flag - we will later wipe out some
- * of them to only have one in out keyblock */
+ * of them to only have one in our keyblock */
uid->is_primary = 0;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_PRIMARY_UID, NULL );
+ p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL );
if ( p && *p )
uid->is_primary = 1;
/* We could also query this from the unhashed area if it is not in
@@ -1460,6 +1155,46 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode )
* there should be no security problem with this.
* For now we only look at the hashed one.
*/
+
+ /* Now build the preferences list. These must come from the
+ hashed section so nobody can modify the ciphers a key is
+ willing to accept. */
+ p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PREF_SYM, &n );
+ sym = p; nsym = p?n:0;
+ p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PREF_HASH, &n );
+ hash = p; nhash = p?n:0;
+ p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PREF_COMPR, &n );
+ zip = p; nzip = p?n:0;
+ if (uid->prefs)
+ m_free (uid->prefs);
+ n = nsym + nhash + nzip;
+ if (!n)
+ uid->prefs = NULL;
+ else {
+ uid->prefs = m_alloc (sizeof (*uid->prefs) * (n+1));
+ n = 0;
+ for (; nsym; nsym--, n++) {
+ uid->prefs[n].type = PREFTYPE_SYM;
+ uid->prefs[n].value = *sym++;
+ }
+ for (; nhash; nhash--, n++) {
+ uid->prefs[n].type = PREFTYPE_HASH;
+ uid->prefs[n].value = *hash++;
+ }
+ for (; nzip; nzip--, n++) {
+ uid->prefs[n].type = PREFTYPE_ZIP;
+ uid->prefs[n].value = *zip++;
+ }
+ uid->prefs[n].type = PREFTYPE_NONE; /* end of list marker */
+ uid->prefs[n].value = 0;
+ }
+
+ /* see whether we have the MDC feature */
+ uid->mdc_feature = 0;
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ if (p && n && (p[0] & 0x01))
+ uid->mdc_feature = 1;
+
}
static void
@@ -1472,29 +1207,38 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
KBNODE signode, uidnode, uidnode2;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
+ u32 keytimestamp = 0;
u32 key_expire = 0;
int key_expire_seen = 0;
+ byte sigversion = 0;
*r_revoked = 0;
if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
BUG ();
pk = keyblock->pkt->pkt.public_key;
- pk->created = 0;
+ keytimestamp = pk->timestamp;
+
keyid_from_pk( pk, kid );
pk->main_keyid[0] = kid[0];
pk->main_keyid[1] = kid[1];
if ( pk->version < 4 ) {
- /* before v4 the key packet itself contains the expiration date
- * and there was noway to change it. So we also use only the
- * one from the key packet */
- key_expire = pk->expiredate;
+ /* before v4 the key packet itself contains the expiration
+ * date and there was no way to change it, so we start with
+ * the one from the key packet */
+ key_expire = pk->max_expiredate;
key_expire_seen = 1;
}
/* first pass: find the latest direct key self-signature.
* We assume that the newest one overrides all others
*/
+
+ /* In case this key was already merged */
+ m_free(pk->revkey);
+ pk->revkey=NULL;
+ pk->numrevkeys=0;
+
signode = NULL;
sigdate = 0; /* helper to find the latest signature */
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
@@ -1505,30 +1249,82 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
; /* signature did not verify */
else if ( IS_KEY_REV (sig) ){
/* key has been revoked - there is no way to override
- * such a revocation, so we can stop now.
- * we can't cope with expiration times for revocations
- * here because we have to assumethat an attacker can
- * generate all kinds of signatures.
+ * such a revocation, so we theoretically can stop now.
+ * We should not cope with expiration times for revocations
+ * here because we have to assume that an attacker can
+ * generate all kinds of signatures. However due to the
+ * fact that the key has been revoked it does not harm
+ * either and by continuing we gather some more info on
+ * that key.
*/
*r_revoked = 1;
- return;
}
- else if ( IS_KEY_SIG (sig) && sig->timestamp >= sigdate ) {
- const byte *p;
-
- p = parse_sig_subpkt( sig->hashed_data,
- SIGSUBPKT_SIG_EXPIRE, NULL );
- if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ else if ( IS_KEY_SIG (sig) ) {
+ /* Add any revocation keys onto the pk. This is
+ particularly interesting since we normally only
+ get data from the most recent 1F signature, but
+ you need multiple 1F sigs to properly handle
+ revocation keys (PGP does it this way, and a
+ revocation key could be sensitive and hence in a
+ different signature). */
+ if(sig->revkey) {
+ int i;
+
+ pk->revkey=
+ m_realloc(pk->revkey,sizeof(struct revocation_key)*
+ (pk->numrevkeys+sig->numrevkeys));
+
+ for(i=0;i<sig->numrevkeys;i++)
+ memcpy(&pk->revkey[pk->numrevkeys++],
+ sig->revkey[i],
+ sizeof(struct revocation_key));
+ }
+
+ if( sig->timestamp >= sigdate ) {
+ if(sig->flags.expired)
; /* signature has expired - ignore it */
else {
sigdate = sig->timestamp;
signode = k;
- }
+ sigversion = sig->version;
+
+ }
+ }
}
}
}
}
+ /* Remove dupes from the revocation keys */
+
+ if(pk->revkey)
+ {
+ int i,j,x,changed=0;
+
+ for(i=0;i<pk->numrevkeys;i++)
+ {
+ for(j=i+1;j<pk->numrevkeys;j++)
+ {
+ if(memcmp(&pk->revkey[i],&pk->revkey[j],
+ sizeof(struct revocation_key))==0)
+ {
+ /* remove j */
+
+ for(x=j;x<pk->numrevkeys-1;x++)
+ pk->revkey[x]=pk->revkey[x+1];
+
+ pk->numrevkeys--;
+ j--;
+ changed=1;
+ }
+ }
+ }
+
+ if(changed)
+ pk->revkey=m_realloc(pk->revkey,
+ pk->numrevkeys*sizeof(struct revocation_key));
+ }
+
if ( signode ) {
/* some information from a direct key signature take precedence
* over the same information given in UID sigs.
@@ -1537,40 +1333,60 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
const byte *p;
size_t n;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
if ( p && n ) {
/* first octet of the keyflags */
if ( (*p & 3) )
- key_usage |= GCRY_PK_USAGE_SIGN;
+ key_usage |= PUBKEY_USAGE_SIG;
if ( (*p & 12) )
- key_usage |= GCRY_PK_USAGE_ENCR;
+ key_usage |= PUBKEY_USAGE_ENC;
}
- if ( pk->version > 3 ) {
- p = parse_sig_subpkt ( sig->hashed_data,
- SIGSUBPKT_KEY_EXPIRE, NULL);
- if ( p ) {
- key_expire = sig->timestamp + buffer_to_u32(p);
- key_expire_seen = 1;
- }
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if ( p ) {
+ key_expire = keytimestamp + buffer_to_u32(p);
+ key_expire_seen = 1;
}
- /* and set the created field */
- pk->created = sigdate;
- /* and mark that key as valid: one direct key signature should
+
+ /* mark that key as valid: one direct key signature should
* render a key as valid */
pk->is_valid = 1;
}
+ /* pass 1.5: look for key revocation signatures that were not made
+ by the key (i.e. did a revocation key issue a revocation for
+ us?). Only bother to do this if there is a revocation key in
+ the first place. */
+
+ if(pk->revkey)
+ for(k=keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next )
+ {
+ if ( k->pkt->pkttype == PKT_SIGNATURE )
+ {
+ PKT_signature *sig = k->pkt->pkt.signature;
+
+ if(IS_KEY_REV(sig) &&
+ (sig->keyid[0]!=kid[0] || sig->keyid[1]!=kid[1]))
+ {
+ if(check_revocation_keys(pk,sig))
+ ; /* did not verify, or loop broken */
+ else
+ *r_revoked=1;
+
+ /* In the future handle subkey and cert revocations?
+ PGP doesn't, but it's in 2440. */
+ }
+ }
+ }
/* second pass: look at the self-signature of all user IDs */
signode = uidnode = NULL;
sigdate = 0; /* helper to find the latest signature in one user ID */
uiddate = 0; /* and over of all user IDs */
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
- if ( k->pkt->pkttype == PKT_USER_ID
- || k->pkt->pkttype == PKT_PHOTO_ID ) {
- if ( uidnode )
- fixup_uidnode ( uidnode, signode );
+ if ( k->pkt->pkttype == PKT_USER_ID ) {
+ if ( uidnode && signode )
+ fixup_uidnode ( uidnode, signode, keytimestamp );
uidnode = k;
signode = NULL;
if ( sigdate > uiddate )
@@ -1582,48 +1398,89 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) {
if ( check_key_signature( keyblock, k, NULL ) )
; /* signature did not verify */
- else if ( IS_UID_SIG (sig) || IS_UID_REV (sig)) {
- /* Note: we allow to invalidated cert revocations
+ else if ( (IS_UID_SIG (sig) || IS_UID_REV (sig))
+ && sig->timestamp >= sigdate ) {
+ /* Note: we allow to invalidate cert revocations
* by a newer signature. An attacker can't use this
* because a key should be revoced with a key revocation.
* The reason why we have to allow for that is that at
* one time an email address may become invalid but later
* the same email address may become valid again (hired,
* fired, hired again).
- */
- const byte *p;
-
- p = parse_sig_subpkt( sig->hashed_data,
- SIGSUBPKT_SIG_EXPIRE, NULL );
- if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
- ; /* signature/revocation has expired - ignore it */
+ */
+ if(sig->flags.expired) {
+ /* Expired uids don't get to be primary unless
+ they are the only uid there is. */
+ uidnode->pkt->pkt.user_id->is_primary=0;
+ uidnode->pkt->pkt.user_id->is_expired=1;
+ uidnode->pkt->pkt.user_id->expiredate=sig->expiredate;
+ }
else {
sigdate = sig->timestamp;
signode = k;
+ if( sig->version > sigversion )
+ sigversion = sig->version;
}
}
}
}
}
- if ( uidnode ) {
- fixup_uidnode ( uidnode, signode );
+ if ( uidnode && signode ) {
+ fixup_uidnode ( uidnode, signode, keytimestamp );
pk->is_valid = 1;
}
- if ( sigdate > uiddate )
- uiddate = sigdate;
- /* if we do not have a direct key signature, take the key creation date
- * from the latest user ID. Hmmm, another possibilty would be to take
- * it from the latest primary user ID - but we don't implement it for
- * now */
- if ( !pk->created )
- pk->created = uiddate;
- if ( !pk->created ) {
- /* oops, still no creation date: use the timestamp */
- if (DBG_CACHE)
- log_debug( "merge_selfsigs_main: "
- "using timestamp as creation date\n");
- pk->created = pk->timestamp;
- }
+
+ /* If the key isn't valid yet, and we have
+ --allow-non-selfsigned-uid set, then force it valid. */
+ if(!pk->is_valid && opt.allow_non_selfsigned_uid)
+ {
+ if(opt.verbose)
+ log_info(_("Invalid key %08lX made valid by "
+ "--allow-non-selfsigned-uid\n"),
+ (ulong)keyid_from_pk(pk,NULL));
+
+ pk->is_valid = 1;
+ }
+
+ /* The key STILL isn't valid, so try and find an ultimately
+ trusted signature. */
+ if(!pk->is_valid)
+ {
+ uidnode=NULL;
+
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k=k->next)
+ {
+ if ( k->pkt->pkttype == PKT_USER_ID )
+ uidnode = k;
+ else if ( k->pkt->pkttype == PKT_SIGNATURE && uidnode )
+ {
+ PKT_signature *sig = k->pkt->pkt.signature;
+
+ if(sig->keyid[0] != kid[0] || sig->keyid[1]!=kid[1])
+ {
+ PKT_public_key *ultimate_pk;
+
+ ultimate_pk=m_alloc_clear(sizeof(*ultimate_pk));
+
+ if(get_pubkey(ultimate_pk,sig->keyid)==0 &&
+ check_key_signature(keyblock,k,NULL)==0 &&
+ get_ownertrust(ultimate_pk)==TRUST_ULTIMATE)
+ {
+ free_public_key(ultimate_pk);
+ pk->is_valid=1;
+ break;
+ }
+
+ free_public_key(ultimate_pk);
+ }
+ }
+ }
+ }
+
+ /* Record the highest selfsigversion so we know if this is a v3
+ key through and through, or a v3 key with a v4 selfsig, which
+ means we can trust the preferences (if any). */
+ pk->selfsigversion=sigversion;
/* Now that we had a look at all user IDs we can now get some information
* from those user IDs.
@@ -1634,8 +1491,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
uiddate = 0; /* helper to find the latest user ID */
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next ) {
- if ( k->pkt->pkttype == PKT_USER_ID
- || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ if ( k->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *uid = k->pkt->pkt.user_id;
if ( uid->help_key_usage && uid->created > uiddate ) {
key_usage = uid->help_key_usage;
@@ -1654,16 +1510,14 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
}
pk->pubkey_usage = key_usage;
-
if ( !key_expire_seen ) {
/* find the latest valid user ID with a key expiration set
- * Note, that this may be a diferent one from the above because
+ * Note, that this may be a different one from the above because
* some user IDs may have no expiration date set */
uiddate = 0;
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next ) {
- if ( k->pkt->pkttype == PKT_USER_ID
- || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ if ( k->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *uid = k->pkt->pkt.user_id;
if ( uid->help_key_expire && uid->created > uiddate ) {
key_expire = uid->help_key_expire;
@@ -1672,17 +1526,23 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
}
}
}
-
- pk->has_expired = key_expire >= curtime? 0 : key_expire;
- /* FIXME: we should see how to get rid of the expiretime fields */
+ /* Currently only v3 keys have a maximum expiration date, but I'll
+ bet v5 keys get this feature again. */
+ if(key_expire==0 || (pk->max_expiredate && key_expire>pk->max_expiredate))
+ key_expire=pk->max_expiredate;
+
+ pk->has_expired = key_expire >= curtime? 0 : key_expire;
+ pk->expiredate = key_expire;
+ /* Fixme: we should see how to get rid of the expiretime fields but
+ * this needs changes at other places too. */
/* and now find the real primary user ID and delete all others */
uiddate = uiddate2 = 0;
uidnode = uidnode2 = NULL;
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
- if ( k->pkt->pkttype == PKT_USER_ID
- || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ if ( k->pkt->pkttype == PKT_USER_ID &&
+ !k->pkt->pkt.user_id->attrib_data) {
PKT_user_id *uid = k->pkt->pkt.user_id;
if ( uid->is_primary && uid->created > uiddate ) {
uiddate = uid->created;
@@ -1697,8 +1557,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if ( uidnode ) {
for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next ) {
- if ( k->pkt->pkttype == PKT_USER_ID
- || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ if ( k->pkt->pkttype == PKT_USER_ID &&
+ !k->pkt->pkt.user_id->attrib_data) {
PKT_user_id *uid = k->pkt->pkt.user_id;
if ( k != uidnode )
uid->is_primary = 0;
@@ -1709,7 +1569,23 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
/* none is flagged primary - use the latest user ID we have */
uidnode2->pkt->pkt.user_id->is_primary = 1;
}
-
+ else
+ {
+ /* None of our uids were self-signed, so pick the first one to
+ be the primary. This is the best we can do here since
+ there are no self sigs to date the uids. */
+
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ k = k->next )
+ {
+ if(k->pkt->pkttype==PKT_USER_ID &&
+ !k->pkt->pkt.user_id->attrib_data)
+ {
+ k->pkt->pkt.user_id->is_primary=1;
+ break;
+ }
+ }
+ }
}
@@ -1724,6 +1600,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
KBNODE signode;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
+ u32 keytimestamp = 0;
u32 key_expire = 0;
const byte *p;
size_t n;
@@ -1735,11 +1612,11 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
return; /* (actually this should never happen) */
keyid_from_pk( mainpk, mainkid );
subpk = subnode->pkt->pkt.public_key;
+ keytimestamp = subpk->timestamp;
+
subpk->is_valid = 0;
subpk->main_keyid[0] = mainpk->main_keyid[0];
subpk->main_keyid[1] = mainpk->main_keyid[1];
- if ( subpk->version < 4 )
- return; /* there are no v3 subkeys */
/* find the latest key binding self-signature. */
signode = NULL;
@@ -1752,17 +1629,13 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
if ( check_key_signature( keyblock, k, NULL ) )
; /* signature did not verify */
else if ( IS_SUBKEY_REV (sig) ) {
- /* key has been revoked - given the fact that it is easy
- * to create a new subkey, it does not make sense to
- * revive a revoked key. So we can stop here.
- */
subpk->is_revoked = 1;
- return;
+ /* although we could stop now, we continue to
+ * figure out other information like the old expiration
+ * time */
}
else if ( IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate ) {
- p = parse_sig_subpkt( sig->hashed_data,
- SIGSUBPKT_SIG_EXPIRE, NULL );
- if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ if(sig->flags.expired)
; /* signature has expired - ignore it */
else {
sigdate = sig->timestamp;
@@ -1774,21 +1647,19 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
}
if ( !signode ) {
- subpk->created = subpk->timestamp;
return; /* no valid key binding */
}
subpk->is_valid = 1;
- subpk->created = sigdate;
sig = signode->pkt->pkt.signature;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
if ( p && n ) {
/* first octet of the keyflags */
if ( (*p & 3) )
- key_usage |= GCRY_PK_USAGE_SIGN;
+ key_usage |= PUBKEY_USAGE_SIG;
if ( (*p & 12) )
- key_usage |= GCRY_PK_USAGE_ENCR;
+ key_usage |= PUBKEY_USAGE_ENC;
}
if ( !key_usage ) { /* no key flags at all: get it from the algo */
key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo );
@@ -1800,12 +1671,13 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
}
subpk->pubkey_usage = key_usage;
- p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if ( p )
- key_expire = sig->timestamp + buffer_to_u32(p);
+ key_expire = keytimestamp + buffer_to_u32(p);
else
key_expire = 0;
subpk->has_expired = key_expire >= curtime? 0 : key_expire;
+ subpk->expiredate = key_expire;
}
@@ -1828,9 +1700,20 @@ merge_selfsigs( KBNODE keyblock )
KBNODE k;
int revoked;
PKT_public_key *main_pk;
-
- if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
+ prefitem_t *prefs;
+ int mdc_feature;
+
+ if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY ) {
+ if (keyblock->pkt->pkttype == PKT_SECRET_KEY ) {
+ log_error ("expected public key but found secret key "
+ "- must stop\n");
+ /* we better exit here becuase a public key is expected at
+ other places too. FIXME: Figure this out earlier and
+ don't get to here at all */
+ g10_exit (1);
+ }
BUG ();
+ }
merge_selfsigs_main ( keyblock, &revoked );
main_pk = keyblock->pkt->pkt.public_key;
@@ -1855,6 +1738,44 @@ merge_selfsigs( KBNODE keyblock )
merge_selfsigs_subkey ( keyblock, k );
}
}
+
+ /* If the main key is not valid, then the subkeys aren't either,
+ even if they have binding sigs. */
+ if(!main_pk->is_valid)
+ for(k=keyblock; k; k=k->next)
+ if(k->pkt->pkttype==PKT_PUBLIC_SUBKEY)
+ k->pkt->pkt.public_key->is_valid=0;
+
+ /* set the preference list of all keys to those of the primary real
+ * user ID. Note: we use these preferences when we don't know by
+ * which user ID the key has been selected.
+ * fixme: we should keep atoms of commonly used preferences or
+ * use reference counting to optimize the preference lists storage.
+ * FIXME: it might be better to use the intersection of
+ * all preferences.
+ * Do a similar thing for the MDC feature flag.
+ */
+ prefs = NULL;
+ mdc_feature = 0;
+ for (k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) {
+ if (k->pkt->pkttype == PKT_USER_ID
+ && !k->pkt->pkt.user_id->attrib_data
+ && k->pkt->pkt.user_id->is_primary) {
+ prefs = k->pkt->pkt.user_id->prefs;
+ mdc_feature = k->pkt->pkt.user_id->mdc_feature;
+ break;
+ }
+ }
+ for(k=keyblock; k; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ PKT_public_key *pk = k->pkt->pkt.public_key;
+ if (pk->prefs)
+ m_free (pk->prefs);
+ pk->prefs = copy_prefs (prefs);
+ pk->mdc_feature = mdc_feature;
+ }
+ }
}
@@ -1865,7 +1786,7 @@ merge_selfsigs( KBNODE keyblock )
* keys at all and have a way to store just the real secret parts
* from the key.
*/
-void
+static void
merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
{
KBNODE pub;
@@ -1898,7 +1819,7 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
if ( !cmp_public_secret_key ( pk, sk ) ) {
copy_public_parts_to_secret_key ( pk, sk );
free_public_key ( pk );
- pub->pkt->pkttype = PKT_SECRET_KEY;
+ pub->pkt->pkttype = PKT_SECRET_SUBKEY;
pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
break;
}
@@ -1911,11 +1832,12 @@ merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
}
/* This function checks that for every public subkey a corresponding
- * secret subkey is avalable and deletes the public subkey otherwise.
- * We need this function becuase we can'tdelete it later when we
+ * secret subkey is available and deletes the public subkey otherwise.
+ * We need this function because we can't delete it later when we
* actually merge the secret parts into the pubring.
+ * The function also plays some games with the node flags.
*/
-void
+static void
premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
{
KBNODE last, pub;
@@ -1924,6 +1846,7 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
assert ( secblock->pkt->pkttype == PKT_SECRET_KEY );
for (pub=pubblock,last=NULL; pub; last = pub, pub = pub->next ) {
+ pub->flag &= ~3; /* reset bits 0 and 1 */
if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
KBNODE sec;
PKT_public_key *pk = pub->pkt->pkt.public_key;
@@ -1931,14 +1854,25 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
for (sec=secblock->next; sec; sec = sec->next ) {
if ( sec->pkt->pkttype == PKT_SECRET_SUBKEY ) {
PKT_secret_key *sk = sec->pkt->pkt.secret_key;
- if ( !cmp_public_secret_key ( pk, sk ) )
+ if ( !cmp_public_secret_key ( pk, sk ) ) {
+ if ( sk->protect.s2k.mode == 1001 ) {
+ /* The secret parts are not available so
+ we can't use that key for signing etc.
+ Fix the pubkey usage */
+ pk->pubkey_usage &= ~PUBKEY_USAGE_SIG;
+ }
+ /* transfer flag bits 0 and 1 to the pubblock */
+ pub->flag |= (sec->flag &3);
break;
+ }
}
}
if ( !sec ) {
KBNODE next, ll;
- log_error ( "no corresponding secret subkey "
- "for public subkey - removing\n" );
+
+ log_info ( "no secret subkey "
+ "for public subkey %08lX - ignoring\n",
+ (ulong)keyid_from_pk (pk,NULL) );
/* we have to remove the subkey in this case */
assert ( last );
/* find the next subkey */
@@ -1956,108 +1890,25 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
}
}
}
+ /* We need to copy the found bits (0 and 1) from the secret key to
+ the public key. This has already been done for the subkeys but
+ got lost on the primary key - fix it here *. */
+ pubblock->flag |= (secblock->flag & 3);
}
-/************************************************
- ************* Find stuff ***********************
- ************************************************/
-
-static int
-find_by_name( KBNODE keyblock, const char *name,
- int mode, byte *namehash )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_USER_ID
- && !compare_name( k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len, name, mode)) {
- /* we found a matching name, look for the key */
- if( k->pkt->pkt.user_id->photo ) {
- /* oops: this can never happen */
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
- k->pkt->pkt.user_id->photo,
- k->pkt->pkt.user_id->photolen );
- }
- else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
- k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len );
- }
- return 1;
- }
- }
-
- return 0;
-}
-
-
-
-static KBNODE
-find_by_keyid( KBNODE keyblock, u32 *keyid, int mode )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- if( aki[1] == keyid[1] && ( mode == 10 || aki[0] == keyid[0] ) ) {
- return k; /* found */
- }
- }
- }
- return NULL;
-}
-
-
-
-static KBNODE
-find_by_fpr( KBNODE keyblock, const char *name, int mode )
-{
- KBNODE k;
-
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- byte afp[MAX_FINGERPRINT_LEN];
- size_t an;
-
- fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
- if ( mode == 21 ) {
- /* Unified fingerprint. The fingerprint is always 20 bytes*/
- while ( an < 20 )
- afp[an++] = 0;
- if ( !memcmp( afp, name, 20 ) )
- return k;
- }
- else {
- if( an == mode && !memcmp( afp, name, an) ) {
- return k;
- }
- }
- }
- }
- return NULL;
-}
-
-
-
-
/* See see whether the key fits
* our requirements and in case we do not
- * request a the primary key, we should select
+ * request the primary key, we should select
* a suitable subkey.
* FIXME: Check against PGP 7 whether we still need a kludge
* to favor type 16 keys over type 20 keys when type 20
* has not been explitely requested.
* Returns: True when a suitable key has been found.
*
- * We have to distinguish four cases:
+ * We have to distinguish four cases: FIXME!
* 1. No usage and no primary key requested
* Examples for this case are that we have a keyID to be used
* for decrytion or verification.
@@ -2069,35 +1920,79 @@ find_by_fpr( KBNODE keyblock, const char *name, int mode )
* 4. Usage but no primary key requested
* FIXME
* FIXME: Tell what is going to happen here and something about the rationale
+ * Note: We don't use this function if no specific usage is requested;
+ * This way the getkey functions can be used for plain key listings.
*
+ * CTX ist the keyblock we are investigating, if FOUNDK is not NULL this
+ * is the key we actually found by looking at the keyid or a fingerprint and
+ * may eitehr point to the primary or one of the subkeys.
*/
static int
-finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
+finish_lookup (GETKEY_CTX ctx)
{
KBNODE keyblock = ctx->keyblock;
KBNODE k;
- #define USAGE_MASK (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR)
+ KBNODE foundk = NULL;
+ PKT_user_id *foundu = NULL;
+ #define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC)
unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
+ /* Request the primary if we're certifying another key, and also
+ if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
+ do not understand signatures made by a signing subkey. */
+ int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) ||
+ ((opt.pgp6 || opt.pgp7) && (ctx->req_usage & PUBKEY_USAGE_SIG));
u32 latest_date;
KBNODE latest_key;
+ u32 curtime = make_timestamp ();
- assert( !foundk || foundk->pkt->pkttype == PKT_PUBLIC_KEY
- || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY );
assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
ctx->found_key = NULL;
-
+
+ if (ctx->exact) {
+ for (k=keyblock; k; k = k->next) {
+ if ( (k->flag & 1) ) {
+ assert ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+ foundk = k;
+ break;
+ }
+ }
+ }
+
+ for (k=keyblock; k; k = k->next) {
+ if ( (k->flag & 2) ) {
+ assert (k->pkt->pkttype == PKT_USER_ID);
+ foundu = k->pkt->pkt.user_id;
+ break;
+ }
+ }
+
if ( DBG_CACHE )
- log_debug( "finish_lookup: checking %s (req_usage=%x)\n",
- foundk? "one key":"all keys", req_usage);
+ log_debug( "finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
+ (ulong)keyid_from_pk( keyblock->pkt->pkt.public_key, NULL),
+ foundk? "one":"all", req_usage);
+ if (!req_usage) {
+ latest_key = foundk? foundk:keyblock;
+ goto found;
+ }
+
+ if (!req_usage) {
+ PKT_public_key *pk = foundk->pkt->pkt.public_key;
+ if (pk->user_id)
+ free_user_id (pk->user_id);
+ pk->user_id = scopy_user_id (foundu);
+ ctx->found_key = foundk;
+ cache_user_id( keyblock );
+ return 1; /* found */
+ }
+
latest_date = 0;
latest_key = NULL;
- /* We do check the subkeys only if we either have requested a specific
- * usage or have not requested to get the primary key. */
- if ( (req_usage || !ctx->primary)
- && (!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
+ /* do not look at subkeys if a certification key is requested */
+ if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_prim) {
KBNODE nextk;
/* either start a loop or check just this one subkey */
for (k=foundk?foundk:keyblock; k; k = nextk ) {
@@ -2108,6 +2003,9 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
if ( foundk )
nextk = NULL; /* what a hack */
pk = k->pkt->pkt.public_key;
+ if (DBG_CACHE)
+ log_debug( "\tchecking subkey %08lX\n",
+ (ulong)keyid_from_pk( pk, NULL));
if ( !pk->is_valid ) {
if (DBG_CACHE)
log_debug( "\tsubkey not valid\n");
@@ -2123,9 +2021,13 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
log_debug( "\tsubkey has expired\n");
continue;
}
+ if ( pk->timestamp > curtime && !opt.ignore_valid_from ) {
+ if (DBG_CACHE)
+ log_debug( "\tsubkey not yet valid\n");
+ continue;
+ }
- if ( req_usage &&
- !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+ if ( !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
if (DBG_CACHE)
log_debug( "\tusage does not match: want=%x have=%x\n",
req_usage, pk->pubkey_usage );
@@ -2133,18 +2035,19 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
}
if (DBG_CACHE)
- log_debug( "\tconsidering key %08lX\n",
- (ulong)keyid_from_pk( pk, NULL));
- if ( pk->created > latest_date ) {
- latest_date = pk->created;
+ log_debug( "\tsubkey looks fine\n");
+ if ( pk->timestamp > latest_date ) {
+ latest_date = pk->timestamp;
latest_key = k;
}
}
}
- if ( !latest_key ) {
+ /* Okay now try the primary key unless we want an exact
+ * key ID match on a subkey */
+ if ((!latest_key && !(ctx->exact && foundk != keyblock)) || req_prim) {
PKT_public_key *pk;
- if (DBG_CACHE && !foundk )
+ if (DBG_CACHE && !foundk && !req_prim )
log_debug( "\tno suitable subkeys found - trying primary\n");
pk = keyblock->pkt->pkt.public_key;
if ( !pk->is_valid ) {
@@ -2159,17 +2062,17 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
if (DBG_CACHE)
log_debug( "\tprimary key has expired\n");
}
- else if ( req_usage
- && !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+ else if ( !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
if (DBG_CACHE)
- log_debug( "\tusage does not match: want=%x have=%x\n",
+ log_debug( "\tprimary key usage does not match: "
+ "want=%x have=%x\n",
req_usage, pk->pubkey_usage );
}
else { /* okay */
if (DBG_CACHE)
log_debug( "\tprimary key may be used\n");
latest_key = keyblock;
- latest_date = pk->created;
+ latest_date = pk->timestamp;
}
}
@@ -2179,13 +2082,21 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
return 0;
}
+ found:
if (DBG_CACHE)
log_debug( "\tusing key %08lX\n",
(ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL) );
+ if (latest_key) {
+ PKT_public_key *pk = latest_key->pkt->pkt.public_key;
+ if (pk->user_id)
+ free_user_id (pk->user_id);
+ pk->user_id = scopy_user_id (foundu);
+ }
+
ctx->found_key = latest_key;
- if ( latest_key != keyblock ) {
+ if (latest_key != keyblock && opt.verbose) {
log_info(_("using secondary key %08lX "
"instead of primary key %08lX\n"),
(ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL),
@@ -2197,109 +2108,91 @@ finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
return 1; /* found */
}
-
+
static int
lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
{
int rc;
- int oldmode = set_packet_list_mode(0);
- byte namehash[20];
- int use_namehash=0;
KBNODE secblock = NULL; /* helper */
-
- if( !ctx->count ) /* first time */
- rc = enum_keyblocks_begin( &ctx->kbpos, secmode );
- else
- rc = 0;
- if( !rc ) {
- while( !(rc = enum_keyblocks_next( ctx->kbpos, 1, &ctx->keyblock )) ) {
- int n;
- getkey_item_t *item;
-
- if ( secmode ) {
- /* find the correspondig public key and use this
- * this one for the selection process */
- u32 aki[2];
- KBNODE k = ctx->keyblock;
-
- if ( k->pkt->pkttype != PKT_SECRET_KEY )
- BUG();
- keyid_from_sk( k->pkt->pkt.secret_key, aki );
- k = get_pubkeyblock( aki );
- if( !k ) {
- log_info(_("key %08lX: secret key without public key "
+ int no_suitable_key = 0;
+
+ rc = 0;
+ while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems))) {
+ /* If we are searching for the first key we have to make sure
+ that the next interation does not no an implicit reset.
+ This can be triggered by an empty key ring. */
+ if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
+ ctx->items->mode = KEYDB_SEARCH_MODE_NEXT;
+
+ rc = keydb_get_keyblock (ctx->kr_handle, &ctx->keyblock);
+ if (rc) {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ rc = 0;
+ goto skip;
+ }
+
+ if ( secmode ) {
+ /* find the correspondig public key and use this
+ * this one for the selection process */
+ u32 aki[2];
+ KBNODE k = ctx->keyblock;
+
+ if (k->pkt->pkttype != PKT_SECRET_KEY)
+ BUG();
+
+ keyid_from_sk (k->pkt->pkt.secret_key, aki);
+ k = get_pubkeyblock (aki);
+ if( !k ) {
+ if (!opt.quiet)
+ log_info(_("key %08lX: secret key without public key "
"- skipped\n"), (ulong)aki[1] );
- goto skip;
- }
- secblock = ctx->keyblock;
- ctx->keyblock = k;
- premerge_public_with_secret ( ctx->keyblock, secblock );
+ goto skip;
}
+ secblock = ctx->keyblock;
+ ctx->keyblock = k;
+ premerge_public_with_secret ( ctx->keyblock, secblock );
+ }
- /* loop over all the user ids we want to look for */
- item = ctx->items;
- for(n=0; n < ctx->nitems; n++, item++ ) {
- KBNODE k = NULL;
- int found = 0;
-
- if( item->mode < 10 ) {
- found = find_by_name( ctx->keyblock,
- item->name, item->mode,
- namehash );
- use_namehash = found;
- }
- else if( item->mode >= 10 && item->mode <= 12 ) {
- k = find_by_keyid( ctx->keyblock,
- item->keyid, item->mode );
- found = !!k;
- }
- else if( item->mode == 15 ) {
- found = 1;
- }
- else if( item->mode == 16 || item->mode == 20
- || item->mode == 21 ) {
- k = find_by_fpr( ctx->keyblock,
- item->fprint, item->mode );
- found = !!k;
- }
- else
- BUG();
- if( found ) {
- /* this keyblock looks fine - do further investigation */
- merge_selfsigs ( ctx->keyblock );
- if ( finish_lookup( ctx, k ) ) {
- if ( secmode ) {
- merge_public_with_secret ( ctx->keyblock,
- secblock);
- release_kbnode (secblock);
- secblock = NULL;
- }
- goto found;
- }
- }
- }
- skip:
- /* release resources and try the next keyblock */
+ /* warning: node flag bits 0 and 1 should be preserved by
+ * merge_selfsigs. For secret keys, premerge did tranfer the
+ * keys to the keyblock */
+ merge_selfsigs ( ctx->keyblock );
+ if ( finish_lookup (ctx) ) {
+ no_suitable_key = 0;
if ( secmode ) {
- release_kbnode( secblock );
+ merge_public_with_secret ( ctx->keyblock,
+ secblock);
+ release_kbnode (secblock);
secblock = NULL;
}
- release_kbnode( ctx->keyblock );
- ctx->keyblock = NULL;
- }
- found:
- ;
+ goto found;
+ }
+ else
+ no_suitable_key = 1;
+
+ skip:
+ /* release resources and continue search */
+ if ( secmode ) {
+ release_kbnode( secblock );
+ secblock = NULL;
+ }
+ release_kbnode( ctx->keyblock );
+ ctx->keyblock = NULL;
}
+
+ found:
if( rc && rc != -1 )
- log_error("enum_keyblocks failed: %s\n", gpg_errstr(rc));
+ log_error("keydb_search failed: %s\n", g10_errstr(rc));
if( !rc ) {
*ret_keyblock = ctx->keyblock; /* return the keyblock */
ctx->keyblock = NULL;
}
+ else if (rc == -1 && no_suitable_key)
+ rc = secmode ? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
else if( rc == -1 )
- rc = secmode ? GPGERR_NO_SECKEY : GPGERR_NO_PUBKEY;
+ rc = secmode ? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
if ( secmode ) {
release_kbnode( secblock );
@@ -2307,36 +2200,14 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
}
release_kbnode( ctx->keyblock );
ctx->keyblock = NULL;
- set_packet_list_mode(oldmode);
- #if 0
- if( opt.debug & DBG_MEMSTAT_VALUE ) {
- static int initialized;
-
- if( !initialized ) {
- initialized = 1;
- atexit( print_stats );
- }
-
- assert( ctx->mode < DIM(lkup_stats) );
- lkup_stats[ctx->mode].any = 1;
- if( !rc )
- lkup_stats[ctx->mode].okay_count++;
- else if ( rc == GPGERR_NO_PUBKEY || rc == GPGERR_NO_SECKEY )
- lkup_stats[ctx->mode].nokey_count++;
- else
- lkup_stats[ctx->mode].error_count++;
- }
- #endif
ctx->last_rc = rc;
- ctx->count++;
return rc;
}
-
/****************
* FIXME: Replace by the generic function
* It does not work as it is right now - it is used at
@@ -2352,34 +2223,33 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
* to indicate EOF.
* 4) Always call this function a last time with SK set to NULL,
* so that can free it's context.
- *
- *
*/
int
enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
{
int rc=0;
- PACKET pkt;
- int save_mode;
struct {
int eof;
- int sequence;
- const char *name;
- IOBUF iobuf;
+ int first;
+ KEYDB_HANDLE hd;
+ KBNODE keyblock;
+ KBNODE node;
} *c = *context;
if( !c ) { /* make a new context */
- c = gcry_xcalloc( 1, sizeof *c );
+ c = m_alloc_clear( sizeof *c );
*context = c;
- c->sequence = 0;
- c->name = enum_keyblock_resources( &c->sequence, 1 );
+ c->hd = keydb_new (1);
+ c->first = 1;
+ c->keyblock = NULL;
+ c->node = NULL;
}
if( !sk ) { /* free the context */
- if( c->iobuf )
- iobuf_close(c->iobuf);
- gcry_free( c );
+ keydb_release (c->hd);
+ release_kbnode (c->keyblock);
+ m_free( c );
*context = NULL;
return 0;
}
@@ -2387,33 +2257,33 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
if( c->eof )
return -1;
- /* FIXME: This assumes a plain keyring file */
- for( ; c->name; c->name = enum_keyblock_resources( &c->sequence, 1 ) ) {
- if( !c->iobuf ) {
- if( !(c->iobuf = iobuf_open( c->name ) ) ) {
- log_error("enum_secret_keys: can't open `%s'\n", c->name );
- continue; /* try next file */
- }
- }
+ do {
+ /* get the next secret key from the current keyblock */
+ for (; c->node; c->node = c->node->next) {
+ if (c->node->pkt->pkttype == PKT_SECRET_KEY
+ || (with_subkeys
+ && c->node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
+ copy_secret_key (sk, c->node->pkt->pkt.secret_key );
+ c->node = c->node->next;
+ return 0; /* found */
+ }
+ }
+ release_kbnode (c->keyblock);
+ c->keyblock = c->node = NULL;
+
+ rc = c->first? keydb_search_first (c->hd) : keydb_search_next (c->hd);
+ c->first = 0;
+ if (rc) {
+ keydb_release (c->hd); c->hd = NULL;
+ c->eof = 1;
+ return -1; /* eof */
+ }
+
+ rc = keydb_get_keyblock (c->hd, &c->keyblock);
+ c->node = c->keyblock;
+ } while (!rc);
- save_mode = set_packet_list_mode(0);
- init_packet(&pkt);
- while( (rc=parse_packet(c->iobuf, &pkt, NULL)) != -1 ) {
- if( rc )
- ; /* e.g. unknown packet */
- else if( pkt.pkttype == PKT_SECRET_KEY
- || ( with_subkeys && pkt.pkttype == PKT_SECRET_SUBKEY ) ) {
- copy_secret_key( sk, pkt.pkt.secret_key );
- set_packet_list_mode(save_mode);
- return 0; /* found */
- }
- free_packet(&pkt);
- }
- set_packet_list_mode(save_mode);
- iobuf_close(c->iobuf); c->iobuf = NULL;
- }
- c->eof = 1;
- return -1;
+ return rc; /* error */
}
@@ -2438,7 +2308,7 @@ get_user_id_string( u32 *keyid )
keyid_list_t a;
for (a=r->keyids; a; a= a->next ) {
if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len + 10 );
+ p = m_alloc( r->len + 10 );
sprintf(p, "%08lX %.*s",
(ulong)keyid[1], r->len, r->name );
return p;
@@ -2446,7 +2316,7 @@ get_user_id_string( u32 *keyid )
}
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = gcry_xmalloc( 15 );
+ p = m_alloc( 15 );
sprintf(p, "%08lX [?]", (ulong)keyid[1] );
return p;
}
@@ -2456,9 +2326,9 @@ char*
get_user_id_string_native( u32 *keyid )
{
char *p = get_user_id_string( keyid );
- char *p2 = utf8_to_native( p, strlen(p) );
+ char *p2 = utf8_to_native( p, strlen(p), 0 );
- gcry_free(p);
+ m_free(p);
return p2;
}
@@ -2475,7 +2345,7 @@ get_long_user_id_string( u32 *keyid )
keyid_list_t a;
for (a=r->keyids; a; a= a->next ) {
if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len + 20 );
+ p = m_alloc( r->len + 20 );
sprintf(p, "%08lX%08lX %.*s",
(ulong)keyid[0], (ulong)keyid[1],
r->len, r->name );
@@ -2484,7 +2354,7 @@ get_long_user_id_string( u32 *keyid )
}
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = gcry_xmalloc( 25 );
+ p = m_alloc( 25 );
sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] );
return p;
}
@@ -2502,7 +2372,7 @@ get_user_id( u32 *keyid, size_t *rn )
keyid_list_t a;
for (a=r->keyids; a; a= a->next ) {
if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len );
+ p = m_alloc( r->len );
memcpy(p, r->name, r->len );
*rn = r->len;
return p;
@@ -2510,9 +2380,84 @@ get_user_id( u32 *keyid, size_t *rn )
}
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = gcry_xstrdup( _("[User id not found]") );
+ p = m_strdup( _("[User id not found]") );
*rn = strlen(p);
return p;
}
+char*
+get_user_id_native( u32 *keyid )
+{
+ size_t rn;
+
+ char *p = get_user_id( keyid, &rn );
+ char *p2 = utf8_to_native( p, rn, 0 );
+
+ m_free(p);
+ return p2;
+}
+
+KEYDB_HANDLE
+get_ctx_handle(GETKEY_CTX ctx)
+{
+ return ctx->kr_handle;
+}
+
+/* Check the revocation keys to see if any of them have revoked our
+ pk. sig is the revocation sig. pk is the key it is on. This code
+ will need to be modified if gpg ever becomes multi-threaded. Note
+ that this is written so that a revoked revoker can still issue
+ revocations: i.e. If A revokes B, but A is revoked, B is still
+ revoked. I'm not completely convinced this is the proper behavior,
+ but it matches how PGP does it. -dms */
+/* Return 0 if pk is revoked, non-0 if not revoked */
+static int
+check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
+{
+ static int busy=0;
+ int i,rc=-1;
+
+ assert(IS_KEY_REV(sig));
+ assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
+
+ if(busy)
+ {
+ /* return -1 (i.e. not revoked), but mark the pk as uncacheable
+ as we don't really know its revocation status until it is
+ checked directly. */
+
+ pk->dont_cache=1;
+ return -1;
+ }
+
+ busy=1;
+
+ /* printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
+ (ulong)sig->keyid[1]); */
+
+ /* is the issuer of the sig one of our revokers? */
+ if( !pk->revkey && pk->numrevkeys )
+ BUG();
+ else
+ for(i=0;i<pk->numrevkeys;i++) {
+ u32 keyid[2];
+
+ keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
+
+ if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1]) {
+ MD_HANDLE md;
+
+ md=md_open(sig->digest_algo,0);
+ hash_public_key(md,pk);
+ if(signature_check(sig,md)==0) {
+ rc=0;
+ break;
+ }
+ }
+ }
+
+ busy=0;
+
+ return rc;
+}
diff --git a/g10/basicdefs.h b/g10/global.h
index 1a7f0901a..3c4e59ec4 100644
--- a/g10/basicdefs.h
+++ b/g10/global.h
@@ -1,5 +1,5 @@
-/* basicdefs.h - Some definitions used at many place
- * Copyright (C) 1999 Free Software Foundation, Inc.
+/* global.h - Local typedefs and constants
+ * Copyright (C) 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,23 +18,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_BASICDEFS_H
-#define GPG_BASICDEFS_H
+#ifndef GPG_GLOBAL_H
+#define GPG_GLOBAL_H
-#include "types.h"
+#define MAX_FINGERPRINT_LEN 20
-typedef struct {
- int algo;
- int keylen;
- byte key[32]; /* this is the largest used keylen (256 bit) */
-} DEK;
+typedef struct kbnode_struct *KBNODE;
+typedef struct keydb_search_desc KEYDB_SEARCH_DESC;
-
-struct pk_list;
-struct sk_list;
-typedef struct pk_list *PK_LIST;
-typedef struct sk_list *SK_LIST;
-
-
-
-#endif /* GPG_BASICDEFS_H */
+#endif /*GPG_GLOBAL_H*/
diff --git a/g10/gpgd.c b/g10/gpgd.c
index 8ca37d34a..365556604 100644
--- a/g10/gpgd.c
+++ b/g10/gpgd.c
@@ -1,5 +1,5 @@
-/* ggpd.c - The GnuPG daemon (keyserver)
- * Copyright (C) 1998 Free Software Foundation, Inc.
+/* gpd.c - The GnuPG daemon (keyserver)
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -112,7 +112,7 @@ build_list( const char *text, const char * (*mapf)(int), int (*chkf)(int) )
for(i=1; i < 100; i++ )
if( !chkf(i) && (s=mapf(i)) )
n += strlen(s) + 2;
- list = gcry_xmalloc( 21 + n ); *list = 0;
+ list = m_alloc( 21 + n ); *list = 0;
for(p=NULL, i=1; i < 100; i++ ) {
if( !chkf(i) && (s=mapf(i)) ) {
if( !p )
@@ -201,9 +201,9 @@ main( int argc, char **argv )
else {
log_error("option file `%s': %s\n",
configname, strerror(errno) );
- gpg_exit(1);
+ g10_exit(1);
}
- gcry_free(configname); configname = NULL;
+ m_free(configname); configname = NULL;
}
if( parse_debug && configname )
log_info("reading options from `%s'\n", configname );
@@ -216,8 +216,8 @@ main( int argc, char **argv )
case 'v': opt.verbose++; break;
case 501:
if( !configfp ) {
- gcry_free(configname);
- configname = gcry_xstrdup(pargs.r.ret_str);
+ m_free(configname);
+ configname = m_strdup(pargs.r.ret_str);
goto next_pass;
}
break;
@@ -230,12 +230,12 @@ main( int argc, char **argv )
if( configfp ) {
fclose( configfp );
configfp = NULL;
- gcry_free(configname); configname = NULL;
+ m_free(configname); configname = NULL;
goto next_pass;
}
- gcry_free( configname ); configname = NULL;
+ m_free( configname ); configname = NULL;
if( log_get_errorcount(0) )
- gpg_exit(2);
+ g10_exit(2);
fprintf(stderr, "%s %s; %s\n", strusage(11), strusage(13), strusage(14) );
fprintf(stderr, "%s\n", strusage(15) );
@@ -245,13 +245,13 @@ main( int argc, char **argv )
become_daemon();
- gpg_exit(0);
+ g10_exit(0);
return 8; /*NEVER REACHED*/
}
void
-gpg_exit( int rc )
+g10_exit( int rc )
{
secmem_term();
rc = rc? rc : log_get_errorcount(0)? 2:0;
diff --git a/g10/gpgv.c b/g10/gpgv.c
new file mode 100644
index 000000000..362f5c528
--- /dev/null
+++ b/g10/gpgv.c
@@ -0,0 +1,372 @@
+/* gpgv.c - The GnuPG signature verify utility
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#ifdef HAVE_DOSISH_SYSTEM
+ #include <fcntl.h> /* for setmode() */
+#endif
+
+#define INCLUDED_BY_MAIN_MODULE 1
+#include "packet.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+#include "options.h"
+#include "keydb.h"
+#include "trustdb.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "filter.h"
+#include "ttyio.h"
+#include "i18n.h"
+#include "status.h"
+#include "g10defs.h"
+
+
+enum cmd_and_opt_values { aNull = 0,
+ oQuiet = 'q',
+ oVerbose = 'v',
+ oBatch = 500,
+ oKeyring,
+ oIgnoreTimeConflict,
+ oStatusFD,
+ oLoggerFD,
+ oHomedir,
+aTest };
+
+
+static ARGPARSE_OPTS opts[] = {
+
+ { 301, NULL, 0, N_("@\nOptions:\n ") },
+
+ { oVerbose, "verbose", 0, N_("verbose") },
+ { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
+ { oKeyring, "keyring" ,2, N_("take the keys from this keyring")},
+ { oIgnoreTimeConflict, "ignore-time-conflict", 0,
+ N_("make timestamp conflicts only a warning") },
+ { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
+ { oLoggerFD, "logger-fd",1, "@" },
+ { oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */
+
+{0} };
+
+
+
+int g10_errors_seen = 0;
+
+#ifdef __riscos__
+RISCOS_GLOBAL_STATICS("GnuPG (gpgv) Heap")
+#endif /* __riscos__ */
+
+const char *
+strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 11: p = "gpgv (GnuPG)";
+ break;
+ case 13: p = VERSION; break;
+ case 17: p = PRINTABLE_OS_NAME; break;
+ case 19: p =
+ _("Please report bugs to <gnupg-bugs@gnu.org>.\n");
+ break;
+ case 1:
+ case 40: p =
+ _("Usage: gpgv [options] [files] (-h for help)");
+ break;
+ case 41: p =
+ _("Syntax: gpg [options] [files]\n"
+ "Check signatures against known trusted keys\n");
+ break;
+
+ default: p = default_strusage(level);
+ }
+ return p;
+}
+
+
+
+
+static void
+i18n_init(void)
+{
+ #ifdef USE_SIMPLE_GETTEXT
+ set_gettext_file( PACKAGE );
+ #else
+ #ifdef ENABLE_NLS
+ #ifdef HAVE_LC_MESSAGES
+ setlocale( LC_TIME, "" );
+ setlocale( LC_MESSAGES, "" );
+ #else
+ setlocale( LC_ALL, "" );
+ #endif
+ bindtextdomain( PACKAGE, G10_LOCALEDIR );
+ textdomain( PACKAGE );
+ #endif
+ #endif
+}
+
+
+int
+main( int argc, char **argv )
+{
+ ARGPARSE_ARGS pargs;
+ int rc=0;
+ STRLIST sl;
+ STRLIST nrings=NULL;
+ unsigned configlineno;
+
+ #ifdef __riscos__
+ riscos_global_defaults();
+ #endif /* __riscos__ */
+
+ log_set_name("gpgv");
+ init_signals();
+ i18n_init();
+ opt.command_fd = -1; /* no command fd */
+ opt.pgp2_workarounds = 1;
+ opt.keyserver_options.auto_key_retrieve = 1;
+ opt.always_trust = 1;
+ opt.batch = 1;
+
+ #if defined (__MINGW32__) || defined (__CYGWIN32__)
+ opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
+ #else
+ opt.homedir = getenv("GNUPGHOME");
+ #endif
+ if( !opt.homedir || !*opt.homedir ) {
+ opt.homedir = GNUPG_HOMEDIR;
+ }
+ tty_no_terminal(1);
+ tty_batchmode(1);
+ disable_dotlock();
+
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags= 1; /* do not remove the args */
+ while( optfile_parse( NULL, NULL, &configlineno, &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case oQuiet: opt.quiet = 1; break;
+ case oVerbose: g10_opt_verbose++;
+ opt.verbose++; opt.list_sigs=1; break;
+ case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
+ case oStatusFD: set_status_fd( pargs.r.ret_int ); break;
+ case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break;
+ case oHomedir: opt.homedir = pargs.r.ret_str; break;
+ default : pargs.err = 2; break;
+ }
+ }
+
+ if( log_get_errorcount(0) )
+ g10_exit(2);
+
+ g10_opt_homedir = opt.homedir;
+
+ if( opt.verbose > 1 )
+ set_packet_list_mode(1);
+
+ if( !nrings ) /* no keyring given: use default one */
+ keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 0, 0);
+ for(sl = nrings; sl; sl = sl->next )
+ keydb_add_resource (sl->d, 0, 0 );
+
+ FREE_STRLIST(nrings);
+
+ if( (rc = verify_signatures( argc, argv ) ))
+ log_error("verify signatures failed: %s\n", g10_errstr(rc) );
+
+ /* cleanup */
+ g10_exit(0);
+ return 8; /*NEVER REACHED*/
+}
+
+
+void
+g10_exit( int rc )
+{
+ rc = rc? rc : log_get_errorcount(0)? 2 :
+ g10_errors_seen? 1 : 0;
+ exit(rc );
+}
+
+
+/* Stub:
+ * We have to override the trustcheck from pkclist.c becuase
+ * this utility assumes that all keys in the keyring are trustworthy
+ */
+int
+check_signatures_trust( PKT_signature *sig )
+{
+ return 0;
+}
+
+
+/* Stub:
+ * We don't have the trustdb , so we have to provide some stub functions
+ * instead
+ */
+int
+get_validity_info (PKT_public_key *pk, const byte *namehash )
+{
+ return '?';
+}
+
+/* Stub: */
+int
+get_ownertrust_info (PKT_public_key *pk)
+{
+ return '?';
+}
+
+unsigned int
+get_ownertrust (PKT_public_key *pk)
+{
+ return TRUST_UNKNOWN;
+}
+
+
+/* Stub:
+ * Because we only work with trusted keys, it does not make sense to
+ * get them from a keyserver
+ */
+int
+keyserver_import_keyid( u32 *keyid, void *dummy )
+{
+ return -1;
+}
+
+/* Stub:
+ * No encryption here but mainproc links to these functions.
+ */
+int
+get_session_key( PKT_pubkey_enc *k, DEK *dek )
+{
+ return G10ERR_GENERAL;
+}
+/* Stub: */
+int
+get_override_session_key( DEK *dek, const char *string )
+{
+ return G10ERR_GENERAL;
+}
+/* Stub: */
+int
+decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
+{
+ return G10ERR_GENERAL;
+}
+
+
+/* Stub:
+ * No interactive commnds, so we don't need the helptexts
+ */
+void
+display_online_help( const char *keyword )
+{
+}
+
+/* Stub:
+ * We don't use secret keys, but getkey.c links to this
+ */
+int
+check_secret_key( PKT_secret_key *sk, int n )
+{
+ return G10ERR_GENERAL;
+}
+
+/* Stub:
+ * No secret key, so no passphrase needed
+ */
+DEK *
+passphrase_to_dek( u32 *keyid, int pubkey_algo,
+ int cipher_algo, STRING2KEY *s2k, int mode,
+ const char *tmp)
+{
+ return NULL;
+}
+
+/* Stubs to avoid linking to photoid.c */
+void show_photos(const struct user_attribute *attrs,int count,PKT_public_key *pk) {}
+int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len) {return 0;}
+char *image_type_to_string(byte type,int string) {return NULL;}
+
+/* Stubs to void linking to ../cipher/cipher.c */
+int string_to_cipher_algo( const char *string ) { return 0; }
+const char *cipher_algo_to_string( int algo ) { return "?";}
+void disable_cipher_algo( int algo ) {}
+int check_cipher_algo( int algo ) { return -1;}
+unsigned int cipher_get_keylen( int algo ) { return 0; }
+unsigned int cipher_get_blocksize( int algo ) {return 0;}
+CIPHER_HANDLE cipher_open( int algo, int mode, int secure ) { return NULL;}
+void cipher_close( CIPHER_HANDLE c ) {}
+int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) { return -1;}
+void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ){}
+void cipher_encrypt( CIPHER_HANDLE c, byte *outbuf,
+ byte *inbuf, unsigned nbytes ) {}
+void cipher_decrypt( CIPHER_HANDLE c, byte *outbuf,
+ byte *inbuf, unsigned nbytes ) {}
+void cipher_sync( CIPHER_HANDLE c ) {}
+
+/* Stubs to avoid linking to ../cipher/random.c */
+void random_dump_stats(void) {}
+int quick_random_gen( int onoff ) { return -1;}
+void randomize_buffer( byte *buffer, size_t length, int level ) {}
+int random_is_faked() { return -1;}
+byte *get_random_bits( size_t nbits, int level, int secure ) { return NULL;}
+void set_random_seed_file( const char *name ) {}
+void update_random_seed_file() {}
+void fast_random_poll() {}
+
+/* Stubs to avoid linking of ../cipher/primegen.c */
+void register_primegen_progress ( void (*cb)( void *, int), void *cb_data ) {}
+MPI generate_secret_prime( unsigned nbits ) { return NULL;}
+MPI generate_public_prime( unsigned nbits ) { return NULL;}
+MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
+ MPI g, MPI **ret_factors ) { return NULL;}
+
+/* Do not link to ../cipher/rndlinux.c */
+void rndlinux_constructor(void) {}
+
+
+/* Stubs to avoid linking to ../util/ttyio.c */
+int tty_batchmode( int onoff ) { return 0; }
+void tty_printf( const char *fmt, ... ) { }
+void tty_print_string( byte *p, size_t n ) { }
+void tty_print_utf8_string( byte *p, size_t n ) {}
+void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
+char *tty_get( const char *prompt ) { return NULL;}
+char *tty_get_hidden( const char *prompt ) {return NULL; }
+void tty_kill_prompt(void) {}
+int tty_get_answer_is_yes( const char *prompt ) {return 0;}
+int tty_no_terminal(int onoff) {return 0;}
+
+/* We do not do any locking, so use these stubs here */
+void disable_dotlock(void) {}
+DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
+int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
+int release_dotlock( DOTLOCK h ) {return 0;}
+void remove_lockfiles(void) {}
diff --git a/g10/helptext.c b/g10/helptext.c
index 4a7a14fde..0150c549c 100644
--- a/g10/helptext.c
+++ b/g10/helptext.c
@@ -1,5 +1,5 @@
/* helptext.c - English help texts
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -49,6 +49,13 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
"to do with the (implicitly created) web-of-certificates."
)},
+{ "edit_ownertrust.set_ultimate.okay", N_(
+ "To build the Web-of-Trust, GnuPG needs to know which keys are\n"
+ "ultimately trusted - those are usually the keys for which you have\n"
+ "access to the secret key. Answer \"yes\" to set this key to\n"
+ "ultimately trusted\n"
+)},
+
{ "revoked_key.override", N_(
"If you want to use this revoked key anyway, answer \"yes\"."
)},
@@ -87,6 +94,12 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
"with them are quite large and very slow to verify."
)},
+{ "keygen.algo.rsa_se", N_(
+"In general it is not a good idea to use the same key for signing and\n"
+"encryption. This algorithm should only be used in certain domains.\n"
+"Please consult your security expert first."
+)},
+
{ "keygen.size", N_(
"Enter the size of the key"
@@ -145,6 +158,29 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
"Answer \"yes\" or \"no\""
)},
+{ "sign_uid.class", N_(
+"When you sign a user ID on a key, you should first verify that the key\n"
+"belongs to the person named in the user ID. It is useful for others to\n"
+"know how carefully you verified this.\n\n"
+"\"0\" means you make no particular claim as to how carefully you verified the\n"
+" key.\n\n"
+"\"1\" means you believe the key is owned by the person who claims to own it\n"
+" but you could not, or did not verify the key at all. This is useful for\n"
+" a \"persona\" verification, where you sign the key of a pseudonymous user.\n\n"
+"\"2\" means you did casual verification of the key. For example, this could\n"
+" mean that you verified the key fingerprint and checked the user ID on the\n"
+" key against a photo ID.\n\n"
+"\"3\" means you did extensive verification of the key. For example, this could\n"
+" mean that you verified the key fingerprint with the owner of the key in\n"
+" person, and that you checked, by means of a hard to forge document with a\n"
+" photo ID (such as a passport) that the name of the key owner matches the\n"
+" name in the user ID on the key, and finally that you verified (by exchange\n"
+" of email) that the email address on the key belongs to the key owner.\n\n"
+"Note that the examples given above for levels 2 and 3 are *only* examples.\n"
+"In the end, it is up to you to decide just what \"casual\" and \"extensive\"\n"
+"mean to you when you sign other keys.\n\n"
+"If you don't know what the right answer is, answer \"0\"."
+)},
{ "change_passwd.empty.okay", N_(
"Answer \"yes\" or \"no\""
@@ -197,11 +233,16 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
"a second one is available."
)},
+{ "keyedit.updpref.okay", N_(
+ "Change the preferences of all user IDs (or just of the selected ones)\n"
+ "to the current list of preferences. The timestamp of all affected\n"
+ "self-signatures will be advanced by one second.\n"
+)},
+
{ "passphrase.enter", N_(
""
"Please enter the passhrase; this is a secret sentence \n"
-" Blurb, blurb,.... "
)},
@@ -231,7 +272,7 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = {
" \"Key has been compromised\"\n"
" Use this if you have a reason to believe that unauthorized persons\n"
" got access to your secret key.\n"
- " \"Key is superseeded\"\n"
+ " \"Key is superseded\"\n"
" Use this if you have replaced this key with a newer one.\n"
" \"Key is no longer used\"\n"
" Use this if you have retired this key.\n"
@@ -271,5 +312,3 @@ display_online_help( const char *keyword )
}
tty_printf("\n");
}
-
-
diff --git a/g10/hkp.c b/g10/hkp.c
index 2f6031361..7b96570cd 100644
--- a/g10/hkp.c
+++ b/g10/hkp.c
@@ -1,5 +1,5 @@
-/* hkp.c - Horrowitz Keyserver Protocol
- * Copyright (C) 1999 Free Software Foundation, Inc.
+/* hkp.c - Horowitz Keyserver Protocol
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -34,6 +34,7 @@
#include "filter.h"
#include "http.h"
#include "main.h"
+#include "keyserver-internal.h"
static int urlencode_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len);
@@ -47,95 +48,72 @@ static int urlencode_filter( void *opaque, int control,
* or other error codes.
*/
int
-hkp_ask_import( u32 *keyid )
+hkp_ask_import( KEYDB_SEARCH_DESC *desc, void *stats_handle)
{
- #ifdef HAVE_DOSISH_SYSTEM
- return -1;
- #else
struct http_context hd;
char *request;
int rc;
- unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
+ unsigned int hflags = opt.keyserver_options.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
+ u32 key[2];
- if( !opt.keyserver_name )
- return -1;
- log_info(_("requesting key %08lX from %s ...\n"), (ulong)keyid[1],
- opt.keyserver_name );
- request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
+ if(desc->mode==KEYDB_SEARCH_MODE_FPR20)
+ keyid_from_fingerprint(desc->u.fpr,MAX_FINGERPRINT_LEN,key);
+ else if(desc->mode==KEYDB_SEARCH_MODE_LONG_KID ||
+ desc->mode==KEYDB_SEARCH_MODE_SHORT_KID)
+ {
+ key[0]=desc->u.kid[0];
+ key[1]=desc->u.kid[1];
+ }
+ else
+ return -1; /* HKP does not support v3 fingerprints */
+
+ log_info(_("requesting key %08lX from HKP keyserver %s\n"),
+ (ulong)key[1],opt.keyserver_host );
+ request = m_alloc( strlen( opt.keyserver_host ) + 100 );
/* hkp does not accept the long keyid - we should really write a
* nicer one :-)
* FIXME: request binary mode - need to pass no_armor mode
* down to the import function. Marc told that there is such a
* binary mode ... how?
*/
- sprintf( request, "x-hkp://%s:11371/pks/lookup?op=get&search=0x%08lX",
- opt.keyserver_name, (ulong)keyid[1] );
+
+ if(opt.keyserver_options.broken_http_proxy)
+ hflags |= HTTP_FLAG_NO_SHUTDOWN;
+
+ sprintf(request,"x-hkp://%s%s%s/pks/lookup?op=get&search=0x%08lX",
+ opt.keyserver_host,
+ atoi(opt.keyserver_port)>0?":":"",
+ atoi(opt.keyserver_port)>0?opt.keyserver_port:"",
+ (ulong)key[1] );
+
+ if(opt.keyserver_options.verbose>2)
+ log_info("request is \"%s\"\n",request);
+
rc = http_open_document( &hd, request, hflags );
if( rc ) {
log_info(_("can't get key from keyserver: %s\n"),
- rc == GPGERR_NETWORK? strerror(errno)
- : gpg_errstr(rc) );
+ rc == G10ERR_NETWORK? strerror(errno)
+ : g10_errstr(rc) );
}
else {
- rc = import_keys_stream( hd.fp_read , 0 );
+ rc = import_keys_stream( hd.fp_read, 0, stats_handle);
http_close( &hd );
}
- gcry_free( request );
+ m_free( request );
return rc;
- #endif
-}
-
-
-
-int
-hkp_import( STRLIST users )
-{
- #ifdef HAVE_DOSISH_SYSTEM
- return -1;
- #else
- if( !opt.keyserver_name ) {
- log_error(_("no keyserver known (use option --keyserver)\n"));
- return -1;
- }
-
- for( ; users; users = users->next ) {
- u32 kid[2];
- int type = classify_user_id( users->d, kid, NULL, NULL, NULL );
- if( type != 10 && type != 11 ) {
- log_info(_("%s: not a valid key ID\n"), users->d );
- continue;
- }
- /* because the function may use log_info in some situations, the
- * errorcounter ist not increaed and the program will return
- * with success - which is not good when this function is used.
- */
- if( hkp_ask_import( kid ) )
- log_inc_errorcount();
- }
- return 0;
- #endif
}
-
int
hkp_export( STRLIST users )
{
- #ifdef HAVE_DOSISH_SYSTEM
- return -1;
- #else
int rc;
armor_filter_context_t afx;
IOBUF temp = iobuf_temp();
struct http_context hd;
char *request;
unsigned int status;
- unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
-
- if( !opt.keyserver_name ) {
- log_error(_("no keyserver known (use option --keyserver)\n"));
- return -1;
- }
+ unsigned int hflags = opt.keyserver_options.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0;
iobuf_push_filter( temp, urlencode_filter, NULL );
@@ -151,23 +129,34 @@ hkp_export( STRLIST users )
iobuf_flush_temp( temp );
- request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 );
- sprintf( request, "x-hkp://%s:11371/pks/add", opt.keyserver_name );
+ request = m_alloc( strlen( opt.keyserver_host ) + 100 );
+
+ if(opt.keyserver_options.broken_http_proxy)
+ hflags |= HTTP_FLAG_NO_SHUTDOWN;
+
+ sprintf( request, "x-hkp://%s%s%s/pks/add",
+ opt.keyserver_host,
+ atoi(opt.keyserver_port)>0?":":"",
+ atoi(opt.keyserver_port)>0?opt.keyserver_port:"");
+
+ if(opt.keyserver_options.verbose>2)
+ log_info("request is \"%s\"\n",request);
+
rc = http_open( &hd, HTTP_REQ_POST, request , hflags );
if( rc ) {
log_error(_("can't connect to `%s': %s\n"),
- opt.keyserver_name,
- rc == GPGERR_NETWORK? strerror(errno)
- : gpg_errstr(rc) );
+ opt.keyserver_host,
+ rc == G10ERR_NETWORK? strerror(errno)
+ : g10_errstr(rc) );
iobuf_close(temp);
- gcry_free( request );
+ m_free( request );
return rc;
}
sprintf( request, "Content-Length: %u\n",
(unsigned)iobuf_get_temp_length(temp) + 9 );
iobuf_writestr( hd.fp_write, request );
- gcry_free( request );
+ m_free( request );
http_start_data( &hd );
iobuf_writestr( hd.fp_write, "keytext=" );
@@ -180,26 +169,28 @@ hkp_export( STRLIST users )
rc = http_wait_response( &hd, &status );
if( rc ) {
log_error(_("error sending to `%s': %s\n"),
- opt.keyserver_name, gpg_errstr(rc) );
+ opt.keyserver_host, g10_errstr(rc) );
}
else {
#if 1
if( opt.verbose ) {
int c;
while( (c=iobuf_get(hd.fp_read)) != EOF )
+ if ( c >= 32 && c < 127 )
putchar( c );
+ else
+ putchar ( '?' );
}
#endif
if( (status/100) == 2 )
log_info(_("success sending to `%s' (status=%u)\n"),
- opt.keyserver_name, status );
+ opt.keyserver_host, status );
else
log_error(_("failed sending to `%s': status=%u\n"),
- opt.keyserver_name, status );
+ opt.keyserver_host, status );
}
http_close( &hd );
return rc;
- #endif
}
static int
@@ -228,3 +219,373 @@ urlencode_filter( void *opaque, int control,
return rc;
}
+static int
+write_quoted(IOBUF a, const char *buf, char delim)
+{
+ char quoted[5];
+
+ sprintf(quoted,"\\x%02X",delim);
+
+ while(*buf)
+ {
+ if(*buf==delim)
+ {
+ if(iobuf_writestr(a,quoted))
+ return -1;
+ }
+ else if(*buf=='\\')
+ {
+ if(iobuf_writestr(a,"\\x5c"))
+ return -1;
+ }
+ else
+ {
+ if(iobuf_writebyte(a,*buf))
+ return -1;
+ }
+
+ buf++;
+ }
+
+ return 0;
+}
+
+/* pub 2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw &lt;<a href="/pks/lookup?op=get&search=0x3CB3B415">dshaw@jabberwocky.com</a>&gt; */
+
+/* Luckily enough, both the HKP server and NAI HKP interface to their
+ LDAP server are close enough in output so the same function can
+ parse them both. */
+
+static int
+parse_hkp_index(IOBUF buffer,char *line)
+{
+ static int open=0,revoked=0;
+ static char *key=NULL;
+#ifdef __riscos__
+ static char *uid=NULL;
+#else
+ static unsigned char *uid=NULL;
+#endif
+ static u32 bits,createtime;
+ int ret=0;
+
+ /* printf("Open %d, LINE: %s, uid: %s\n",open,line,uid); */
+
+ /* Try and catch some bastardization of HKP. If we don't have
+ certain unchanging landmarks, we can't reliably parse the
+ response. */
+ if(open && ascii_memcasecmp(line,"</pre>",6)!=0 &&
+ ascii_memcasecmp(line,"pub ",5)!=0 &&
+ ascii_memcasecmp(line," ",5)!=0)
+ {
+ m_free(key);
+ m_free(uid);
+ log_error(_("this keyserver is not fully HKP compatible\n"));
+ return -1;
+ }
+
+ /* For multiple UIDs */
+ if(open && uid!=NULL)
+ {
+ ret=0;
+
+ if(!(revoked && !opt.keyserver_options.include_revoked))
+ {
+ char intstr[11];
+
+ if(key)
+ write_quoted(buffer,key,':');
+ iobuf_writestr(buffer,":");
+ write_quoted(buffer,uid,':');
+ iobuf_writestr(buffer,":");
+ iobuf_writestr(buffer,revoked?"1:":":");
+ sprintf(intstr,"%u",createtime);
+ write_quoted(buffer,intstr,':');
+ iobuf_writestr(buffer,"::::");
+ sprintf(intstr,"%u",bits);
+ write_quoted(buffer,intstr,':');
+ iobuf_writestr(buffer,"\n");
+
+ ret=1;
+ }
+
+ if(strncmp(line," ",5)!=0)
+ {
+ revoked=0;
+ m_free(key);
+ m_free(uid);
+ uid=NULL;
+ open=0;
+ }
+ }
+
+ if(ascii_memcasecmp(line,"pub ",5)==0)
+ {
+ char *tok,*temp;
+
+ open=1;
+
+ line+=4;
+
+ tok=strsep(&line,"/");
+ if(tok==NULL)
+ return ret;
+
+ bits=atoi(tok);
+
+ tok=strsep(&line,">");
+ if(tok==NULL)
+ return ret;
+
+ tok=strsep(&line,"<");
+ if(tok==NULL)
+ return ret;
+
+ key=m_strdup(tok);
+
+ tok=strsep(&line," ");
+ if(tok==NULL)
+ return ret;
+
+ tok=strsep(&line," ");
+ if(tok==NULL)
+ return ret;
+
+ /* The date parser wants '-' instead of '/', so... */
+ temp=tok;
+ while(*temp!='\0')
+ {
+ if(*temp=='/')
+ *temp='-';
+
+ temp++;
+ }
+
+ createtime=scan_isodatestr(tok);
+ }
+
+ if(open)
+ {
+ int uidindex=0;
+
+ if(line==NULL)
+ {
+ uid=m_strdup("Key index corrupted");
+ return ret;
+ }
+
+ /* All that's left is the user name. Strip off anything
+ <between brackets> and de-urlencode it. */
+
+ while(*line==' ' && *line!='\0')
+ line++;
+
+ if(strncmp(line,"*** KEY REVOKED ***",19)==0)
+ {
+ revoked=1;
+ return ret;
+ }
+
+ uid=m_alloc(strlen(line)+1);
+
+ while(*line!='\0')
+ {
+ switch(*line)
+ {
+ case '<':
+ while(*line!='>' && *line!='\0')
+ line++;
+
+ if(*line!='\0')
+ line++;
+ break;
+
+ case '&':
+ if((*(line+1)!='\0' && tolower(*(line+1))=='l') &&
+ (*(line+2)!='\0' && tolower(*(line+2))=='t') &&
+ (*(line+3)!='\0' && *(line+3)==';'))
+ {
+ uid[uidindex++]='<';
+ line+=4;
+ break;
+ }
+ else if((*(line+1)!='\0' && tolower(*(line+1))=='g') &&
+ (*(line+2)!='\0' && tolower(*(line+2))=='t') &&
+ (*(line+3)!='\0' && *(line+3)==';'))
+ {
+ uid[uidindex++]='>';
+ line+=4;
+ break;
+ }
+ else if((*(line+1)!='\0' && tolower(*(line+1))=='a') &&
+ (*(line+2)!='\0' && tolower(*(line+2))=='m') &&
+ (*(line+3)!='\0' && tolower(*(line+3))=='p') &&
+ (*(line+4)!='\0' && *(line+4)==';'))
+ {
+ uid[uidindex++]='&';
+ line+=5;
+ break;
+ }
+
+ default:
+ uid[uidindex++]=*line;
+ line++;
+ break;
+ }
+ }
+
+ uid[uidindex]='\0';
+
+ /* Chop off the trailing \r, \n, or both. This is fussy as the
+ true HKP servers have \r\n, and the NAI HKP servers have just
+ \n. */
+
+ if(isspace(uid[uidindex-1]))
+ uid[uidindex-1]='\0';
+
+ if(isspace(uid[uidindex-2]))
+ uid[uidindex-2]='\0';
+ }
+
+ return ret;
+}
+
+int hkp_search(STRLIST tokens)
+{
+ int rc=0,len=0,max,first=1;
+ unsigned int maxlen=1024,buflen=0;
+#ifndef __riscos__
+ unsigned char *searchstr=NULL,*searchurl;
+ unsigned char *request;
+#else
+ char *searchstr=NULL,*searchurl;
+ char *request;
+#endif
+ struct http_context hd;
+ unsigned int hflags=opt.keyserver_options.honor_http_proxy?HTTP_FLAG_TRY_PROXY:0;
+ byte *line=NULL;
+
+ /* Glue the tokens together to make a search string */
+
+ for(;tokens;tokens=tokens->next)
+ {
+ len+=strlen(tokens->d)+1;
+
+ searchstr=m_realloc(searchstr,len+1);
+ if(first)
+ {
+ searchstr[0]='\0';
+ first=0;
+ }
+
+ strcat(searchstr,tokens->d);
+ strcat(searchstr," ");
+ }
+
+ if(len<=1)
+ {
+ m_free(searchstr);
+ return 0;
+ }
+
+ searchstr[len-1]='\0';
+
+ log_info(_("searching for \"%s\" from HKP server %s\n"),
+ searchstr,opt.keyserver_host);
+
+ /* Now make it url-ish */
+
+ max=0;
+ len=0;
+ searchurl=NULL;
+ request=searchstr;
+
+ while(*request!='\0')
+ {
+ if(max-len<3)
+ {
+ max+=100;
+ searchurl=m_realloc(searchurl,max+1); /* Note +1 for \0 */
+ }
+
+ if(isalnum(*request) || *request=='-')
+ searchurl[len++]=*request;
+ else if(*request==' ')
+ searchurl[len++]='+';
+ else
+ {
+ sprintf(&searchurl[len],"%%%02X",*request);
+ len+=3;
+ }
+
+ request++;
+ }
+
+ searchurl[len]='\0';
+
+ request=m_alloc(strlen(opt.keyserver_host) + 100 + strlen(searchurl));
+
+ if(opt.keyserver_options.broken_http_proxy)
+ hflags |= HTTP_FLAG_NO_SHUTDOWN;
+
+ sprintf(request,"x-hkp://%s%s%s/pks/lookup?op=index&search=%s",
+ opt.keyserver_host,
+ atoi(opt.keyserver_port)>0?":":"",
+ atoi(opt.keyserver_port)>0?opt.keyserver_port:"",
+ searchurl);
+
+ if(opt.keyserver_options.verbose>2)
+ log_info("request is \"%s\"\n",request);
+
+ rc=http_open_document(&hd,request,hflags);
+ if(rc)
+ {
+ log_error(_("can't search keyserver: %s\n"),
+ rc==G10ERR_NETWORK?strerror(errno):g10_errstr(rc));
+ }
+ else
+ {
+ IOBUF buffer;
+ int count=1;
+ int ret;
+
+ buffer=iobuf_temp();
+
+ rc=1;
+ while(rc!=0)
+ {
+ /* This is a judgement call. Is it better to slurp up all
+ the results before prompting the user? On the one hand,
+ it probably makes the keyserver happier to not be blocked
+ on sending for a long time while the user picks a key.
+ On the other hand, it might be nice for the server to be
+ able to stop sending before a large search result page is
+ complete. */
+
+ rc=iobuf_read_line(hd.fp_read,&line,&buflen,&maxlen);
+
+ ret=parse_hkp_index(buffer,line);
+ if(ret==-1)
+ break;
+
+ if(rc!=0)
+ count+=ret;
+ }
+
+ http_close(&hd);
+
+ count--;
+
+ if(ret>-1)
+ keyserver_search_prompt(buffer,count,searchstr);
+
+ iobuf_close(buffer);
+ m_free(line);
+ }
+
+ m_free(request);
+ m_free(searchurl);
+ m_free(searchstr);
+
+ return rc;
+}
diff --git a/g10/hkp.h b/g10/hkp.h
index 64f049739..1fbf123f5 100644
--- a/g10/hkp.h
+++ b/g10/hkp.h
@@ -1,5 +1,5 @@
-/* hkp.h - Horrowitz Keyserver Protocol
- * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* hkp.h - Horowitz Keyserver Protocol
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,13 +18,12 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_HKP_H
-#define GPG_HKP_H 1
+#ifndef G10_HKP_H
+#define G10_HKP_H 1
-
-int hkp_ask_import( u32 *keyid );
+int hkp_ask_import( KEYDB_SEARCH_DESC *desc, void *stats_handle);
int hkp_import( STRLIST users );
int hkp_export( STRLIST users );
+int hkp_search(STRLIST tokens);
-
-#endif /*GPG_HKP_H*/
+#endif /*G10_HKP_H*/
diff --git a/g10/import.c b/g10/import.c
index 7e2e5bc18..ccc665145 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1,5 +1,5 @@
/* import.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,15 +29,15 @@
#include "packet.h"
#include "errors.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "trustdb.h"
#include "main.h"
#include "i18n.h"
#include "status.h"
+#include "keyserver-internal.h"
-
-static struct {
+struct stats_s {
ulong count;
ulong no_user_id;
ulong imported;
@@ -51,18 +51,22 @@ static struct {
ulong secret_imported;
ulong secret_dups;
ulong skipped_new_keys;
-} stats;
+};
-static int import( IOBUF inp, int fast, const char* fname );
-static void print_stats(void);
+static int import( IOBUF inp, int fast, const char* fname,
+ struct stats_s *stats );
static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
-static int import_one( const char *fname, KBNODE keyblock, int fast );
-static int import_secret_one( const char *fname, KBNODE keyblock );
-static int import_revoke_cert( const char *fname, KBNODE node );
+static void revocation_present(KBNODE keyblock);
+static void remove_bad_stuff (KBNODE keyblock);
+static int import_one( const char *fname, KBNODE keyblock, int fast,
+ struct stats_s *stats);
+static int import_secret_one( const char *fname, KBNODE keyblock,
+ struct stats_s *stats );
+static int import_revoke_cert( const char *fname, KBNODE node,
+ struct stats_s *stats);
static int chk_self_sigs( const char *fname, KBNODE keyblock,
PKT_public_key *pk, u32 *keyid );
-static void mark_non_selfsigned_uids_valid( KBNODE keyblock, u32 *kid );
static int delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid );
static int merge_blocks( const char *fname, KBNODE keyblock_orig,
KBNODE keyblock, u32 *keyid,
@@ -77,6 +81,18 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
const char *fname, u32 *keyid );
+void *
+import_new_stats_handle (void)
+{
+ return m_alloc_clear ( sizeof (struct stats_s) );
+}
+
+void
+import_release_stats_handle (void *p)
+{
+ m_free (p);
+}
+
/****************
* Import the public keys from the given filename. Input may be armored.
* This function rejects all keys which are not validly self signed on at
@@ -109,12 +125,13 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
*
*/
void
-import_keys( char **fnames, int nnames, int fast )
+import_keys( char **fnames, int nnames, int fast, void *stats_handle )
{
int i;
+ struct stats_s *stats = stats_handle;
- /* fixme: don't use static variables */
- memset( &stats, 0, sizeof( stats ) );
+ if (!stats)
+ stats = import_new_stats_handle ();
if( !fnames && !nnames )
nnames = 1; /* Ohh what a ugly hack to jump into the loop */
@@ -127,36 +144,42 @@ import_keys( char **fnames, int nnames, int fast )
if( !inp )
log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
else {
- int rc = import( inp, fast, fname );
+ int rc = import( inp, fast, fname, stats );
iobuf_close(inp);
if( rc )
log_error("import from `%s' failed: %s\n", fname,
- gpg_errstr(rc) );
+ g10_errstr(rc) );
}
if( !fname )
break;
}
- print_stats();
- if( !fast )
- sync_trustdb();
+ if (!stats_handle) {
+ import_print_stats (stats);
+ import_release_stats_handle (stats);
+ }
+
}
int
-import_keys_stream( IOBUF inp, int fast )
+import_keys_stream( IOBUF inp, int fast, void *stats_handle )
{
int rc = 0;
+ struct stats_s *stats = stats_handle;
+
+ if (!stats)
+ stats = import_new_stats_handle ();
+
+ rc = import( inp, fast, "[stream]", stats);
+ if (!stats_handle) {
+ import_print_stats (stats);
+ import_release_stats_handle (stats);
+ }
- /* fixme: don't use static variables */
- memset( &stats, 0, sizeof( stats ) );
- rc = import( inp, fast, "[stream]" );
- print_stats();
- if( !fast )
- sync_trustdb();
return rc;
}
static int
-import( IOBUF inp, int fast, const char* fname )
+import( IOBUF inp, int fast, const char* fname, struct stats_s *stats )
{
PACKET *pending_pkt = NULL;
KBNODE keyblock;
@@ -165,19 +188,20 @@ import( IOBUF inp, int fast, const char* fname )
getkey_disable_caches();
if( !opt.no_armor ) { /* armored reading is not disabled */
- armor_filter_context_t *afx = gcry_xcalloc( 1, sizeof *afx );
+ armor_filter_context_t *afx = m_alloc_clear( sizeof *afx );
afx->only_keyblocks = 1;
iobuf_push_filter2( inp, armor_filter, afx, 1 );
}
while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
+ remove_bad_stuff (keyblock);
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
- rc = import_one( fname, keyblock, fast );
- else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
- rc = import_secret_one( fname, keyblock );
+ rc = import_one( fname, keyblock, fast, stats );
+ else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
+ rc = import_secret_one( fname, keyblock, stats );
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
- rc = import_revoke_cert( fname, keyblock );
+ rc = import_revoke_cert( fname, keyblock, stats );
else {
log_info( _("skipping block of type %d\n"),
keyblock->pkt->pkttype );
@@ -185,67 +209,70 @@ import( IOBUF inp, int fast, const char* fname )
release_kbnode(keyblock);
if( rc )
break;
- if( !(++stats.count % 100) && !opt.quiet )
- log_info(_("%lu keys so far processed\n"), stats.count );
+ if( !(++stats->count % 100) && !opt.quiet )
+ log_info(_("%lu keys so far processed\n"), stats->count );
}
if( rc == -1 )
rc = 0;
- else if( rc && rc != GPGERR_INV_KEYRING )
- log_error( _("error reading `%s': %s\n"), fname, gpg_errstr(rc));
+ else if( rc && rc != G10ERR_INV_KEYRING )
+ log_error( _("error reading `%s': %s\n"), fname, g10_errstr(rc));
return rc;
}
-static void
-print_stats()
+void
+import_print_stats (void *hd)
{
+ struct stats_s *stats = hd;
+
if( !opt.quiet ) {
- log_info(_("Total number processed: %lu\n"), stats.count );
- if( stats.skipped_new_keys )
+ log_info(_("Total number processed: %lu\n"), stats->count );
+ if( stats->skipped_new_keys )
log_info(_(" skipped new keys: %lu\n"),
- stats.skipped_new_keys );
- if( stats.no_user_id )
- log_info(_(" w/o user IDs: %lu\n"), stats.no_user_id );
- if( stats.imported || stats.imported_rsa ) {
- log_info(_(" imported: %lu"), stats.imported );
- if( stats.imported_rsa )
- fprintf(stderr, " (RSA: %lu)", stats.imported_rsa );
+ stats->skipped_new_keys );
+ if( stats->no_user_id )
+ log_info(_(" w/o user IDs: %lu\n"), stats->no_user_id );
+ if( stats->imported || stats->imported_rsa ) {
+ log_info(_(" imported: %lu"), stats->imported );
+ if( stats->imported_rsa )
+ fprintf(stderr, " (RSA: %lu)", stats->imported_rsa );
putc('\n', stderr);
}
- if( stats.unchanged )
- log_info(_(" unchanged: %lu\n"), stats.unchanged );
- if( stats.n_uids )
- log_info(_(" new user IDs: %lu\n"), stats.n_uids );
- if( stats.n_subk )
- log_info(_(" new subkeys: %lu\n"), stats.n_subk );
- if( stats.n_sigs )
- log_info(_(" new signatures: %lu\n"), stats.n_sigs );
- if( stats.n_revoc )
- log_info(_(" new key revocations: %lu\n"), stats.n_revoc );
- if( stats.secret_read )
- log_info(_(" secret keys read: %lu\n"), stats.secret_read );
- if( stats.secret_imported )
- log_info(_(" secret keys imported: %lu\n"), stats.secret_imported );
- if( stats.secret_dups )
- log_info(_(" secret keys unchanged: %lu\n"), stats.secret_dups );
+ if( stats->unchanged )
+ log_info(_(" unchanged: %lu\n"), stats->unchanged );
+ if( stats->n_uids )
+ log_info(_(" new user IDs: %lu\n"), stats->n_uids );
+ if( stats->n_subk )
+ log_info(_(" new subkeys: %lu\n"), stats->n_subk );
+ if( stats->n_sigs )
+ log_info(_(" new signatures: %lu\n"), stats->n_sigs );
+ if( stats->n_revoc )
+ log_info(_(" new key revocations: %lu\n"), stats->n_revoc );
+ if( stats->secret_read )
+ log_info(_(" secret keys read: %lu\n"), stats->secret_read );
+ if( stats->secret_imported )
+ log_info(_(" secret keys imported: %lu\n"), stats->secret_imported );
+ if( stats->secret_dups )
+ log_info(_(" secret keys unchanged: %lu\n"), stats->secret_dups );
}
if( is_status_enabled() ) {
- char buf[12*20];
- sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
- stats.count,
- stats.no_user_id,
- stats.imported,
- stats.imported_rsa,
- stats.unchanged,
- stats.n_uids,
- stats.n_subk,
- stats.n_sigs,
- stats.n_revoc,
- stats.secret_read,
- stats.secret_imported,
- stats.secret_dups);
+ char buf[13*20];
+ sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ stats->count,
+ stats->no_user_id,
+ stats->imported,
+ stats->imported_rsa,
+ stats->unchanged,
+ stats->n_uids,
+ stats->n_subk,
+ stats->n_sigs,
+ stats->n_revoc,
+ stats->secret_read,
+ stats->secret_imported,
+ stats->secret_dups,
+ stats->skipped_new_keys );
write_status_text( STATUS_IMPORT_RES, buf );
}
}
@@ -272,13 +299,13 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
}
else
in_cert = 0;
- pkt = gcry_xmalloc( sizeof *pkt );
+ pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
- while( (rc=parse_packet(a, pkt, NULL)) != -1 ) {
+ while( (rc=parse_packet(a, pkt)) != -1 ) {
if( rc ) { /* ignore errors */
- if( rc != GPGERR_UNKNOWN_PACKET ) {
- log_error("read_block: read error: %s\n", gpg_errstr(rc) );
- rc = GPGERR_INV_KEYRING;
+ if( rc != G10ERR_UNKNOWN_PACKET ) {
+ log_error("read_block: read error: %s\n", g10_errstr(rc) );
+ rc = G10ERR_INV_KEYRING;
goto ready;
}
free_packet( pkt );
@@ -300,11 +327,11 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
case PKT_COMPRESSED:
if( pkt->pkt.compressed->algorithm < 1
|| pkt->pkt.compressed->algorithm > 2 ) {
- rc = GPGERR_COMPR_ALGO;
+ rc = G10ERR_COMPR_ALGO;
goto ready;
}
{
- compress_filter_context_t *cfx = gcry_xcalloc( 1, sizeof *cfx );
+ compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx );
cfx->algo = pkt->pkt.compressed->algorithm;
pkt->pkt.compressed->buf = NULL;
iobuf_push_filter2( a, compress_filter, cfx, 1 );
@@ -313,6 +340,11 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
init_packet(pkt);
break;
+ case PKT_RING_TRUST:
+ /* skip those packets */
+ free_packet( pkt );
+ init_packet(pkt);
+ break;
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
@@ -328,7 +360,7 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
root = new_kbnode( pkt );
else
add_kbnode( root, new_kbnode( pkt ) );
- pkt = gcry_xmalloc( sizeof *pkt );
+ pkt = m_alloc( sizeof *pkt );
}
init_packet(pkt);
break;
@@ -343,19 +375,125 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
else
*ret_root = root;
free_packet( pkt );
- gcry_free( pkt );
+ m_free( pkt );
return rc;
}
+static void
+remove_bad_stuff (KBNODE keyblock)
+{
+ KBNODE node;
+
+ for (node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_SIGNATURE ) {
+ /* delete the subpackets we used to use for the
+ verification cache */
+ delete_sig_subpkt (node->pkt->pkt.signature->unhashed,
+ SIGSUBPKT_PRIV_VERIFY_CACHE);
+ }
+ }
+}
+
+/* Clean the subkeys on a pk so that they each have at most 1 binding
+ sig and at most 1 revocation sig. This works based solely on the
+ timestamps like the rest of gpg. If the standard does get
+ revocation targets, this may need to be revised. */
+
+static int
+clean_subkeys(KBNODE keyblock,u32 *keyid)
+{
+ int removed=0;
+ KBNODE node,sknode=keyblock;
+
+ while((sknode=find_kbnode(sknode,PKT_PUBLIC_SUBKEY)))
+ {
+ KBNODE bsnode=NULL,rsnode=NULL;
+ u32 bsdate=0,rsdate=0;
+
+ sknode=sknode->next;
+
+ for(node=sknode;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_SIGNATURE)
+ {
+ PKT_signature *sig=node->pkt->pkt.signature;
+
+ /* We're only interested in valid sigs */
+ if(check_key_signature(keyblock,node,NULL))
+ continue;
+
+ if(IS_SUBKEY_SIG(sig) && bsdate<=sig->timestamp)
+ {
+ bsnode=node;
+ bsdate=sig->timestamp;
+ }
+ else if(IS_SUBKEY_REV(sig) && rsdate<=sig->timestamp)
+ {
+ rsnode=node;
+ rsdate=sig->timestamp;
+ }
+ /* If it's not a subkey sig or rev, then it shouldn't be
+ here so ignore it. */
+ }
+ else
+ break;
+ }
+
+ /* We now know the most recent binding sig and revocation sig
+ (if any). If the binding sig is more recent than the
+ revocation sig, strip everything but the binding sig. If the
+ revocation sig is more recent than the binding sig, strip
+ everything but the binding sig and the revocation sig. */
+
+ if(bsdate>=rsdate)
+ {
+ rsnode=NULL;
+ rsdate=0;
+ }
+
+ for(node=sknode;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_SIGNATURE)
+ {
+ PKT_signature *sig=node->pkt->pkt.signature;
+
+ if(IS_SUBKEY_SIG(sig) && node!=bsnode)
+ {
+ delete_kbnode(node);
+ removed++;
+ }
+ else if(IS_SUBKEY_REV(sig) && node!=rsnode)
+ {
+ delete_kbnode(node);
+ removed++;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ if(removed)
+ {
+ log_info(_("key %08lX: removed multiple subkey binding\n"),
+ (ulong)keyid[1]);
+ commit_kbnode(&keyblock);
+ }
+
+ return removed;
+}
+
+
/****************
* Try to import one keyblock. Return an error only in serious cases, but
* never for an invalid keyblock. It uses log_error to increase the
* internal errorcount, so that invalid input can be detected by programs
- * which called gpg.
+ * which called g10.
*/
static int
-import_one( const char *fname, KBNODE keyblock, int fast )
+import_one( const char *fname, KBNODE keyblock, int fast,
+ struct stats_s *stats )
{
PKT_public_key *pk;
PKT_public_key *pk_orig;
@@ -395,8 +533,18 @@ import_one( const char *fname, KBNODE keyblock, int fast )
if( rc )
return rc== -1? 0:rc;
+ /* If we allow such a thing, mark unsigned uids as valid */
if( opt.allow_non_selfsigned_uid )
- mark_non_selfsigned_uids_valid( keyblock, keyid );
+ for( node=keyblock; node; node = node->next )
+ if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
+ {
+ char *user=utf8_to_native(node->pkt->pkt.user_id->name,
+ node->pkt->pkt.user_id->len,0);
+ node->flag |= 1;
+ log_info( _("key %08lX: accepted non self-signed user ID '%s'\n"),
+ (ulong)keyid[1],user);
+ m_free(user);
+ }
if( !delete_inv_parts( fname, keyblock, keyid ) ) {
if( !opt.quiet ) {
@@ -404,47 +552,63 @@ import_one( const char *fname, KBNODE keyblock, int fast )
(ulong)keyid[1]);
log_info(_("this may be caused by a missing self-signature\n"));
}
- stats.no_user_id++;
+ stats->no_user_id++;
return 0;
}
-
/* do we have this key already in one of our pubrings ? */
- pk_orig = gcry_xcalloc( 1, sizeof *pk_orig );
+ pk_orig = m_alloc_clear( sizeof *pk_orig );
rc = get_pubkey( pk_orig, keyid );
- if( rc && rc != GPGERR_NO_PUBKEY ) {
+ if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY ) {
log_error( _("key %08lX: public key not found: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
+ (ulong)keyid[1], g10_errstr(rc));
}
else if ( rc && opt.merge_only ) {
if( opt.verbose )
log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
rc = 0;
fast = 1; /* so that we don't get into the trustdb update */
- stats.skipped_new_keys++;
+ stats->skipped_new_keys++;
}
else if( rc ) { /* insert this key */
-#if 0 /* we don't know wehre we are going to write */
+ KEYDB_HANDLE hd = keydb_new (0);
+
+ rc = keydb_locate_writable (hd, NULL);
+ if (rc) {
+ log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
+ keydb_release (hd);
+ return G10ERR_GENERAL;
+ }
if( opt.verbose > 1 )
- log_info( _("writing to `%s'\n"),
- keyblock_resource_name(kbpos) );
-#endif
- if( (rc=insert_keyblock( keyblock )) )
- log_error( _("error writing key: %s\n"), gpg_errstr(rc) );
- /* we are ready */
- if( !opt.quiet )
- log_info( _("key %08lX: public key imported\n"), (ulong)keyid[1]);
+ log_info (_("writing to `%s'\n"), keydb_get_resource_name (hd) );
+ clean_subkeys(keyblock,keyid);
+ rc = keydb_insert_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc));
+ else
+ revalidation_mark ();
+ keydb_release (hd);
+
+ /* we are ready */
+ if( !opt.quiet ) {
+ char *p=get_user_id_native(keyid);
+ log_info( _("key %08lX: public key \"%s\" imported\n"),
+ (ulong)keyid[1],p);
+ m_free(p);
+ }
if( is_status_enabled() ) {
char *us = get_long_user_id_string( keyid );
write_status_text( STATUS_IMPORTED, us );
- gcry_free(us);
+ m_free(us);
}
- stats.imported++;
+ stats->imported++;
if( is_RSA( pk->pubkey_algo ) )
- stats.imported_rsa++;
+ stats->imported_rsa++;
new_key = 1;
}
else { /* merge */
+ KEYDB_HANDLE hd;
int n_uids, n_sigs, n_subk;
/* Compare the original against the new key; just to be sure nothing
@@ -452,15 +616,31 @@ import_one( const char *fname, KBNODE keyblock, int fast )
if( cmp_public_keys( pk_orig, pk ) ) {
log_error( _("key %08lX: doesn't match our copy\n"),
(ulong)keyid[1]);
- rc = GPGERR_GENERAL;
goto leave;
}
/* now read the original keyblock */
- rc = find_keyblock_bypk( &keyblock_orig, pk_orig );
+ hd = keydb_new (0);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk_orig, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (hd, afp);
+ }
if( rc ) {
- log_error( _("key %08lX: can't locate original keyblock: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
+ log_error (_("key %08lX: can't locate original keyblock: %s\n"),
+ (ulong)keyid[1], g10_errstr(rc));
+ keydb_release (hd);
+ goto leave;
+ }
+ rc = keydb_get_keyblock (hd, &keyblock_orig );
+ if (rc) {
+ log_error (_("key %08lX: can't read original keyblock: %s\n"),
+ (ulong)keyid[1], g10_errstr(rc));
+ keydb_release (hd);
goto leave;
}
@@ -471,73 +651,80 @@ import_one( const char *fname, KBNODE keyblock, int fast )
n_uids = n_sigs = n_subk = 0;
rc = merge_blocks( fname, keyblock_orig, keyblock,
keyid, &n_uids, &n_sigs, &n_subk );
- if( rc )
+ if( rc ) {
+ keydb_release (hd);
goto leave;
+ }
if( n_uids || n_sigs || n_subk ) {
mod_key = 1;
/* keyblock_orig has been updated; write */
- if( (rc=update_keyblock( keyblock_orig )) )
- log_error( _("error writing key: %s\n"), gpg_errstr(rc) );
+ n_sigs-=clean_subkeys(keyblock_orig,keyid);
+ rc = keydb_update_keyblock (hd, keyblock_orig);
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ else
+ revalidation_mark ();
+
/* we are ready */
if( !opt.quiet ) {
+ char *p=get_user_id_native(keyid);
if( n_uids == 1 )
- log_info( _("key %08lX: 1 new user ID\n"),
- (ulong)keyid[1]);
+ log_info( _("key %08lX: \"%s\" 1 new user ID\n"),
+ (ulong)keyid[1], p);
else if( n_uids )
- log_info( _("key %08lX: %d new user IDs\n"),
- (ulong)keyid[1], n_uids );
+ log_info( _("key %08lX: \"%s\" %d new user IDs\n"),
+ (ulong)keyid[1], p, n_uids );
if( n_sigs == 1 )
- log_info( _("key %08lX: 1 new signature\n"),
- (ulong)keyid[1]);
+ log_info( _("key %08lX: \"%s\" 1 new signature\n"),
+ (ulong)keyid[1], p);
else if( n_sigs )
- log_info( _("key %08lX: %d new signatures\n"),
- (ulong)keyid[1], n_sigs );
+ log_info( _("key %08lX: \"%s\" %d new signatures\n"),
+ (ulong)keyid[1], p, n_sigs );
if( n_subk == 1 )
- log_info( _("key %08lX: 1 new subkey\n"),
- (ulong)keyid[1]);
+ log_info( _("key %08lX: \"%s\" 1 new subkey\n"),
+ (ulong)keyid[1], p);
else if( n_subk )
- log_info( _("key %08lX: %d new subkeys\n"),
- (ulong)keyid[1], n_subk );
+ log_info( _("key %08lX: \"%s\" %d new subkeys\n"),
+ (ulong)keyid[1], p, n_subk );
+ m_free(p);
}
- stats.n_uids +=n_uids;
- stats.n_sigs +=n_sigs;
- stats.n_subk +=n_subk;
+ stats->n_uids +=n_uids;
+ stats->n_sigs +=n_sigs;
+ stats->n_subk +=n_subk;
}
else {
- if( !opt.quiet )
- log_info( _("key %08lX: not changed\n"), (ulong)keyid[1] );
- stats.unchanged++;
- }
- }
- if( !rc && !fast ) {
- rc = query_trust_record( new_key? pk : pk_orig );
- if( rc && rc != -1 )
- log_error("trustdb error: %s\n", gpg_errstr(rc) );
- else if( rc == -1 ) { /* not found trustdb */
- rc = insert_trust_record( new_key? keyblock : keyblock_orig );
- if( rc )
- log_error("key %08lX: trustdb insert failed: %s\n",
- (ulong)keyid[1], gpg_errstr(rc) );
+ if( !opt.quiet ) {
+ char *p=get_user_id_native(keyid);
+ log_info( _("key %08lX: \"%s\" not changed\n"),
+ (ulong)keyid[1],p);
+ m_free(p);
+ }
+ stats->unchanged++;
}
- else if( mod_key )
- rc = update_trust_record( keyblock_orig, 1, NULL );
- else
- rc = clear_trust_checked_flag( new_key? pk : pk_orig );
+ keydb_release (hd); hd = NULL;
}
leave:
release_kbnode( keyblock_orig );
free_public_key( pk_orig );
+
+ revocation_present(keyblock);
+
return rc;
}
/****************
* Ditto for secret keys. Handling is simpler than for public keys.
+ * We allow secret key importing only when allow is true, this is so
+ * that a secret key can not be imported accidently and thereby tampering
+ * with the trust calculation.
*/
static int
-import_secret_one( const char *fname, KBNODE keyblock )
+import_secret_one( const char *fname, KBNODE keyblock,
+ struct stats_s *stats)
{
PKT_secret_key *sk;
KBNODE node, uidnode;
@@ -563,7 +750,8 @@ import_secret_one( const char *fname, KBNODE keyblock )
uidnode->pkt->pkt.user_id->len );
putc('\n', stderr);
}
- stats.secret_read++;
+ stats->secret_read++;
+
if( !uidnode ) {
log_error( _("key %08lX: no user ID\n"), (ulong)keyid[1]);
return 0;
@@ -573,22 +761,34 @@ import_secret_one( const char *fname, KBNODE keyblock )
/* do we have this key already in one of our secrings ? */
rc = seckey_available( keyid );
- if( rc == GPGERR_NO_SECKEY && !opt.merge_only ) { /*just insert this key*/
- if( (rc=insert_keyblock( keyblock )) )
- log_error( _("error writing key: %s\n"), gpg_errstr(rc) );
+ if( rc == G10ERR_NO_SECKEY && !opt.merge_only ) { /* simply insert this key */
+ KEYDB_HANDLE hd = keydb_new (1);
+
+ /* get default resource */
+ rc = keydb_locate_writable (hd, NULL);
+ if (rc) {
+ log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+ keydb_release (hd);
+ return G10ERR_GENERAL;
+ }
+ rc = keydb_insert_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ keydb_release (hd);
/* we are ready */
if( !opt.quiet )
log_info( _("key %08lX: secret key imported\n"), (ulong)keyid[1]);
- stats.secret_imported++;
+ stats->secret_imported++;
}
else if( !rc ) { /* we can't merge secret keys */
log_error( _("key %08lX: already in secret keyring\n"),
(ulong)keyid[1]);
- stats.secret_dups++;
+ stats->secret_dups++;
}
else
log_error( _("key %08lX: secret key not found: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
+ (ulong)keyid[1], g10_errstr(rc));
return rc;
}
@@ -598,10 +798,11 @@ import_secret_one( const char *fname, KBNODE keyblock )
* Import a revocation certificate; this is a single signature packet.
*/
static int
-import_revoke_cert( const char *fname, KBNODE node )
+import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
{
PKT_public_key *pk=NULL;
KBNODE onode, keyblock = NULL;
+ KEYDB_HANDLE hd = NULL;
u32 keyid[2];
int rc = 0;
@@ -612,9 +813,9 @@ import_revoke_cert( const char *fname, KBNODE node )
keyid[0] = node->pkt->pkt.signature->keyid[0];
keyid[1] = node->pkt->pkt.signature->keyid[1];
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
rc = get_pubkey( pk, keyid );
- if( rc == GPGERR_NO_PUBKEY ) {
+ if( rc == G10ERR_NO_PUBKEY ) {
log_info( _("key %08lX: no public key - "
"can't apply revocation certificate\n"), (ulong)keyid[1]);
rc = 0;
@@ -622,15 +823,30 @@ import_revoke_cert( const char *fname, KBNODE node )
}
else if( rc ) {
log_error( _("key %08lX: public key not found: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
+ (ulong)keyid[1], g10_errstr(rc));
goto leave;
}
/* read the original keyblock */
- rc = find_keyblock_bypk( &keyblock, pk );
- if( rc ) {
- log_error( _("key %08lX: can't locate original keyblock: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
+ hd = keydb_new (0);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (hd, afp);
+ }
+ if (rc) {
+ log_error (_("key %08lX: can't locate original keyblock: %s\n"),
+ (ulong)keyid[1], g10_errstr(rc));
+ goto leave;
+ }
+ rc = keydb_get_keyblock (hd, &keyblock );
+ if (rc) {
+ log_error (_("key %08lX: can't read original keyblock: %s\n"),
+ (ulong)keyid[1], g10_errstr(rc));
goto leave;
}
@@ -641,7 +857,8 @@ import_revoke_cert( const char *fname, KBNODE node )
rc = check_key_signature( keyblock, node, NULL);
if( rc ) {
log_error( _("key %08lX: invalid revocation certificate"
- ": %s - rejected\n"), (ulong)keyid[1], gpg_errstr(rc));
+ ": %s - rejected\n"), (ulong)keyid[1], g10_errstr(rc));
+ goto leave;
}
@@ -663,24 +880,23 @@ import_revoke_cert( const char *fname, KBNODE node )
insert_kbnode( keyblock, clone_kbnode(node), 0 );
/* and write the keyblock back */
- if( (rc=update_keyblock( keyblock )) )
- log_error( _("error writing key: %s\n"), gpg_errstr(rc) );
+ rc = keydb_update_keyblock (hd, keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ keydb_release (hd); hd = NULL;
/* we are ready */
- if( !opt.quiet )
- log_info( _("key %08lX: revocation certificate imported\n"),
- (ulong)keyid[1]);
- stats.n_revoc++;
- if( clear_trust_checked_flag( pk ) ) {
- /* seems that we have to insert the record first */
- rc = insert_trust_record( keyblock );
- if( rc )
- log_error("key %08lX: trustdb insert failed: %s\n",
- (ulong)keyid[1], gpg_errstr(rc) );
- else
- rc = clear_trust_checked_flag( pk );
+ if( !opt.quiet ) {
+ char *p=get_user_id_native(keyid);
+ log_info( _("key %08lX: \"%s\" revocation certificate imported\n"),
+ (ulong)keyid[1],p);
+ m_free(p);
}
+ stats->n_revoc++;
+ revalidation_mark ();
leave:
+ keydb_release (hd);
release_kbnode( keyblock );
free_public_key( pk );
return rc;
@@ -713,16 +929,25 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
(ulong)keyid[1]);
return -1; /* the complete keyblock is invalid */
}
- rc = check_key_signature( keyblock, n, NULL);
- if( rc ) {
- log_info( rc == GPGERR_PUBKEY_ALGO ?
- _("key %08lX: unsupported public key algorithm\n"):
- _("key %08lX: invalid self-signature\n"),
- (ulong)keyid[1]);
- unode->flag |= 2; /* mark as invalid */
+ /* If it hasn't been marked valid yet, keep trying */
+ if(!(unode->flag&1)) {
+ rc = check_key_signature( keyblock, n, NULL);
+ if( rc )
+ {
+ char *p=utf8_to_native(unode->pkt->pkt.user_id->name,
+ strlen(unode->pkt->pkt.user_id->name),0);
+ log_info( rc == G10ERR_PUBKEY_ALGO ?
+ _("key %08lX: unsupported public key "
+ "algorithm on user id \"%s\"\n"):
+ _("key %08lX: invalid self-signature "
+ "on user id \"%s\"\n"),
+ (ulong)keyid[1],p);
+ m_free(p);
+ }
+ else
+ unode->flag |= 1; /* mark that signature checked */
}
- unode->flag |= 1; /* mark that signature checked */
}
else if( sig->sig_class == 0x18 ) {
KBNODE knode = find_prev_kbnode( keyblock,
@@ -737,16 +962,17 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
n->flag |= 4; /* delete this */
}
else {
+ /* If it hasn't been marked valid yet, keep trying */
+ if(!(knode->flag&1)) {
rc = check_key_signature( keyblock, n, NULL);
- if( rc ) {
- log_info( rc == GPGERR_PUBKEY_ALGO ?
+ if( rc )
+ log_info( rc == G10ERR_PUBKEY_ALGO ?
_("key %08lX: unsupported public key algorithm\n"):
_("key %08lX: invalid subkey binding\n"),
(ulong)keyid[1]);
-
- knode->flag |= 2; /* mark as invalid */
- }
- knode->flag |= 1; /* mark that signature checked */
+ else
+ knode->flag |= 1; /* mark that signature checked */
+ }
}
}
}
@@ -754,30 +980,6 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
return 0;
}
-
-
-/****************
- * If a user ID has at least one signature, mark it as valid
- */
-static void
-mark_non_selfsigned_uids_valid( KBNODE keyblock, u32 *kid )
-{
- KBNODE node;
- for(node=keyblock->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) ) {
- if( (node->next && node->next->pkt->pkttype == PKT_SIGNATURE)
- || !node->next ) {
- node->flag |= 1;
- log_info( _("key %08lX: accepted non self-signed user ID '"),
- (ulong)kid[1]);
- print_string( log_stream(), node->pkt->pkt.user_id->name,
- node->pkt->pkt.user_id->len, 0 );
- fputs("'\n", log_stream() );
- }
- }
- }
-}
-
/****************
* delete all parts which are invalid and those signatures whose
* public key algorithm is not available in this implemenation;
@@ -790,7 +992,6 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
{
KBNODE node;
int nvalid=0, uid_seen=0;
- const char *p;
for(node=keyblock->next; node; node = node->next ) {
if( node->pkt->pkttype == PKT_USER_ID ) {
@@ -833,14 +1034,12 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
}
}
else if( node->pkt->pkttype == PKT_SIGNATURE
- && openpgp_pk_test_algo( node->pkt->pkt.signature->pubkey_algo, 0 )
- && node->pkt->pkt.signature->pubkey_algo != GCRY_PK_RSA )
+ && check_pubkey_algo( node->pkt->pkt.signature->pubkey_algo)
+ && node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA )
delete_kbnode( node ); /* build_packet() can't handle this */
- else if( node->pkt->pkttype == PKT_SIGNATURE
- && (p = parse_sig_subpkt2( node->pkt->pkt.signature,
- SIGSUBPKT_EXPORTABLE, NULL ))
- && !*p
- && seckey_available( node->pkt->pkt.signature->keyid ) ) {
+ else if( node->pkt->pkttype == PKT_SIGNATURE &&
+ !node->pkt->pkt.signature->flags.exportable &&
+ seckey_available( node->pkt->pkt.signature->keyid ) ) {
/* here we violate the rfc a bit by still allowing
* to import non-exportable signature when we have the
* the secret key used to create this signature - it
@@ -860,12 +1059,22 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
delete_kbnode( node );
}
else {
- int rc = check_key_signature( keyblock, node, NULL);
- if( rc ) {
- log_error( _("key %08lX: invalid revocation "
- "certificate: %s - skipped\n"),
- (ulong)keyid[1], gpg_errstr(rc));
- delete_kbnode( node );
+ /* If the revocation cert is from a different key than
+ the one we're working on don't check it - it's
+ probably from a revocation key and won't be
+ verifiable with this key anyway. */
+
+ if(node->pkt->pkt.signature->keyid[0]==keyid[0] &&
+ node->pkt->pkt.signature->keyid[1]==keyid[1])
+ {
+ int rc = check_key_signature( keyblock, node, NULL);
+ if( rc )
+ {
+ log_error( _("key %08lX: invalid revocation "
+ "certificate: %s - skipped\n"),
+ (ulong)keyid[1], g10_errstr(rc));
+ delete_kbnode( node );
+ }
}
}
}
@@ -968,7 +1177,84 @@ collapse_uids( KBNODE *keyblock )
return 1;
}
+/* Check for a 0x20 revocation from a revocation key that is not
+ present. This gets called without the benefit of merge_xxxx so you
+ can't rely on pk->revkey and friends. */
+static void
+revocation_present(KBNODE keyblock)
+{
+ KBNODE onode,inode;
+ PKT_public_key *pk=keyblock->pkt->pkt.public_key;
+
+ for(onode=keyblock->next;onode;onode=onode->next)
+ {
+ /* If we reach user IDs, we're done. */
+ if(onode->pkt->pkttype==PKT_USER_ID)
+ break;
+
+ if(onode->pkt->pkttype==PKT_SIGNATURE &&
+ onode->pkt->pkt.signature->sig_class==0x1F &&
+ onode->pkt->pkt.signature->revkey)
+ {
+ int idx;
+ PKT_signature *sig=onode->pkt->pkt.signature;
+
+ for(idx=0;idx<sig->numrevkeys;idx++)
+ {
+ u32 keyid[2];
+
+ keyid_from_fingerprint(sig->revkey[idx]->fpr,
+ MAX_FINGERPRINT_LEN,keyid);
+
+ for(inode=keyblock->next;inode;inode=inode->next)
+ {
+ /* If we reach user IDs, we're done. */
+ if(inode->pkt->pkttype==PKT_USER_ID)
+ break;
+ if(inode->pkt->pkttype==PKT_SIGNATURE &&
+ inode->pkt->pkt.signature->sig_class==0x20 &&
+ inode->pkt->pkt.signature->keyid[0]==keyid[0] &&
+ inode->pkt->pkt.signature->keyid[1]==keyid[1])
+ {
+ /* Okay, we have a revocation key, and a
+ revocation issued by it. Do we have the key
+ itself? */
+ int rc;
+
+ rc=get_pubkey_byfprint(NULL,sig->revkey[idx]->fpr,
+ MAX_FINGERPRINT_LEN);
+ if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
+ {
+ /* No, so try and get it */
+ if(opt.keyserver_scheme &&
+ opt.keyserver_options.auto_key_retrieve)
+ {
+ log_info(_("Warning: key %08lX may be revoked: "
+ "fetching revocation key %08lX\n"),
+ (ulong)keyid_from_pk(pk,NULL),
+ (ulong)keyid[1]);
+ keyserver_import_fprint(sig->revkey[idx]->fpr,
+ MAX_FINGERPRINT_LEN);
+
+ /* Do we have it now? */
+ rc=get_pubkey_byfprint(NULL,
+ sig->revkey[idx]->fpr,
+ MAX_FINGERPRINT_LEN);
+ }
+
+ if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
+ log_info(_("Warning: key %08lX may be revoked: "
+ "revocation key %08lX not present.\n"),
+ (ulong)keyid_from_pk(pk,NULL),
+ (ulong)keyid[1]);
+ }
+ }
+ }
+ }
+ }
+ }
+}
/****************
* compare and merge the blocks
@@ -1010,16 +1296,49 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
}
}
if( !found ) {
+ char *p=get_user_id_native(keyid);
KBNODE n2 = clone_kbnode(node);
insert_kbnode( keyblock_orig, n2, 0 );
n2->flag |= 1;
- log_info( _("key %08lX: revocation certificate added\n"),
+ ++*n_sigs;
+ log_info(_("key %08lX: \"%s\" revocation certificate added\n"),
+ (ulong)keyid[1],p);
+ m_free(p);
+ }
+ }
+ }
+
+ /* 2nd: merge in any direct key (0x1F) sigs */
+ for(node=keyblock->next; node; node=node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID )
+ break;
+ else if( node->pkt->pkttype == PKT_SIGNATURE
+ && node->pkt->pkt.signature->sig_class == 0x1F ) {
+ /* check whether we already have this */
+ found = 0;
+ for(onode=keyblock_orig->next; onode; onode=onode->next ) {
+ if( onode->pkt->pkttype == PKT_USER_ID )
+ break;
+ else if( onode->pkt->pkttype == PKT_SIGNATURE
+ && onode->pkt->pkt.signature->sig_class == 0x1F
+ && !cmp_signatures(onode->pkt->pkt.signature,
+ node->pkt->pkt.signature)) {
+ found = 1;
+ break;
+ }
+ }
+ if( !found ) {
+ KBNODE n2 = clone_kbnode(node);
+ insert_kbnode( keyblock_orig, n2, 0 );
+ n2->flag |= 1;
+ ++*n_sigs;
+ log_info( _("key %08lX: direct key signature added\n"),
(ulong)keyid[1]);
}
}
}
- /* 2nd: try to merge new certificates in */
+ /* 3rd: try to merge new certificates in */
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
if( !(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID) {
/* find the user id in the imported keyblock */
@@ -1036,7 +1355,7 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
}
}
- /* 3rd: add new user-ids */
+ /* 4th: add new user-ids */
for(node=keyblock->next; node; node=node->next ) {
if( node->pkt->pkttype == PKT_USER_ID) {
/* do we have this in the original keyblock */
@@ -1054,7 +1373,7 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
}
}
- /* add new subkeys */
+ /* 5th: add new subkeys */
for(node=keyblock->next; node; node=node->next ) {
onode = NULL;
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
@@ -1087,7 +1406,7 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
}
}
- /* merge subkey certificates */
+ /* 6th: merge subkey certificates */
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
if( !(onode->flag & 1)
&& ( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
@@ -1126,11 +1445,6 @@ append_uid( KBNODE keyblock, KBNODE node, int *n_sigs,
KBNODE n, n_where=NULL;
assert(node->pkt->pkttype == PKT_USER_ID );
- if( !node->next || node->next->pkt->pkttype == PKT_USER_ID ) {
- log_error( _("key %08lX: our copy has no self-signature\n"),
- (ulong)keyid[1]);
- return GPGERR_GENERAL;
- }
/* find the position */
for( n = keyblock; n; n_where = n, n = n->next ) {
@@ -1179,12 +1493,6 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
assert(dst->pkt->pkttype == PKT_USER_ID );
assert(src->pkt->pkttype == PKT_USER_ID );
- if( !dst->next || dst->next->pkt->pkttype == PKT_USER_ID ) {
- log_error( _("key %08lX: our copy has no self-signature\n"),
- (ulong)keyid[1]);
- return 0;
- }
-
for(n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next ) {
if( n->pkt->pkttype != PKT_SIGNATURE )
@@ -1304,4 +1612,3 @@ append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
return 0;
}
-
diff --git a/g10/kbnode.c b/g10/kbnode.c
index 2c1e2ad3c..06d28f844 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -1,5 +1,5 @@
/* kbnode.c - keyblock node utility functions
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,9 +23,8 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "packet.h"
#include "keydb.h"
@@ -42,7 +41,7 @@ alloc_node(void)
if( n )
unused_nodes = n->next;
else
- n = gcry_xmalloc( sizeof *n );
+ n = m_alloc( sizeof *n );
n->next = NULL;
n->pkt = NULL;
n->flag = 0;
@@ -59,7 +58,7 @@ free_node( KBNODE n )
n->next = unused_nodes;
unused_nodes = n;
#else
- gcry_free( n );
+ m_free( n );
#endif
}
}
@@ -95,7 +94,7 @@ release_kbnode( KBNODE n )
n2 = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
- gcry_free( n->pkt );
+ m_free( n->pkt );
}
free_node( n );
n = n2;
@@ -165,9 +164,10 @@ find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
{
KBNODE n1;
- for(n1=NULL ; root && root != node; root = root->next )
- if( !pkttype || root->pkt->pkttype == pkttype )
- n1 = root;
+ for (n1=NULL; root && root != node; root = root->next ) {
+ if (!pkttype ||root->pkt->pkttype == pkttype)
+ n1 = root;
+ }
return n1;
}
@@ -185,7 +185,7 @@ find_next_kbnode( KBNODE node, int pkttype )
for( node=node->next ; node; node = node->next ) {
if( !pkttype )
return node;
- else if( pkttype == PKT_USER_ID
+ else if( pkttype == PKT_USER_ID
&& ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
return NULL;
@@ -267,7 +267,7 @@ commit_kbnode( KBNODE *root )
nl->next = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
- gcry_free( n->pkt );
+ m_free( n->pkt );
}
free_node( n );
changed = 1;
@@ -291,7 +291,7 @@ remove_kbnode( KBNODE *root, KBNODE node )
nl->next = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
- gcry_free( n->pkt );
+ m_free( n->pkt );
}
free_node( n );
}
@@ -356,28 +356,44 @@ dump_kbnode( KBNODE node )
case PKT_PLAINTEXT: s="plaintext"; break;
case PKT_COMPRESSED: s="compressed"; break;
case PKT_ENCRYPTED: s="encrypted"; break;
+ case PKT_GPG_CONTROL: s="gpg-control"; break;
default: s="unknown"; break;
}
fprintf(stderr, "node %p %02x/%02x type=%s",
node, node->flag, node->private_flag, s);
if( node->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
fputs(" \"", stderr);
- print_string( stderr, node->pkt->pkt.user_id->name,
- node->pkt->pkt.user_id->len, 0 );
- fputs("\"\n", stderr);
+ print_string( stderr, uid->name, uid->len, 0 );
+ fprintf (stderr, "\" %c%c%c%c\n",
+ uid->is_expired? 'e':'.',
+ uid->is_revoked? 'r':'.',
+ uid->created? 'v':'.',
+ uid->is_primary? 'p':'.' );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
- fprintf(stderr, " class=%02x keyid=%08lX\n",
+ fprintf(stderr, " class=%02x keyid=%08lX ts=%lu\n",
node->pkt->pkt.signature->sig_class,
- (ulong)node->pkt->pkt.signature->keyid[1] );
+ (ulong)node->pkt->pkt.signature->keyid[1],
+ (ulong)node->pkt->pkt.signature->timestamp);
+ }
+ else if( node->pkt->pkttype == PKT_GPG_CONTROL ) {
+ fprintf(stderr, " ctrl=%d len=%u\n",
+ node->pkt->pkt.gpg_control->control,
+ (unsigned int)node->pkt->pkt.gpg_control->datalen);
}
else if( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- fprintf(stderr, " keyid=%08lX\n", (ulong)
- keyid_from_pk( node->pkt->pkt.public_key, NULL ));
+ PKT_public_key *pk = node->pkt->pkt.public_key;
+ fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
+ (ulong)keyid_from_pk( pk, NULL ),
+ pk->pubkey_algo, pk->pubkey_usage,
+ pk->has_expired? 'e':'.',
+ pk->is_revoked? 'r':'.',
+ pk->is_valid? 'v':'.',
+ pk->mdc_feature? 'm':'.');
}
else
fputs("\n", stderr);
}
}
-
diff --git a/g10/kbx.h b/g10/kbx.h
deleted file mode 100644
index 25825a4ec..000000000
--- a/g10/kbx.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* kbx.h - The GnuPG Keybox
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef GPG_KBX_H
-#define GPG_KBX_H 1
-
-#include "keydb.h"
-
-/*-- kbxblob.c */
-struct kbxblob;
-typedef struct kbxblob *KBXBLOB;
-
-int kbx_new_blob ( KBXBLOB *r_blob, char *image, size_t imagelen );
-int kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock );
-void kbx_release_blob ( KBXBLOB blob );
-const char *kbx_get_blob_image ( KBXBLOB blob, size_t *n );
-
-int kbx_dump_blob ( FILE *fp, KBXBLOB blob );
-int kbx_blob_has_fpr ( KBXBLOB blob, const byte *fpr );
-int kbx_blob_has_kid ( KBXBLOB blob, const byte *keyidbuf, size_t keyidlen );
-int kbx_blob_has_uid ( KBXBLOB blob,
- int (*cmp)(const byte *, size_t, void *), void *opaque );
-
-/*-- kbxio.c --*/
-int kbx_read_blob ( KBXBLOB *r_blob, FILE *a );
-
-/*-- kbxfile.c --*/
-int kbxfile_search_by_fpr( const char *filename, const byte *fpr );
-int kbxfile_search_by_kid ( const char *filename, u32 *kid, int mode );
-int kbxfile_search_by_uid ( const char *filename, const char *name );
-void print_kbxfile( const char *filename );
-
-
-#endif /*GPG_KBX_H*/
diff --git a/g10/kbxblob.c b/g10/kbxblob.c
deleted file mode 100644
index 01d0dfe10..000000000
--- a/g10/kbxblob.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/* kbxblob.c - KBX Blob handling
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-/* The keybox data formats
-
-The KeyBox uses an augmented OpenPGP key format. This makes random
-access to a keyblock easier and also gives the opportunity to store
-additional information (e.g. the fingerprint) along with the key.
-All integers are stored in network byte order, offsets are counted from
-the beginning of the Blob.
-
-The first record of a plain KBX file has a special format:
-
- u32 length of the first record
- byte Blob type (1)
- byte version number (1)
- byte reserved
- byte reserved
- u32 magic 'KBXf'
- byte marginals used for validity calculation of this file
- byte completes ditto.
- byte cert_depth ditto.
-
-The standard KBX Blob looks like this:
-
- u32 length of this blob (including these 4 bytes)
- byte Blob type (2)
- byte version number of this blob type (1)
- u16 Blob flags
- bit 0 = contains secret key material
-
- u32 offset to the OpenPGP keyblock
- u32 length of the keyblock
- u16 number of keys (at least 1!)
- u16 size of additional key information
- n times:
- b20 The keys fingerprint
- (fingerprints are always 20 bytes, MD5 left padded with zeroes)
- u32 offset to the n-th key's keyID (a keyID is always 8 byte)
- u16 special key flags
- bit 0 =
- u16 reserved
- u16 number of user IDs
- u16 size of additional user ID information
- n times:
- u32 offset to the n-th user ID
- u32 length of this user ID.
- u16 special user ID flags.
- bit 0 =
- byte validity
- byte reserved
- u16 number of signatures
- u16 size of signature information (4)
- u32 expiration time of signature with some special values:
- 0x00000000 = not checked
- 0x00000001 = missing key
- 0x00000002 = bad signature
- 0x10000000 = valid and expires at some date in 1978.
- 0xffffffff = valid and does not expire
- u8 assigned ownertrust
- u8 all_validity
- u16 reserved
- u32 recheck_after
- u32 Newest timestamp in the keyblock (useful for KS syncronsiation?)
- u32 Blob created at
- u32 size of reserved space (not including this field)
- reserved space
-
- Here we might want to put other data
-
- Here comes the keyblock
-
- maybe we put a signature here later.
-
- b16 MD5 checksum (useful for KS syncronisation)
- *
- */
-
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <gcrypt.h>
-
-#include "iobuf.h"
-#include "util.h"
-#include "kbx.h"
-
-/* special values of the signature status */
-#define SF_NONE(a) ( !(a) )
-#define SF_NOKEY(a) ((a) & (1<<0))
-#define SF_BAD(a) ((a) & (1<<1))
-#define SF_VALID(a) ((a) & (1<<29))
-
-#if MAX_FINGERPRINT_LEN < 20
- #error fingerprints are 20 bytes
-#endif
-
-struct kbxblob_key {
- char fpr[20];
- u32 off_kid;
- ulong off_kid_addr;
- u16 flags;
-};
-struct kbxblob_uid {
- ulong off_addr;
- u32 len;
- u16 flags;
- byte validity;
-};
-
-struct keyid_list {
- struct keyid_list *next;
- int seqno;
- byte kid[8];
-};
-
-struct fixup_list {
- struct fixup_list *next;
- u32 off;
- u32 val;
-};
-
-
-struct kbxblob {
- byte *blob;
- size_t bloblen;
-
- /* stuff used only by kbx_create_blob */
- int nkeys;
- struct kbxblob_key *keys;
- int nuids;
- struct kbxblob_uid *uids;
- int nsigs;
- u32 *sigs;
- struct fixup_list *fixups;
-
- struct keyid_list *temp_kids;
- IOBUF buf; /* the KBX is temporarly stored here */
-};
-
-void kbx_release_blob ( KBXBLOB blob );
-
-/* Note: this functions are only used for temportay iobufs and therefore
- * they can't fail */
-static void
-put8 ( IOBUF out, byte a )
-{
- iobuf_put ( out, a );
-}
-
-static void
-put16 ( IOBUF out, u16 a )
-{
- iobuf_put ( out, a>>8 );
- iobuf_put ( out, a );
-}
-
-static void
-put32 ( IOBUF out, u32 a )
-{
- iobuf_put (out, a>> 24);
- iobuf_put (out, a>> 16);
- iobuf_put (out, a>> 8);
- iobuf_put (out, a );
-}
-
-static void
-putn ( IOBUF out, const byte *p, size_t n )
-{
- for ( ; n; p++, n-- ) {
- iobuf_put ( out, *p );
- }
-}
-
-
-/****************
- * We must store the keyid at some place because we can't calculate the
- * offset yet. This is only used for v3 keyIDs. Function returns an index
- * value for later fixupd; this must be a non-zero value
- */
-static int
-temp_store_kid ( KBXBLOB blob, PKT_public_key *pk )
-{
- struct keyid_list *k, *r;
-
- k = gcry_xmalloc ( sizeof *k );
- k->kid[0] = pk->keyid[0] >> 24 ;
- k->kid[1] = pk->keyid[0] >> 16 ;
- k->kid[2] = pk->keyid[0] >> 8 ;
- k->kid[3] = pk->keyid[0] ;
- k->kid[4] = pk->keyid[0] >> 24 ;
- k->kid[5] = pk->keyid[0] >> 16 ;
- k->kid[6] = pk->keyid[0] >> 8 ;
- k->kid[7] = pk->keyid[0] ;
- k->seqno = 0;
- k->next = blob->temp_kids;
- blob->temp_kids = k;
- for ( r=k; r; r = r->next ) {
- k->seqno++;
- }
-
- return k->seqno;
-}
-
-static void
-put_stored_kid( KBXBLOB blob, int seqno )
-{
- struct keyid_list *r;
-
- for ( r = blob->temp_kids; r; r = r->next ) {
- if( r->seqno == seqno ) {
- putn ( blob->buf, r->kid, 8 );
- return;
- }
- }
- BUG();
-}
-
-static void
-release_kid_list ( struct keyid_list *kl )
-{
- struct keyid_list *r, *r2;
-
- for ( r = kl; r; r = r2 ) {
- r2 = r->next;
- gcry_free( r );
- }
-}
-
-
-static int
-create_key_part( KBXBLOB blob, KBNODE keyblock )
-{
- KBNODE node;
- size_t fprlen;
- int n;
-
- for ( n=0, node = keyblock; node; node = node->next ) {
- if ( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- PKT_public_key *pk = node->pkt->pkt.public_key;
- char tmp[20];
-
- fingerprint_from_pk( pk, tmp , &fprlen );
- memcpy(blob->keys[n].fpr,tmp,20);
- if ( fprlen != 20 ) { /*v3 fpr - shift right and fill with zeroes*/
- assert( fprlen == 16 );
- memmove( blob->keys[n].fpr+4, blob->keys[n].fpr, 16);
- memset( blob->keys[n].fpr, 0, 4 );
- blob->keys[n].off_kid = temp_store_kid( blob, pk );
- }
- else {
- blob->keys[n].off_kid = 0; /* will be fixed up later */
- }
- blob->keys[n].flags = 0;
- n++;
- }
- else if ( node->pkt->pkttype == PKT_SECRET_KEY
- || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
- BUG(); /* not yet implemented */
- }
- }
- assert( n == blob->nkeys );
- return 0;
-}
-
-static int
-create_uid_part( KBXBLOB blob, KBNODE keyblock )
-{
- KBNODE node;
- int n;
-
- for ( n=0, node = keyblock; node; node = node->next ) {
- if ( node->pkt->pkttype == PKT_USER_ID ) {
- PKT_user_id *u = node->pkt->pkt.user_id;
-
- blob->uids[n].len = u->len;
- blob->uids[n].flags = 0;
- blob->uids[n].validity = 0;
- n++;
- }
- }
- assert( n == blob->nuids );
- return 0;
-}
-
-static int
-create_sig_part( KBXBLOB blob, KBNODE keyblock )
-{
- KBNODE node;
- int n;
-
- for ( n=0, node = keyblock; node; node = node->next ) {
- if ( node->pkt->pkttype == PKT_SIGNATURE ) {
- PKT_signature *sig = node->pkt->pkt.signature;
-
- blob->sigs[n] = 0; /* FIXME: check the signature here */
- n++;
- }
- }
- assert( n == blob->nsigs );
- return 0;
-}
-
-
-static int
-create_blob_header( KBXBLOB blob )
-{
- IOBUF a = blob->buf;
- int i;
-
- put32 ( a, 0 ); /* blob length, needs fixup */
- put8 ( a, 2 ); /* blob type */
- put8 ( a, 1 ); /* blob type version */
- put16 ( a, 0 ); /* blob flags */
-
- put32 ( a, 0 ); /* offset to the keyblock, needs fixup */
- put32 ( a, 0 ); /* length of the keyblock, needs fixup */
-
- put16 ( a, blob->nkeys );
- put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */
- for ( i=0; i < blob->nkeys; i++ ) {
- putn ( a, blob->keys[i].fpr, 20 );
- blob->keys[i].off_kid_addr = iobuf_get_temp_length (a);
- put32 ( a, 0 ); /* offset to keyid, fixed up later */
- put16 ( a, blob->keys[i].flags );
- put16 ( a, 0 ); /* reserved */
- }
-
- put16 ( a, blob->nuids );
- put16 ( a, 4 + 4 + 2 + 1 + 1 ); /* size of uid info */
- for ( i=0; i < blob->nuids; i++ ) {
- blob->uids[i].off_addr = iobuf_get_temp_length ( a );
- put32 ( a, 0 ); /* offset to userid, fixed up later */
- put32 ( a, blob->uids[i].len );
- put16 ( a, blob->uids[i].flags );
- put8 ( a, 0 ); /* validity */
- put8 ( a, 0 ); /* reserved */
- }
-
- put16 ( a, blob->nsigs );
- put16 ( a, 4 ); /* size of sig info */
- for ( i=0; i < blob->nsigs; i++ ) {
- put32 ( a, blob->sigs[i] );
- }
-
- put8 ( a, 0 ); /* assigned ownertrust */
- put8 ( a, 0 ); /* validity of all user IDs */
- put16 ( a, 0 ); /* reserved */
- put32 ( a, 0 ); /* time of next recheck */
- put32 ( a, 0 ); /* newest timestamp (none) */
- put32 ( a, make_timestamp() ); /* creation time */
- put32 ( a, 0 ); /* size of reserved space */
- /* reserved space (which is currently of size 0) */
-
- /* We need to store the keyids for all v3 keys because those key IDs are
- * not part of the fingerprint. While we are doing that, we fixup all
- * the keyID offsets */
- for ( i=0; i < blob->nkeys; i++ ) {
- struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
- fl->off = blob->keys[i].off_kid_addr;
- fl->next = blob->fixups;
- blob->fixups = fl;
-
- if ( blob->keys[i].off_kid ) { /* this is a v3 one */
- fl->val = iobuf_get_temp_length (a);
- put_stored_kid ( blob, blob->keys[i].off_kid );
- }
- else { /* the better v4 key IDs - just store an offset 8 bytes back */
- fl->val = blob->keys[i].off_kid_addr-8;
- }
- }
-
-
- return 0;
-}
-
-static int
-create_blob_keyblock( KBXBLOB blob, KBNODE keyblock )
-{
- IOBUF a = blob->buf;
- KBNODE node;
- int rc;
- int n;
- u32 kbstart = iobuf_get_temp_length ( a );
-
- {
- struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
- fl->off = 8;
- fl->val = kbstart;
- fl->next = blob->fixups;
- blob->fixups = fl;
- }
- for ( n = 0, node = keyblock; node; node = node->next ) {
- rc = build_packet ( a, node->pkt );
- if ( rc ) {
- gpg_log_error("build_packet(%d) for kbxblob failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- return GPGERR_WRITE_FILE;
- }
- if ( node->pkt->pkttype == PKT_USER_ID ) {
- PKT_user_id *u = node->pkt->pkt.user_id;
- /* build_packet has set the offset of the name into u ;
- * now we can do the fixup */
- struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
- fl->off = blob->uids[n].off_addr;
- fl->val = u->stored_at;
- fl->next = blob->fixups;
- blob->fixups = fl;
- n++;
- }
- }
- assert( n == blob->nuids );
- {
- struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
- fl->off = 12;
- fl->val = iobuf_get_temp_length (a) - kbstart;
- fl->next = blob->fixups;
- blob->fixups = fl;
- }
- return 0;
-}
-
-static int
-create_blob_trailer( KBXBLOB blob )
-{
- IOBUF a = blob->buf;
- return 0;
-}
-
-static int
-create_blob_finish( KBXBLOB blob )
-{
- IOBUF a = blob->buf;
- byte *p;
- char *pp;
- int i;
- size_t n;
-
- /* write a placeholder for the checksum */
- for ( i = 0; i < 16; i++ )
- put32( a, 0 );
- /* get the memory area */
- iobuf_flush_temp ( a );
- p = iobuf_get_temp_buffer ( a );
- n = iobuf_get_temp_length ( a );
- assert( n >= 20 );
-
- /* fixup the length */
- {
- struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl );
- fl->off = 0;
- fl->val = n;
- fl->next = blob->fixups;
- blob->fixups = fl;
- }
- /* do the fixups */
- {
- struct fixup_list *fl;
- for ( fl = blob->fixups; fl; fl = fl->next ) {
- assert( fl->off+4 <= n );
- p[fl->off+0] = fl->val >> 24 ;
- p[fl->off+1] = fl->val >> 16 ;
- p[fl->off+2] = fl->val >> 8 ;
- p[fl->off+3] = fl->val ;
- }
-
- }
-
- /* calculate and store the MD5 checksum */
- gcry_md_hash_buffer( GCRY_MD_MD5, p + n - 16, p, n - 16 );
-
- pp = gcry_malloc ( n );
- if ( !pp )
- return GCRYERR_NO_MEM;
- memcpy ( pp , p, n );
- blob->blob = pp;
- blob->bloblen = n;
-
- return 0;
-}
-
-
-int
-kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock )
-{
- int rc = 0;
- KBNODE node;
- KBXBLOB blob;
-
- *r_blob = NULL;
- blob = gcry_xcalloc (1, sizeof *blob );
- if( !blob )
- return GCRYERR_NO_MEM;
-
- /* fixme: Do some sanity checks on the keyblock */
-
- /* count userids and keys so that we can allocate the arrays */
- for ( node = keyblock; node; node = node->next ) {
- switch ( node->pkt->pkttype ) {
- case PKT_PUBLIC_KEY:
- case PKT_SECRET_KEY:
- case PKT_PUBLIC_SUBKEY:
- case PKT_SECRET_SUBKEY: blob->nkeys++; break;
- case PKT_USER_ID: blob->nuids++; break;
- case PKT_SIGNATURE: blob->nsigs++; break;
- default: break;
- }
- }
- blob->keys = gcry_xcalloc ( blob->nkeys, sizeof ( *blob->keys ) );
- blob->uids = gcry_xcalloc ( blob->nuids, sizeof ( *blob->uids ) );
- blob->sigs = gcry_xcalloc ( blob->nsigs, sizeof ( *blob->sigs ) );
- if ( !blob->keys || !blob->uids || !blob->sigs ) {
- rc = GCRYERR_NO_MEM;
- goto leave;
- }
-
- rc = create_key_part ( blob, keyblock );
- if( rc )
- goto leave;
- rc = create_uid_part ( blob, keyblock );
- if( rc )
- goto leave;
- rc = create_sig_part ( blob, keyblock );
- if( rc )
- goto leave;
-
- blob->buf = iobuf_temp();
- rc = create_blob_header ( blob );
- if( rc )
- goto leave;
- rc = create_blob_keyblock ( blob, keyblock );
- if( rc )
- goto leave;
- rc = create_blob_trailer ( blob );
- if( rc )
- goto leave;
- rc = create_blob_finish ( blob );
- if( rc )
- goto leave;
-
-
- leave:
- release_kid_list( blob->temp_kids );
- blob->temp_kids = NULL;
- if ( rc ) {
- kbx_release_blob ( blob );
- *r_blob = NULL;
- }
- else {
- *r_blob = blob;
- }
- return rc;
-}
-
-int
-kbx_new_blob ( KBXBLOB *r_blob, char *image, size_t imagelen )
-{
- KBXBLOB blob;
-
- *r_blob = NULL;
- blob = gcry_xcalloc (1, sizeof *blob );
- if( !blob )
- return GCRYERR_NO_MEM;
- blob->blob = image;
- blob->bloblen = imagelen;
- *r_blob = blob;
- return 0;
-}
-
-
-
-const char *
-kbx_get_blob_image ( KBXBLOB blob, size_t *n )
-{
- *n = blob->bloblen;
- return blob->blob;
-}
-
-void
-kbx_release_blob ( KBXBLOB blob )
-{
- if( !blob )
- return;
- if( blob->buf )
- iobuf_cancel( blob->buf );
- gcry_free( blob->keys );
- gcry_free( blob->uids );
- gcry_free( blob->sigs );
-
- gcry_free ( blob->blob );
-
- gcry_free( blob );
-}
-
-static ulong
-get32( const byte *buffer )
-{
- ulong a;
- a = *buffer << 24;
- a |= buffer[1] << 16;
- a |= buffer[2] << 8;
- a |= buffer[3];
- return a;
-}
-
-static ulong
-get16( const byte *buffer )
-{
- ulong a;
- a = *buffer << 8;
- a |= buffer[1];
- return a;
-}
-
-
-int
-kbx_dump_blob ( FILE *fp, KBXBLOB blob )
-{
- const byte *buffer = blob->blob;
- size_t length = blob->bloblen;
- ulong n, nkeys, keyinfolen;
- ulong nuids, uidinfolen;
- ulong nsigs, siginfolen;
- ulong keyblock_off, keyblock_len;
- const byte *p;
-
- if( length < 40 ) {
- fprintf( fp, "blob too short\n");
- return -1;
- }
- n = get32( buffer );
- if( n > length ) {
- fprintf( fp, "blob larger than length - output truncated\n");
- }
- else
- length = n; /* ignore the rest */
- fprintf( fp, "Length: %lu\n", n );
- fprintf( fp, "Type: %d\n", buffer[4] );
- fprintf( fp, "Version: %d\n", buffer[5] );
- if( buffer[4] != 2 ) {
- fprintf( fp, "can't dump this blob type\n" );
- return 0;
- }
-
- n = get16( buffer + 6 );
- fprintf( fp, "Blob-Flags: %04lX\n", n );
- keyblock_off = get32( buffer + 8 );
- keyblock_len = get32( buffer + 12 );
- fprintf( fp, "Keyblock-Offset: %lu\n", keyblock_off );
- fprintf( fp, "Keyblock-Length: %lu\n", keyblock_len );
-
- nkeys = get16( buffer + 16 );
- fprintf( fp, "Key-Count: %lu\n", nkeys );
- keyinfolen = get16( buffer + 18 );
- fprintf( fp, "Key-Info-Length: %lu\n", keyinfolen );
- /* fixme: check bounds */
- p = buffer + 20;
- for(n=0; n < nkeys; n++, p += keyinfolen ) {
- int i;
- ulong kidoff, kflags;
-
- fprintf( fp, "Key-%lu-Fpr: ", n );
- for(i=0; i < 20; i++ )
- fprintf( fp, "%02X", p[i] );
- kidoff = get32( p + 20 );
- fprintf( fp, "\nKey-%lu-Kid-Off: %lu\n", n, kidoff );
- fprintf( fp, "Key-%lu-Kid: ", n );
- /* fixme: check bounds */
- for(i=0; i < 8; i++ )
- fprintf( fp, "%02X", buffer[kidoff+i] );
- kflags = get16( p + 24 );
- fprintf( fp, "\nKey-%lu-Flags: %04lX\n", n, kflags );
- }
-
-
- nuids = get16( p );
- fprintf( fp, "Uid-Count: %lu\n", nuids );
- uidinfolen = get16( p + 2 );
- fprintf( fp, "Uid-Info-Length: %lu\n", uidinfolen );
- /* fixme: check bounds */
- p += 4;
- for(n=0; n < nuids; n++, p += uidinfolen ) {
- ulong uidoff, uidlen, uflags;
-
- uidoff = get32( p );
- uidlen = get32( p+4 );
- fprintf( fp, "Uid-%lu-Off: %lu\n", n, uidoff );
- fprintf( fp, "Uid-%lu-Len: %lu\n", n, uidlen );
- fprintf( fp, "Uid-%lu: \"", n );
- print_string( fp, buffer+uidoff, uidlen, '\"' );
- fputs("\"\n", fp );
- uflags = get16( p + 8 );
- fprintf( fp, "Uid-%lu-Flags: %04lX\n", n, uflags );
- fprintf( fp, "Uid-%lu-Validity: %d\n", n, p[10] );
- }
-
- nsigs = get16( p );
- fprintf( fp, "Sig-Count: %lu\n", nsigs );
- siginfolen = get16( p + 2 );
- fprintf( fp, "Sig-Info-Length: %lu\n", siginfolen );
- /* fixme: check bounds */
- p += 4;
- for(n=0; n < nsigs; n++, p += siginfolen ) {
- ulong sflags;
-
- sflags = get32( p );
- fprintf( fp, "Sig-%lu-Expire: ", n );
- if( !sflags )
- fputs( "[not checked]", fp );
- else if( sflags == 1 )
- fputs( "[missing key]", fp );
- else if( sflags == 2 )
- fputs( "[bad signature]", fp );
- else if( sflags < 0x10000000 )
- fprintf( fp, "[bad flag %0lx]", sflags );
- else if( sflags == 0xffffffff )
- fputs( "0", fp );
- else
- fputs( strtimestamp( sflags ), fp );
- putc('\n', fp );
- }
-
- fprintf( fp, "Ownertrust: %d\n", p[0] );
- fprintf( fp, "All-Validity: %d\n", p[1] );
- p += 4;
- n = get32( p ); p += 4;
- fprintf( fp, "Recheck-After: %s\n", n? strtimestamp(n) : "0" );
- n = get32( p ); p += 4;
- fprintf( fp, "Latest-Timestamp: %s\n", strtimestamp(n) );
- n = get32( p ); p += 4;
- fprintf( fp, "Created-At: %s\n", strtimestamp(n) );
- n = get32( p ); p += 4;
- fprintf( fp, "Reserved-Space: %lu\n", n );
-
-
- /* check that the keyblock is at the correct offset and other bounds */
-
-
- fprintf( fp, "Blob-Checksum: [MD5-hash]\n" );
- return 0;
-}
-
-/****************
- * Check whether the given fingerprint (20 bytes) is in the
- * given keyblob. fpr is always 20 bytes.
- * Return: 0 = found
- * -1 = not found
- other = error (fixme: do not always reurn gpgerr_general)
- */
-int
-kbx_blob_has_fpr ( KBXBLOB blob, const byte *fpr )
-{
- ulong n, nkeys, keyinfolen;
- const byte *p, *pend;
- byte *buffer = blob->blob;
- size_t buflen = blob->bloblen;
-
- if ( buflen < 40 )
- return GPGERR_GENERAL; /* blob too short */
- n = get32( buffer );
- if ( n > buflen )
- return GPGERR_GENERAL; /* blob larger than announced length */
- buflen = n; /* ignore trailing stuff */
- pend = buffer + n - 1;
-
- if ( buffer[4] != 2 )
- return GPGERR_GENERAL; /* invalid blob type */
- if ( buffer[5] != 1 )
- return GPGERR_GENERAL; /* invalid blob format version */
-
- nkeys = get16( buffer + 16 );
- keyinfolen = get16( buffer + 18 );
- p = buffer + 20;
- for(n=0; n < nkeys; n++, p += keyinfolen ) {
- if ( p+20 > pend )
- return GPGERR_GENERAL; /* blob shorter than required */
- if (!memcmp ( p, fpr, 20 ) )
- return 0; /* found */
- }
- return -1;
-}
-
-/****************
- * Check whether the given keyID (20 bytes) is in the
- * given keyblob.
- * Return: 0 = found
- * -1 = not found
- other = error (fixme: do not always return gpgerr_general)
- */
-int
-kbx_blob_has_kid ( KBXBLOB blob, const byte *keyidbuf, size_t keyidlen )
-{
- ulong n, nkeys, keyinfolen, off;
- const byte *p, *pend;
- byte *buffer = blob->blob;
- size_t buflen = blob->bloblen;
-
- if ( buflen < 40 )
- return GPGERR_GENERAL; /* blob too short */
- n = get32( buffer );
- if ( n > buflen )
- return GPGERR_GENERAL; /* blob larger than announced length */
- buflen = n; /* ignore trailing stuff */
- pend = buffer + n - 1;
-
- if ( buffer[4] != 2 )
- return GPGERR_GENERAL; /* invalid blob type */
- if ( buffer[5] != 1 )
- return GPGERR_GENERAL; /* invalid blob format version */
-
- nkeys = get16( buffer + 16 );
- keyinfolen = get16( buffer + 18 );
- p = buffer + 20;
- for(n=0; n < nkeys; n++, p += keyinfolen ) {
- if ( p+24 > pend )
- return GPGERR_GENERAL; /* blob shorter than required */
- off = get32 ( p + 20 );
- if (keyidlen < 8 ) /* actually keyidlen may either be 4 or 8 */
- off +=4;
- if ( off+keyidlen > buflen )
- return GPGERR_GENERAL; /* offset out of bounds */
- if ( !memcmp ( buffer+off, keyidbuf, keyidlen ) )
- return 0; /* found */
- }
- return -1;
-}
-
-
-
-int
-kbx_blob_has_uid ( KBXBLOB blob,
- int (*cmp)(const byte *, size_t, void *), void *opaque )
-{
- ulong n, nuids, uidinfolen, off, len;
- const byte *p, *pend;
- byte *buffer = blob->blob;
- size_t buflen = blob->bloblen;
-
- if ( buflen < 40 )
- return GPGERR_GENERAL; /* blob too short */
- n = get32( buffer );
- if ( n > buflen )
- return GPGERR_GENERAL; /* blob larger than announced length */
- buflen = n; /* ignore trailing stuff */
- pend = buffer + n - 1;
-
- if ( buffer[4] != 2 )
- return GPGERR_GENERAL; /* invalid blob type */
- if ( buffer[5] != 1 )
- return GPGERR_GENERAL; /* invalid blob format version */
-
- p = buffer + 20 + get16( buffer + 16 ) * get16( buffer + 18 );
- if ( p+4 > pend )
- return GPGERR_GENERAL; /* blob shorter than required */
-
- nuids = get16( p ); p+= 2;
- uidinfolen = get16( p ); p+=2;
- for(n=0; n < nuids; n++, p += uidinfolen ) {
- if ( p+8 > pend )
- return GPGERR_GENERAL; /* blob shorter than required */
- off = get32 ( p );
- len = get32 ( p + 4 );
- if ( off+len > buflen )
- return GPGERR_GENERAL; /* offset out of bounds */
- if ( (*cmp) ( buffer+off, len, opaque ) )
- return 0; /* found */
- }
-
- return -1;
-}
-
-
diff --git a/g10/kbxfile.c b/g10/kbxfile.c
deleted file mode 100644
index 94ef13f83..000000000
--- a/g10/kbxfile.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/* kbxfile.c - KBX file handling
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-/****************
- * We will change the whole system to use only KBX. This file here
- * will implement the methods needed to operate on plain KBXfiles.
- * Most stuff from getkey and ringedit will be replaced by stuff here.
- * To make things even more easier we will only allow one updateable kbxfile
- * and optionally some read-only files.
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <gcrypt.h>
-
-#include "kbx.h"
-#include "options.h"
-#include "util.h"
-#include "i18n.h"
-#include "main.h"
-
-/****************
- * Read the blob at the current fileposition and return an allocated
- * pointer nto the blob if it was found.
- * Fixme: return a blob object.
- */
-static int
-do_search_by_fpr ( const char *filename, FILE *a, const char *fpr,
- KBXBLOB *r_blob )
-{
- KBXBLOB blob;
- int rc;
-
- *r_blob = NULL;
- rc = kbx_read_blob ( &blob, a );
- if ( rc && rc != -1 ) {
- log_error (_("file `%s': error reading blob\n"), filename );
- }
- else if ( !rc ) {
- rc = kbx_blob_has_fpr ( blob, fpr );
- }
- else
- log_info ("eof\n");
-
- if ( !rc ) {
- *r_blob = blob;
- }
- else {
- kbx_release_blob ( blob );
- }
- return rc;
-}
-
-int
-kbxfile_search_by_fpr( const char *filename, const byte *fpr )
-{
- FILE *fp;
- KBXBLOB blob;
- int rc;
-
- fp = fopen ( filename, "rb" );
- if( !fp ) {
- log_error(_("can't open `%s': %s\n"), filename, strerror(errno) );
- return 1;
- }
-
- while ( (rc=do_search_by_fpr ( filename, fp, fpr, &blob )) == -1 )
- ;
- if ( !rc ) {
- fputs ("FOUND\n", stderr );
- kbx_dump_blob ( stderr, blob );
- kbx_release_blob ( blob );
- }
-
- fclose (fp);
- return -1;
-}
-
-
-/****************
- * Read the blob at the current fileposition and return an allocated
- * pointer nto the blob if it was found.
- * Fixme: return a blob object.
- */
-static int
-do_search_by_keyid ( const char *filename, FILE *a,
- const byte *keyidbuf, size_t keyidlen, KBXBLOB *r_blob )
-{
- KBXBLOB blob;
- int rc;
-
- *r_blob = NULL;
- rc = kbx_read_blob ( &blob, a );
- if ( rc && rc != -1 ) {
- log_error (_("file `%s': error reading blob\n"), filename );
- }
- else if ( !rc ) {
- rc = kbx_blob_has_kid ( blob, keyidbuf, keyidlen );
- }
- else
- rc = GPGERR_GENERAL; /* eof */
-
- if ( !rc ) {
- *r_blob = blob;
- }
- else {
- kbx_release_blob ( blob );
- }
- return rc;
-}
-
-/****************
- * Look for a KBX described by an keyid. This function will in
- * turn return each matching keyid because there may me duplicates
- * (which can't happen for fingerprints)
- * mode 10 = short keyid
- * 11 = long keyid
- */
-int
-kbxfile_search_by_kid ( const char *filename, u32 *kid, int mode )
-{
- FILE *fp;
- KBXBLOB blob;
- int rc;
- byte kbuf[8], *kbufptr;
- int kbuflen;
-
- fp = fopen ( filename, "rb" );
- if( !fp ) {
- log_error(_("can't open `%s': %s\n"), filename, strerror(errno) );
- return 1;
- }
-
- kbuf[0] = kid[0] >> 24;
- kbuf[1] = kid[0] >> 16;
- kbuf[2] = kid[0] >> 8;
- kbuf[3] = kid[0];
- kbuf[4] = kid[1] >> 24;
- kbuf[5] = kid[1] >> 16;
- kbuf[6] = kid[1] >> 8;
- kbuf[7] = kid[1];
- if ( mode == 10 ) {
- kbufptr=kbuf+4;
- kbuflen = 4;
- }
- else if (mode == 11 ) {
- kbufptr=kbuf;
- kbuflen = 8;
- }
- else {
- BUG();
- }
-
- do {
- while ( (rc=do_search_by_keyid ( filename, fp,
- kbufptr, kbuflen, &blob )) == -1 )
- ;
- if ( !rc ) {
- fputs ("FOUND:\n", stderr );
- kbx_dump_blob ( stderr, blob );
- kbx_release_blob ( blob );
- }
- } while ( !rc );
-
- fclose (fp);
- return -1;
-}
-
-
-static int
-do_search_by_uid ( const char *filename, FILE *a,
- int (*cmpfnc)(const byte*,size_t,void*), void *cmpdata,
- KBXBLOB *r_blob )
-{
- KBXBLOB blob;
- int rc;
-
- *r_blob = NULL;
- rc = kbx_read_blob ( &blob, a );
- if ( rc && rc != -1 ) {
- log_error (_("file `%s': error reading blob\n"), filename );
- }
- else if ( !rc ) {
- rc = kbx_blob_has_uid ( blob, cmpfnc, cmpdata );
- }
- else
- rc = GPGERR_GENERAL; /* eof */
-
- if ( !rc ) {
- *r_blob = blob;
- }
- else {
- kbx_release_blob ( blob );
- }
- return rc;
-}
-
-
-static int
-substr_compare ( const byte *buf, size_t buflen, void *opaque )
-{
- return !!memistr ( buf, buflen, opaque );
-}
-
-
-int
-kbxfile_search_by_uid ( const char *filename, const char *name )
-{
- FILE *fp;
- KBXBLOB blob;
- int rc;
- byte kbuf[8], *kbufptr;
- int kbuflen;
-
- fp = fopen ( filename, "rb" );
- if( !fp ) {
- log_error(_("can't open `%s': %s\n"), filename, strerror(errno) );
- return 1;
- }
-
-
- do {
- while ( (rc=do_search_by_uid ( filename, fp,
- substr_compare, name, &blob )) == -1 )
- ;
- if ( !rc ) {
- fputs ("FOUND:\n", stderr );
- kbx_dump_blob ( stderr, blob );
- kbx_release_blob ( blob );
- }
- } while ( !rc );
-
- fclose ( fp );
- return -1;
-}
-
-
-
-void
-export_as_kbxfile(void)
-{
-
- KBPOS kbpos;
- KBNODE keyblock = NULL;
- int rc=0;
-
- rc = enum_keyblocks_begin( &kbpos, 0 );
- if( rc ) {
- if( rc != -1 )
- log_error("enum_keyblocks(open) failed: %s\n", gpg_errstr(rc) );
- goto leave;
- }
-
- while( !(rc = enum_keyblocks_next( kbpos, 1, &keyblock )) ) {
- KBXBLOB blob;
- const char *p;
- size_t n;
-
- merge_keys_and_selfsig( keyblock );
- rc = kbx_create_blob ( &blob, keyblock );
- if( rc ) {
- log_error("kbx_create_blob failed: %s\n", gpg_errstr(rc) );
- goto leave;
- }
- p = kbx_get_blob_image ( blob, &n );
- fwrite( p, n, 1, stdout );
- kbx_release_blob ( blob );
- }
-
- if( rc && rc != -1 )
- log_error("enum_keyblocks(read) failed: %s\n", gpg_errstr(rc));
-
- leave:
- enum_keyblocks_end( kbpos );
- release_kbnode( keyblock );
-}
-
-
-static int
-do_print_kbxfile( const char *filename, FILE *a )
-{
- KBXBLOB blob;
- int rc;
-
- rc = kbx_read_blob ( &blob, a );
- if ( rc && rc != -1 ) {
- log_error (_("file `%s': error reading blob\n"), filename );
- }
- else if ( ! rc )
- kbx_dump_blob ( stdout, blob );
- kbx_release_blob ( blob );
- return rc;
-}
-
-void
-print_kbxfile( const char *filename )
-{
- FILE *fp;
-
- fp = fopen ( filename, "rb" );
- if( !fp ) {
- log_error(_("can't open `%s': %s\n"), filename, strerror(errno) );
- return;
- }
-
- while ( !do_print_kbxfile( filename, fp ) )
- ;
-
- fclose (fp);
-}
-
diff --git a/g10/kbxio.c b/g10/kbxio.c
deleted file mode 100644
index 6c4437bf8..000000000
--- a/g10/kbxio.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* kbxio.c - KBX I/O handling
- * Copyright (C) 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <gcrypt.h>
-
-#include "iobuf.h"
-#include "util.h"
-#include "kbx.h"
-
-
-int
-kbx_read_blob ( KBXBLOB *r_blob, FILE *a )
-{
- char *image;
- size_t imagelen = 0;
- int c1, c2, c3, c4;
- int rc;
-
- *r_blob = NULL;
- if ( (c1 = getc ( a )) == EOF
- || (c2 = getc ( a )) == EOF
- || (c3 = getc ( a )) == EOF
- || (c4 = getc ( a )) == EOF ) {
- if ( c1 == EOF && !ferror ( a ) )
- return -1;
- return GPGERR_GENERAL;
- }
- imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
- if ( imagelen > 500000 ) { /* sanity check:blob too large */
- return GPGERR_GENERAL;
- }
- else if ( imagelen < 4 ) { /* blobtoo short */
- return GPGERR_GENERAL;
- }
- image = gcry_malloc ( imagelen );
- if ( !image ) {
- return GPGERR_GENERAL;
- }
-
- image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4;
- if ( fread ( image+4, imagelen-4, 1, a ) != 1 ) {
- gcry_free ( image );
- return GPGERR_GENERAL;
- }
-
- rc = kbx_new_blob ( r_blob, image, imagelen );
- return rc;
-}
-
-
-
diff --git a/g10/kbxutil.c b/g10/kbxutil.c
deleted file mode 100644
index 95fcb9cce..000000000
--- a/g10/kbxutil.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* gpg.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#include <gcrypt.h>
-
-#include "packet.h"
-#include "iobuf.h"
-#include "util.h"
-#include "main.h"
-#include "options.h"
-#include "keydb.h"
-#include "filter.h"
-#include "ttyio.h"
-#include "i18n.h"
-#include "gnupg-defs.h"
-#include "kbx.h"
-
-
-enum cmd_and_opt_values { aNull = 0,
- oArmor = 'a',
- aDetachedSign = 'b',
- aSym = 'c',
- aDecrypt = 'd',
- aEncr = 'e',
- oInteractive = 'i',
- oKOption = 'k',
- oDryRun = 'n',
- oOutput = 'o',
- oQuiet = 'q',
- oRecipient = 'r',
- aSign = 's',
- oTextmodeShort= 't',
- oUser = 'u',
- oVerbose = 'v',
- oCompress = 'z',
- oNotation = 'N',
- oBatch = 500,
- aClearsign,
- aStore,
- aKeygen,
- aSignEncr,
- aSignKey,
- aLSignKey,
- aListPackets,
- aEditKey,
- aDeleteKey,
- aDeleteSecretKey,
- aKMode,
- aKModeC,
- aImport,
- aFastImport,
- aVerify,
- aListKeys,
- aListSigs,
- aListSecretKeys,
- aSendKeys,
- aRecvKeys,
- aExport,
- aExportAll,
- aExportSecret,
- aCheckKeys,
- aGenRevoke,
- aPrimegen,
- aPrintMD,
- aPrintHMAC,
- aPrintMDs,
- aCheckTrustDB,
- aUpdateTrustDB,
- aFixTrustDB,
- aListTrustDB,
- aListTrustPath,
- aExportOwnerTrust,
- aImportOwnerTrust,
- aDeArmor,
- aEnArmor,
- aGenRandom,
-
- oTextmode,
- oFingerprint,
- oWithFingerprint,
- oAnswerYes,
- oAnswerNo,
- oKeyring,
- oSecretKeyring,
- oDefaultKey,
- oDefRecipient,
- oDefRecipientSelf,
- oNoDefRecipient,
- oOptions,
- oDebug,
- oDebugAll,
- oStatusFD,
- oNoComment,
- oNoVersion,
- oEmitVersion,
- oCompletesNeeded,
- oMarginalsNeeded,
- oMaxCertDepth,
- oLoadExtension,
- oRFC1991,
- oOpenPGP,
- oCipherAlgo,
- oDigestAlgo,
- oCompressAlgo,
- oPasswdFD,
- oNoVerbose,
- oTrustDBName,
- oNoSecmemWarn,
- oNoArmor,
- oNoDefKeyring,
- oNoGreeting,
- oNoTTY,
- oNoOptions,
- oNoBatch,
- oHomedir,
- oWithColons,
- oWithKeyData,
- oSkipVerify,
- oCompressKeys,
- oCompressSigs,
- oAlwaysTrust,
- oEmuChecksumBug,
- oRunAsShmCP,
- oSetFilename,
- oSetPolicyURL,
- oUseEmbeddedFilename,
- oComment,
- oDefaultComment,
- oThrowKeyid,
- oForceV3Sigs,
- oForceMDC,
- oS2KMode,
- oS2KDigest,
- oS2KCipher,
- oCharset,
- oNotDashEscaped,
- oEscapeFrom,
- oLockOnce,
- oLockMultiple,
- oKeyServer,
- oEncryptTo,
- oNoEncryptTo,
- oLoggerFD,
- oUtf8Strings,
- oNoUtf8Strings,
- oDisableCipherAlgo,
- oDisablePubkeyAlgo,
- oAllowNonSelfsignedUID,
- oNoLiteral,
- oSetFilesize,
- oEntropyDLLName,
-
- aFindByFpr,
- aFindByKid,
- aFindByUid,
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 300, NULL, 0, N_("@Commands:\n ") },
-
- { aFindByFpr, "find-by-fpr", 0, "|FPR| find key using it's fingerprnt" },
- { aFindByKid, "find-by-kid", 0, "|KID| find key using it's keyid" },
- { aFindByUid, "find-by-uid", 0, "|NAME| find key by user name" },
-
- { 301, NULL, 0, N_("@\nOptions:\n ") },
-
- { oArmor, "armor", 0, N_("create ascii armored output")},
- { oArmor, "armour", 0, "@" },
- { oCompress, NULL, 1, N_("|N|set compress level N (0 disables)") },
- { oOutput, "output", 2, N_("use as output file")},
- { oVerbose, "verbose", 0, N_("verbose") },
- { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
- { oDryRun, "dry-run", 0, N_("do not make any changes") },
- { oOptions, "options" , 2, N_("read options from file")},
-
- { oDebug, "debug" ,4|16, N_("set debugging flags")},
- { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
-
-
-{0} };
-
-
-
-int gpg_errors_seen = 0;
-
-
-static const char *
-my_strusage( int level )
-{
- const char *p;
- switch( level ) {
- case 11: p = "kbxutil (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p =
- _("Please report bugs to <gnupg-bugs@gnu.org>.\n");
- break;
- case 1:
- case 40: p =
- _("Usage: kbxutil [options] [files] (-h for help)");
- break;
- case 41: p =
- _("Syntax: kbxutil [options] [files]\n"
- "list, export, import KBX data\n");
- break;
-
-
- default: p = NULL;
- }
- return p;
-}
-
-
-static void
-i18n_init(void)
-{
- #ifdef USE_SIMPLE_GETTEXT
- set_gettext_file( PACKAGE );
- #else
- #ifdef ENABLE_NLS
- #ifdef HAVE_LC_MESSAGES
- setlocale( LC_TIME, "" );
- setlocale( LC_MESSAGES, "" );
- #else
- setlocale( LC_ALL, "" );
- #endif
- bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
- textdomain( PACKAGE );
- #endif
- #endif
-}
-
-
-static void
-wrong_args( const char *text )
-{
- log_error("usage: kbxutil %s\n", text);
- gpg_exit ( 1 );
-}
-
-
-static int
-hextobyte( const byte *s )
-{
- int c;
-
- if( *s >= '0' && *s <= '9' )
- c = 16 * (*s - '0');
- else if( *s >= 'A' && *s <= 'F' )
- c = 16 * (10 + *s - 'A');
- else if( *s >= 'a' && *s <= 'f' )
- c = 16 * (10 + *s - 'a');
- else
- return -1;
- s++;
- if( *s >= '0' && *s <= '9' )
- c += *s - '0';
- else if( *s >= 'A' && *s <= 'F' )
- c += 10 + *s - 'A';
- else if( *s >= 'a' && *s <= 'f' )
- c += 10 + *s - 'a';
- else
- return -1;
- return c;
-}
-
-static char *
-format_fingerprint ( const char *s )
-{
- int i, c;
- byte fpr[20];
-
- for (i=0; i < 20 && *s; ) {
- if ( *s == ' ' || *s == '\t' ) {
- s++;
- continue;
- }
- c = hextobyte(s);
- if (c == -1) {
- return NULL;
- }
- fpr[i++] = c;
- s += 2;
- }
- return gcry_xstrdup ( fpr );
-}
-
-static int
-format_keyid ( const char *s, u32 *kid )
-{
- char helpbuf[9];
- switch ( strlen ( s ) ) {
- case 8:
- kid[0] = 0;
- kid[1] = strtoul( s, NULL, 16 );
- return 10;
-
- case 16:
- mem2str( helpbuf, s, 9 );
- kid[0] = strtoul( helpbuf, NULL, 16 );
- kid[1] = strtoul( s+8, NULL, 16 );
- return 11;
- }
- return 0; /* error */
-}
-
-
-
-int
-main( int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- enum cmd_and_opt_values cmd = 0;
-
- set_strusage( my_strusage );
- log_set_name("kbxutil");
- /* check that the libraries are suitable. Do it here because
- * the option parse may need services of the library */
- if ( !gcry_check_version ( "1.1.0a" ) ) {
- log_fatal(_("libgcrypt is too old (need %s, have %s)\n"),
- VERSION, gcry_check_version(NULL) );
- }
-
- create_dotlock(NULL); /* register locking cleanup */
- i18n_init();
-
-
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- while( arg_parse( &pargs, opts) ) {
- switch( pargs.r_opt ) {
- case oVerbose:
- opt.verbose++;
- gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );
- break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
-
- case aFindByFpr:
- case aFindByKid:
- case aFindByUid:
- cmd = pargs.r_opt;
- break;
-
- default : pargs.err = 2; break;
- }
- }
- if( log_get_errorcount(0) )
- gpg_exit(2);
-
- if ( !cmd ) { /* default is to list a KBX file */
- if( !argc ) {
- print_kbxfile( NULL );
- }
- else {
- for ( ; argc; argc--, argv++ ) {
- print_kbxfile( *argv );
- }
- }
- }
- else if ( cmd == aFindByFpr ) {
- char *fpr;
- if ( argc != 2 )
- wrong_args ("kbxfile foingerprint");
- fpr = format_fingerprint ( argv[1] );
- if ( !fpr )
- log_error ("invalid formatted fingerprint\n");
- else {
- kbxfile_search_by_fpr ( argv[0], fpr );
- gcry_free ( fpr );
- }
- }
- else if ( cmd == aFindByKid ) {
- u32 kid[2];
- int mode;
-
- if ( argc != 2 )
- wrong_args ("kbxfile short-or-long-keyid");
- mode = format_keyid ( argv[1], kid );
- if ( !mode )
- log_error ("invalid formatted keyID\n");
- else {
- kbxfile_search_by_kid ( argv[0], kid, mode );
- }
- }
- else if ( cmd == aFindByUid ) {
- if ( argc != 2 )
- wrong_args ("kbxfile userID");
- kbxfile_search_by_uid ( argv[0], argv[1] );
- }
- else
- log_error ("unsupported action\n");
-
- gpg_exit(0);
- return 8; /*NEVER REACHED*/
-}
-
-
-void
-gpg_exit( int rc )
-{
- if( opt.debug & DBG_MEMSTAT_VALUE ) {
- gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
- gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
- }
- if( opt.debug )
- gcry_control( GCRYCTL_DUMP_SECMEM_STATS );
- rc = rc? rc : log_get_errorcount(0)? 2 :
- gpg_errors_seen? 1 : 0;
- exit(rc );
-}
-
-
diff --git a/g10/keydb.c b/g10/keydb.c
new file mode 100644
index 000000000..96d19105a
--- /dev/null
+++ b/g10/keydb.c
@@ -0,0 +1,698 @@
+/* keydb.c - key database dispatcher
+ * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "options.h"
+#include "main.h" /*try_make_homedir ()*/
+#include "packet.h"
+#include "keyring.h"
+#include "keydb.h"
+#include "i18n.h"
+
+static int active_handles;
+
+typedef enum {
+ KEYDB_RESOURCE_TYPE_NONE = 0,
+ KEYDB_RESOURCE_TYPE_KEYRING
+} KeydbResourceType;
+#define MAX_KEYDB_RESOURCES 20
+
+struct resource_item {
+ KeydbResourceType type;
+ union {
+ KEYRING_HANDLE kr;
+ } u;
+ void *token;
+ int secret;
+};
+
+static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
+static int used_resources;
+
+struct keydb_handle {
+ int locked;
+ int found;
+ int current;
+ int used; /* items in active */
+ struct resource_item active[MAX_KEYDB_RESOURCES];
+};
+
+
+static int lock_all (KEYDB_HANDLE hd);
+static void unlock_all (KEYDB_HANDLE hd);
+
+
+/*
+ * Register a resource (which currently may only be a keyring file).
+ * The first keyring which is added by this function is
+ * created if it does not exist.
+ * Note: this function may be called before secure memory is
+ * available.
+ */
+int
+keydb_add_resource (const char *url, int force, int secret)
+{
+ static int any_secret, any_public;
+ const char *resname = url;
+ IOBUF iobuf = NULL;
+ char *filename = NULL;
+ int rc = 0;
+ KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
+ void *token;
+
+ /* Do we have an URL?
+ * gnupg-ring:filename := this is a plain keyring
+ * filename := See what is is, but create as plain keyring.
+ */
+ if (strlen (resname) > 11) {
+ if (!strncmp( resname, "gnupg-ring:", 11) ) {
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ resname += 11;
+ }
+ #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
+ else if (strchr (resname, ':')) {
+ log_error ("invalid key resource URL `%s'\n", url );
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+ #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
+ }
+
+ if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
+ if (strchr(resname, DIRSEP_C) )
+ filename = make_filename (resname, NULL);
+ else
+ filename = make_filename (opt.homedir, resname, NULL);
+ }
+ else
+ filename = m_strdup (resname);
+
+ check_permissions(filename,0,0);
+
+ if (!force)
+ force = secret? !any_secret : !any_public;
+
+ /* see whether we can determine the filetype */
+ if (rt == KEYDB_RESOURCE_TYPE_NONE) {
+ FILE *fp = fopen( filename, "rb" );
+
+ if (fp) {
+ u32 magic;
+
+ if (fread( &magic, 4, 1, fp) == 1 ) {
+ if (magic == 0x13579ace || magic == 0xce9a5713)
+ ; /* GDBM magic - no more support */
+ else
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ }
+ else /* maybe empty: assume ring */
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ fclose( fp );
+ }
+ else /* no file yet: create ring */
+ rt = KEYDB_RESOURCE_TYPE_KEYRING;
+ }
+
+ switch (rt) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ log_error ("unknown type of key resource `%s'\n", url );
+ rc = G10ERR_GENERAL;
+ goto leave;
+
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ if (access(filename, F_OK))
+ { /* file does not exist */
+ char *last_slash_in_filename;
+
+ if (!force)
+ {
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ last_slash_in_filename = strrchr (filename, DIRSEP_C);
+ *last_slash_in_filename = 0;
+ if (access(filename, F_OK))
+ { /* on the first time we try to create the default
+ homedir and in this case the process will be
+ terminated, so that on the next invocation it can
+ read the options file in on startup */
+ try_make_homedir (filename);
+ rc = G10ERR_OPEN_FILE;
+ *last_slash_in_filename = DIRSEP_C;
+ goto leave;
+ }
+ *last_slash_in_filename = DIRSEP_C;
+
+ iobuf = iobuf_create (filename);
+ if (!iobuf)
+ {
+ log_error ( _("error creating keyring `%s': %s\n"),
+ filename, strerror(errno));
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+#ifndef HAVE_DOSISH_SYSTEM
+ if (secret && !opt.preserve_permissions)
+ {
+ if (chmod (filename, S_IRUSR | S_IWUSR) )
+ {
+ log_error (_("changing permission of "
+ " `%s' failed: %s\n"),
+ filename, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+#endif
+ if (!opt.quiet)
+ log_info (_("keyring `%s' created\n"), filename);
+ iobuf_close (iobuf);
+ iobuf = NULL;
+ /* must invalidate that ugly cache */
+ iobuf_ioctl (NULL, 2, 0, (char*)filename);
+ } /* end file creation */
+
+ token = keyring_register_filename (filename, secret);
+ if (!token)
+ ; /* already registered - ignore it */
+ else if (used_resources >= MAX_KEYDB_RESOURCES)
+ rc = G10ERR_RESOURCE_LIMIT;
+ else
+ {
+ all_resources[used_resources].type = rt;
+ all_resources[used_resources].u.kr = NULL; /* Not used here */
+ all_resources[used_resources].token = token;
+ all_resources[used_resources].secret = secret;
+ used_resources++;
+ }
+ break;
+
+ default:
+ log_error ("resource type of `%s' not supported\n", url);
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+
+ /* fixme: check directory permissions and print a warning */
+
+ leave:
+ if (rc)
+ log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
+ else if (secret)
+ any_secret = 1;
+ else
+ any_public = 1;
+ m_free (filename);
+ return rc;
+}
+
+
+
+
+KEYDB_HANDLE
+keydb_new (int secret)
+{
+ KEYDB_HANDLE hd;
+ int i, j;
+
+ hd = m_alloc_clear (sizeof *hd);
+ hd->found = -1;
+
+ assert (used_resources <= MAX_KEYDB_RESOURCES);
+ for (i=j=0; i < used_resources; i++)
+ {
+ if (!all_resources[i].secret != !secret)
+ continue;
+ switch (all_resources[i].type)
+ {
+ case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ hd->active[j].type = all_resources[i].type;
+ hd->active[j].token = all_resources[i].token;
+ hd->active[j].secret = all_resources[i].secret;
+ hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
+ if (!hd->active[j].u.kr) {
+ m_free (hd);
+ return NULL; /* fixme: release all previously allocated handles*/
+ }
+ j++;
+ break;
+ }
+ }
+ hd->used = j;
+
+ active_handles++;
+ return hd;
+}
+
+void
+keydb_release (KEYDB_HANDLE hd)
+{
+ int i;
+
+ if (!hd)
+ return;
+ assert (active_handles > 0);
+ active_handles--;
+
+ unlock_all (hd);
+ for (i=0; i < hd->used; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_release (hd->active[i].u.kr);
+ break;
+ }
+ }
+
+ m_free (hd);
+}
+
+
+/*
+ * Return the name of the current resource. This is function first
+ * looks for the last found found, then for the current search
+ * position, and last returns the first available resource. The
+ * returned string is only valid as long as the handle exists. This
+ * function does only return NULL if no handle is specified, in all
+ * other error cases an empty string is returned.
+ */
+const char *
+keydb_get_resource_name (KEYDB_HANDLE hd)
+{
+ int idx;
+ const char *s = NULL;
+
+ if (!hd)
+ return NULL;
+
+ if ( hd->found >= 0 && hd->found < hd->used)
+ idx = hd->found;
+ else if ( hd->current >= 0 && hd->current < hd->used)
+ idx = hd->current;
+ else
+ idx = 0;
+
+ switch (hd->active[idx].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ s = NULL;
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ s = keyring_get_resource_name (hd->active[idx].u.kr);
+ break;
+ }
+
+ return s? s: "";
+}
+
+
+
+static int
+lock_all (KEYDB_HANDLE hd)
+{
+ int i, rc = 0;
+
+ for (i=0; !rc && i < hd->used; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_lock (hd->active[i].u.kr, 1);
+ break;
+ }
+ }
+
+ if (rc) {
+ /* revert the already set locks */
+ for (i--; i >= 0; i--) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_lock (hd->active[i].u.kr, 0);
+ break;
+ }
+ }
+ }
+ else
+ hd->locked = 1;
+
+ return rc;
+}
+
+static void
+unlock_all (KEYDB_HANDLE hd)
+{
+ int i;
+
+ if (!hd->locked)
+ return;
+
+ for (i=hd->used-1; i >= 0; i--) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ keyring_lock (hd->active[i].u.kr, 0);
+ break;
+ }
+ }
+ hd->locked = 0;
+}
+
+
+/*
+ * Return the last found keyring. Caller must free it.
+ * The returned keyblock has the kbode flag bit 0 set for the node with
+ * the public key used to locate the keyblock or flag bit 1 set for
+ * the user ID node.
+ */
+int
+keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
+{
+ int rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= hd->used)
+ return -1; /* nothing found */
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * update the current keyblock with KB
+ */
+int
+keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
+{
+ int rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= hd->used)
+ return -1; /* nothing found */
+
+ if( opt.dry_run )
+ return 0;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * Insert a new KB into one of the resources.
+ */
+int
+keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
+{
+ int rc = -1;
+ int idx;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if( opt.dry_run )
+ return 0;
+
+ if ( hd->found >= 0 && hd->found < hd->used)
+ idx = hd->found;
+ else if ( hd->current >= 0 && hd->current < hd->used)
+ idx = hd->current;
+ else
+ return G10ERR_GENERAL;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[idx].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * The current keyblock will be deleted.
+ */
+int
+keydb_delete_keyblock (KEYDB_HANDLE hd)
+{
+ int rc = -1;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ if ( hd->found < 0 || hd->found >= hd->used)
+ return -1; /* nothing found */
+
+ if( opt.dry_run )
+ return 0;
+
+ rc = lock_all (hd);
+ if (rc)
+ return rc;
+
+ switch (hd->active[hd->found].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ rc = G10ERR_GENERAL; /* oops */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
+ break;
+ }
+
+ unlock_all (hd);
+ return rc;
+}
+
+
+/*
+ * Locate the default writable key resource, so that the next
+ * operation (which is only relevant for inserts) will be done on this
+ * resource.
+ */
+int
+keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
+{
+ int rc;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ rc = keydb_search_reset (hd); /* this does reset hd->current */
+ if (rc)
+ return rc;
+
+ for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
+ {
+ switch (hd->active[hd->current].type)
+ {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ BUG();
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ if (keyring_is_writable (hd->active[hd->current].token))
+ return 0; /* found (hd->current is set to it) */
+ break;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * Rebuild the caches of all key resources.
+ */
+void
+keydb_rebuild_caches (void)
+{
+ int i, rc;
+
+ for (i=0; i < used_resources; i++)
+ {
+ if (all_resources[i].secret)
+ continue;
+ switch (all_resources[i].type)
+ {
+ case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_rebuild_cache (all_resources[i].token);
+ if (rc)
+ log_error (_("failed to rebuild keyring cache: %s\n"),
+ g10_errstr (rc));
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Start the next search on this handle right at the beginning
+ */
+int
+keydb_search_reset (KEYDB_HANDLE hd)
+{
+ int i, rc = 0;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ hd->current = 0;
+ hd->found = -1;
+ /* and reset all resources */
+ for (i=0; !rc && i < hd->used; i++) {
+ switch (hd->active[i].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_search_reset (hd->active[i].u.kr);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+/*
+ * Search through all keydb resources, starting at the current position,
+ * for a keyblock which contains one of the keys described in the DESC array.
+ */
+int
+keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+{
+ int rc = -1;
+
+ if (!hd)
+ return G10ERR_INV_ARG;
+
+ while (rc == -1 && hd->current >= 0 && hd->current < hd->used) {
+ switch (hd->active[hd->current].type) {
+ case KEYDB_RESOURCE_TYPE_NONE:
+ BUG(); /* we should never see it here */
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYRING:
+ rc = keyring_search (hd->active[hd->current].u.kr, desc, ndesc);
+ break;
+ }
+ if (rc == -1) /* EOF -> switch to next resource */
+ hd->current++;
+ else if (!rc)
+ hd->found = hd->current;
+ }
+
+ return rc;
+}
+
+
+int
+keydb_search_first (KEYDB_HANDLE hd)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_next (KEYDB_HANDLE hd)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_NEXT;
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
+ desc.u.kid[0] = kid[0];
+ desc.u.kid[1] = kid[1];
+ return keydb_search (hd, &desc, 1);
+}
+
+int
+keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FPR;
+ memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
+ return keydb_search (hd, &desc, 1);
+}
+
+
+
diff --git a/g10/keydb.h b/g10/keydb.h
index c2131ada7..34d02d702 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -1,5 +1,5 @@
/* keydb.h - Key database
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,14 +18,18 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_KEYDB_H
-#define GPG_KEYDB_H
+#ifndef G10_KEYDB_H
+#define G10_KEYDB_H
#include "types.h"
-#include "basicdefs.h"
+#include "global.h"
#include "packet.h"
+#include "cipher.h"
-#define MAX_FINGERPRINT_LEN 20
+/* What qualifies as a certification (rather than a signature?) */
+#define IS_SIG(s) (((s)->sig_class==0x00) || ((s)->sig_class==0x01) || \
+ ((s)->sig_class==0x02) || ((s)->sig_class==0x40))
+#define IS_CERT(s) (!IS_SIG(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
@@ -35,7 +39,6 @@
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
-
struct getkey_ctx_s;
typedef struct getkey_ctx_s *GETKEY_CTX;
@@ -47,7 +50,6 @@ typedef struct getkey_ctx_s *GETKEY_CTX;
* This structure is also used to bind arbitrary packets together.
*/
-typedef struct kbnode_struct *KBNODE;
struct kbnode_struct {
KBNODE next;
PACKET *pkt;
@@ -62,19 +64,28 @@ struct kbnode_struct {
enum resource_type {
rt_UNKNOWN = 0,
- rt_RING = 1,
- rt_KBXF = 2
+ rt_RING = 1
};
/****************
- * A data structure to hold information about the external position
+ * A data structre to hold information about the external position
* of a keyblock.
*/
-struct keyblock_pos_struct;
-typedef struct keyblock_pos_struct *KBPOS;
+struct keyblock_pos_struct {
+ int resno; /* resource number */
+ enum resource_type rt;
+ off_t offset; /* position information */
+ unsigned count; /* length of the keyblock in packets */
+ IOBUF fp; /* used by enum_keyblocks */
+ int secret; /* working on a secret keyring */
+ PACKET *pkt; /* ditto */
+ int valid;
+};
+typedef struct keyblock_pos_struct KBPOS;
/* structure to hold a couple of public key certificates */
+typedef struct pk_list *PK_LIST;
struct pk_list {
PK_LIST next;
PKT_public_key *pk;
@@ -82,18 +93,82 @@ struct pk_list {
};
/* structure to hold a couple of secret key certificates */
+typedef struct sk_list *SK_LIST;
struct sk_list {
SK_LIST next;
PKT_secret_key *sk;
int mark;
};
+/* structure to collect all information which can be used to
+ * identify a public key */
+typedef struct pubkey_find_info *PUBKEY_FIND_INFO;
+struct pubkey_find_info {
+ u32 keyid[2];
+ unsigned nbits;
+ byte pubkey_algo;
+ byte fingerprint[MAX_FINGERPRINT_LEN];
+ char userid[1];
+};
+
+
+typedef struct keydb_handle *KEYDB_HANDLE;
+
+typedef enum {
+ KEYDB_SEARCH_MODE_NONE,
+ KEYDB_SEARCH_MODE_EXACT,
+ KEYDB_SEARCH_MODE_SUBSTR,
+ KEYDB_SEARCH_MODE_MAIL,
+ KEYDB_SEARCH_MODE_MAILSUB,
+ KEYDB_SEARCH_MODE_MAILEND,
+ KEYDB_SEARCH_MODE_WORDS,
+ KEYDB_SEARCH_MODE_SHORT_KID,
+ KEYDB_SEARCH_MODE_LONG_KID,
+ KEYDB_SEARCH_MODE_FPR16,
+ KEYDB_SEARCH_MODE_FPR20,
+ KEYDB_SEARCH_MODE_FPR,
+ KEYDB_SEARCH_MODE_FIRST,
+ KEYDB_SEARCH_MODE_NEXT
+} KeydbSearchMode;
+
+struct keydb_search_desc {
+ KeydbSearchMode mode;
+ int (*skipfnc)(void *,u32*);
+ void *skipfncvalue;
+ union {
+ const char *name;
+ char fpr[MAX_FINGERPRINT_LEN];
+ u32 kid[2];
+ } u;
+};
+
+/*-- keydb.c --*/
+int keydb_add_resource (const char *url, int force, int secret);
+KEYDB_HANDLE keydb_new (int secret);
+void keydb_release (KEYDB_HANDLE hd);
+const char *keydb_get_resource_name (KEYDB_HANDLE hd);
+int keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
+int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
+int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
+int keydb_delete_keyblock (KEYDB_HANDLE hd);
+int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
+void keydb_rebuild_caches (void);
+int keydb_search_reset (KEYDB_HANDLE hd);
+int keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
+int keydb_search_first (KEYDB_HANDLE hd);
+int keydb_search_next (KEYDB_HANDLE hd);
+int keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
+int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
+
/*-- pkclist.c --*/
+void show_revocation_reason( PKT_public_key *pk, int mode );
int check_signatures_trust( PKT_signature *sig );
void release_pk_list( PK_LIST pk_list );
-int build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use );
-int select_algo_from_prefs( PK_LIST pk_list, int preftype );
+int build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use );
+int select_algo_from_prefs( PK_LIST pk_list, int preftype,
+ int request, void *hint );
+int select_mdc_from_pklist (PK_LIST pk_list);
/*-- skclist.c --*/
void release_sk_list( SK_LIST sk_list );
@@ -105,18 +180,19 @@ int have_static_passphrase(void);
void read_passphrase_from_fd( int fd );
void passphrase_clear_cache ( u32 *keyid, int algo );
DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
- int cipher_algo, STRING2KEY *s2k, int mode);
+ int cipher_algo, STRING2KEY *s2k, int mode,
+ const char *tryagain_text);
void set_next_passphrase( const char *s );
char *get_last_passphrase(void);
/*-- getkey.c --*/
-int classify_user_id( const char *name, u32 *keyid, byte *fprint,
- const char **retstr, size_t *retlen );
+int classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc);
+void cache_public_key( PKT_public_key *pk );
void getkey_disable_caches(void);
int get_pubkey( PKT_public_key *pk, u32 *keyid );
KBNODE get_pubkeyblock( u32 *keyid );
-int get_pubkey_byname( GETKEY_CTX *rx, PKT_public_key *pk,
- const char *name, KBNODE *ret_keyblock );
+int get_pubkey_byname( PKT_public_key *pk, const char *name,
+ KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd);
int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock );
int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
@@ -129,25 +205,21 @@ int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
size_t fprint_len );
int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
int seckey_available( u32 *keyid );
-int get_seckey_byname( GETKEY_CTX *rx,
- PKT_secret_key *sk, const char *name, int unlock,
- KBNODE *retblock );
+int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
STRLIST names, KBNODE *ret_keyblock );
+int get_seckey_byfprint( PKT_secret_key *sk,
+ const byte *fprint, size_t fprint_len);
int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
void get_seckey_end( GETKEY_CTX ctx );
-int find_keyblock_byname( KBNODE *retblock, const char *username );
-int find_secret_keyblock_byname( KBNODE *retblock, const char *username );
-int find_keyblock_bypk( KBNODE *retblock, PKT_public_key *pk );
-int find_keyblock_bysk( KBNODE *retblock, PKT_secret_key *sk );
-
int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys );
void merge_keys_and_selfsig( KBNODE keyblock );
-void merge_public_with_secret ( KBNODE pubblock, KBNODE secblock );
char*get_user_id_string( u32 *keyid );
char*get_user_id_string_native( u32 *keyid );
char*get_long_user_id_string( u32 *keyid );
char*get_user_id( u32 *keyid, size_t *rn );
+char*get_user_id_native( u32 *keyid );
+KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
/*-- keyid.c --*/
int pubkey_letter( int algo );
@@ -162,12 +234,16 @@ const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig );
const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sk( PKT_secret_key *sk );
+const char *expirestr_from_sig( PKT_signature *sig );
+
+const char *colon_strtime (u32 t);
+const char *colon_datestr_from_pk (PKT_public_key *pk);
+const char *colon_datestr_from_sk (PKT_secret_key *sk);
+const char *colon_datestr_from_sig (PKT_signature *sig);
+const char *colon_expirestr_from_sig (PKT_signature *sig);
+
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
-char *unified_fingerprint_from_pk( PKT_public_key *pk,
- char *buffer, size_t bufsize );
-char *unified_fingerprint_from_sk( PKT_secret_key *sk,
- char *buffer, size_t bufsize );
/*-- kbnode.c --*/
KBNODE new_kbnode( PACKET *pkt );
@@ -186,18 +262,4 @@ void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
-/*-- ringedit.c --*/
-const char *enum_keyblock_resources( int *sequence, int secret );
-int add_keyblock_resource( const char *resname, int force, int secret );
-const char *keyblock_resource_name( KBPOS kbpos );
-int get_keyblock_handle( const char *filename, int secret, KBPOS kbpos );
-char *get_writable_keyblock_file( int secret );
-int enum_keyblocks_begin( KBPOS *kbpos, int mode );
-int enum_keyblocks_next( KBPOS kbpos, int mode, KBNODE *ret_root );
-void enum_keyblocks_end( KBPOS kbpos );
-int insert_keyblock( KBNODE keyblock );
-int delete_keyblock( KBNODE keyblock );
-int update_keyblock( KBNODE keyblock );
-
-
-#endif /*GPG_KEYDB_H*/
+#endif /*G10_KEYDB_H*/
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 095e43baf..db811ac0c 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1,5 +1,5 @@
/* keyedit.c - keyedit stuff
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -31,7 +31,8 @@
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
+#include "photoid.h"
#include "util.h"
#include "main.h"
#include "trustdb.h"
@@ -40,26 +41,32 @@
#include "status.h"
#include "i18n.h"
-static void show_prefs( KBNODE keyblock, PKT_user_id *uid );
-static void show_key_with_all_names( KBNODE keyblock,
- int only_marked, int with_fpr, int with_subkeys, int with_prefs );
+static void show_prefs( PKT_user_id *uid, int verbose );
+static void show_key_with_all_names( KBNODE keyblock, int only_marked,
+ int with_revoker, int with_fpr, int with_subkeys, int with_prefs );
static void show_key_and_fingerprint( KBNODE keyblock );
-static void show_fingerprint( PKT_public_key *pk );
-static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
+static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock, int photo );
static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int menu_delsig( KBNODE pub_keyblock );
static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int menu_set_primary_uid( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int menu_set_preferences( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int menu_select_uid( KBNODE keyblock, int idx );
static int menu_select_key( KBNODE keyblock, int idx );
static int count_uids( KBNODE keyblock );
static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
static int count_selected_uids( KBNODE keyblock );
+static int real_uids_left( KBNODE keyblock );
static int count_selected_keys( KBNODE keyblock );
static int menu_revsig( KBNODE keyblock );
static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int enable_disable_key( KBNODE keyblock, int disable );
+static void menu_showphoto( KBNODE keyblock );
+
+static int update_trust=0;
#define CONTROL_D ('D' - 'A' + 1)
@@ -68,41 +75,19 @@ static int enable_disable_key( KBNODE keyblock, int disable );
#define NODFLG_SIGERR (1<<2) /* other sig error */
#define NODFLG_MARK_A (1<<4) /* temporary mark */
+#define NODFLG_DELSIG (1<<5) /* to be deleted */
#define NODFLG_SELUID (1<<8) /* indicate the selected userid */
#define NODFLG_SELKEY (1<<9) /* indicate the selected key */
#define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
-
struct sign_attrib {
- int non_exportable;
+ int non_exportable,non_revocable;
struct revocation_reason_info *reason;
};
-
-
-
-static int
-get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
-{
- int rc;
-
- *keyblock = NULL;
- /* search the userid */
- rc = find_keyblock_byname( keyblock, username );
- if( rc ) {
- log_error(_("%s: user not found: %s\n"), username, gpg_errstr(rc) );
- return rc;
- }
-
- merge_keys_and_selfsig( *keyblock );
-
- return rc;
-}
-
-
/****************
- * Print information about a signature, chek it and return true
+ * Print information about a signature, check it and return true
* if the signature is okay. NODE must be a signature packet.
*/
static int
@@ -119,13 +104,14 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
sigrc = '!';
break;
- case GPGERR_BAD_SIGN:
+ case G10ERR_BAD_SIGN:
node->flag = NODFLG_BADSIG;
sigrc = '-';
if( inv_sigs )
++*inv_sigs;
break;
- case GPGERR_NO_PUBKEY:
+ case G10ERR_NO_PUBKEY:
+ case G10ERR_UNU_PUBKEY:
node->flag = NODFLG_NOKEY;
sigrc = '?';
if( no_key )
@@ -139,11 +125,18 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
break;
}
if( sigrc != '?' || print_without_key ) {
- tty_printf("%s%c %08lX %s ",
- is_rev? "rev":"sig",
- sigrc, sig->keyid[1], datestr_from_sig(sig));
+ tty_printf("%s%c%c %c%c%c%c%c %08lX %s ",
+ is_rev? "rev":"sig",sigrc,
+ (sig->sig_class-0x10>0 &&
+ sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
+ sig->flags.exportable?' ':'L',
+ sig->flags.revocable?' ':'R',
+ sig->flags.policy_url?'P':' ',
+ sig->flags.notation?'N':' ',
+ sig->flags.expired?'X':' ',
+ (ulong)sig->keyid[1], datestr_from_sig(sig));
if( sigrc == '%' )
- tty_printf("[%s] ", gpg_errstr(rc) );
+ tty_printf("[%s] ", g10_errstr(rc) );
else if( sigrc == '?' )
;
else if( *is_selfsig ) {
@@ -154,10 +147,17 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
size_t n;
char *p = get_user_id( sig->keyid, &n );
tty_print_utf8_string2( p, n, 40 );
- gcry_free(p);
+ m_free(p);
}
tty_printf("\n");
+
+ if(sig->flags.policy_url && opt.show_policy_url)
+ show_policy_url(sig,3);
+
+ if(sig->flags.notation && opt.show_notation)
+ show_notation(sig,3);
}
+
return (sigrc == '!');
}
@@ -212,7 +212,7 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
if( !has_selfsig )
mis_selfsig++;
if( inv_sigs == 1 )
- tty_printf(_("1 bad signature\n"), inv_sigs );
+ tty_printf(_("1 bad signature\n") );
else if( inv_sigs )
tty_printf(_("%d bad signatures\n"), inv_sigs );
if( no_key == 1 )
@@ -245,6 +245,12 @@ sign_mk_attrib( PKT_signature *sig, void *opaque )
buf[0] = 0; /* not exportable */
build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
}
+
+ if( attrib->non_revocable ) {
+ buf[0] = 0; /* not revocable */
+ build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
+ }
+
if( attrib->reason )
revocation_reason_build_cb( sig, attrib->reason );
@@ -259,7 +265,8 @@ sign_mk_attrib( PKT_signature *sig, void *opaque )
* if some user_ids are marked those will be signed.
*/
static int
-sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
+sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
+ int local , int nonrevocable )
{
int rc = 0;
SK_LIST sk_list = NULL;
@@ -268,18 +275,40 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
KBNODE node, uidnode;
PKT_public_key *primary_pk=NULL;
int select_all = !count_selected_uids(keyblock);
- int upd_trust = 0;
-
- /* build a list of all signators */
- rc=build_sk_list( locusr, &sk_list, 0, 1 );
+ int all_v3=1;
+
+ /* Are there any non-v3 sigs on this key already? */
+ if(opt.pgp2)
+ for(node=keyblock;node;node=node->next)
+ if(node->pkt->pkttype==PKT_SIGNATURE &&
+ node->pkt->pkt.signature->version>3)
+ {
+ all_v3=0;
+ break;
+ }
+
+ /* build a list of all signators.
+ *
+ * We use the CERT flag to request the primary which must always
+ * be one which is capable of signing keys. I can't see a reason
+ * why to sign keys using a subkey. Implementation of USAGE_CERT
+ * is just a hack in getkey.c and does not mean that a subkey
+ * marked as certification capable will be used */
+ rc=build_sk_list( locusr, &sk_list, 0, PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT);
if( rc )
goto leave;
- /* loop over all signaturs */
+ /* loop over all signators */
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
- u32 sk_keyid[2];
+ u32 sk_keyid[2],pk_keyid[2];
size_t n;
char *p;
+ int force_v4=0,class=0,selfsig=0;
+ u32 duration=0,timestamp=0;
+
+ if(local || nonrevocable ||
+ opt.cert_policy_url || opt.cert_notation_data)
+ force_v4=1;
/* we have to use a copy of the sk, because make_keysig_packet
* may remove the protection from sk and if we did other
@@ -299,18 +328,129 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
/* reset mark for uids which are already signed */
uidnode = NULL;
for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ primary_pk=node->pkt->pkt.public_key;
+ keyid_from_pk( primary_pk, pk_keyid );
+
+ /* Is this a self-sig? */
+ if(pk_keyid[0]==sk_keyid[0] && pk_keyid[1]==sk_keyid[1])
+ {
+ selfsig=1;
+ /* Do not force a v4 sig here, otherwise it would
+ be difficult to remake a v3 selfsig. If this
+ is a v3->v4 promotion case, then we set
+ force_v4 later anyway. */
+ force_v4=0;
+ }
+ }
+ else if( node->pkt->pkttype == PKT_USER_ID ) {
uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
+ if(uidnode)
+ {
+ char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
+ uidnode->pkt->pkt.user_id->len,
+ 0);
+
+ if(uidnode->pkt->pkt.user_id->is_revoked)
+ {
+ tty_printf(_("User ID \"%s\" is revoked."),user);
+
+ if(opt.expert)
+ {
+ tty_printf("\n");
+ /* No, so remove the mark and continue */
+ if(!cpr_get_answer_is_yes("sign_uid.revoke_okay",
+ _("Are you sure you "
+ "still want to sign "
+ "it? (y/N) ")))
+ uidnode->flag &= ~NODFLG_MARK_A;
+ }
+ else
+ {
+ uidnode->flag &= ~NODFLG_MARK_A;
+ tty_printf(_(" Unable to sign.\n"));
+ }
+ }
+ else if(!uidnode->pkt->pkt.user_id->created)
+ {
+ tty_printf(_("Warning: user ID \"%s\" is not "
+ "self-signed.\n"),user);
+ }
+
+ m_free(user);
+ }
}
else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
&& sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
+ char buf[50];
+ char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
+ uidnode->pkt->pkt.user_id->len,
+ 0);
+
+ /* It's a v3 self-sig. Make it into a v4 self-sig? */
+ if(node->pkt->pkt.signature->version<4 && selfsig)
+ {
+ tty_printf(_("The self-signature on \"%s\"\n"
+ "is a PGP 2.x-style signature.\n"),user);
+
+ /* Note that the regular PGP2 warning below
+ still applies if there are no v4 sigs on
+ this key at all. */
+
+ if(opt.expert)
+ if(cpr_get_answer_is_yes("sign_uid.v4_promote_okay",
+ _("Do you want to promote "
+ "it to an OpenPGP self-"
+ "signature? (y/N) ")))
+ {
+ force_v4=1;
+ node->flag|=NODFLG_DELSIG;
+ continue;
+ }
+ }
+
+ if(!node->pkt->pkt.signature->flags.exportable && !local)
+ {
+ /* It's a local sig, and we want to make a
+ exportable sig. */
+ tty_printf(_("Your current signature on \"%s\"\n"
+ "is a local signature.\n"),user);
+
+ if(cpr_get_answer_is_yes("sign_uid.local_promote_okay",
+ _("Do you want to promote "
+ "it to a full exportable "
+ "signature? (y/N) ")))
+ {
+ /* Mark these for later deletion. We
+ don't want to delete them here, just in
+ case the replacement signature doesn't
+ happen for some reason. We only delete
+ these after the replacement is already
+ in place. */
+
+ node->flag|=NODFLG_DELSIG;
+ continue;
+ }
+ }
+
/* Fixme: see whether there is a revocation in which
* case we should allow to sign it again. */
- tty_printf(_("Already signed by key %08lX\n"),
- (ulong)sk_keyid[1] );
+ if (!node->pkt->pkt.signature->flags.exportable && local)
+ tty_printf(_(
+ "\"%s\" was already locally signed by key %08lX\n"),
+ user,(ulong)sk_keyid[1] );
+ else
+ tty_printf(_(
+ "\"%s\" was already signed by key %08lX\n"),
+ user,(ulong)sk_keyid[1] );
+ sprintf (buf, "%08lX%08lX",
+ (ulong)sk->keyid[0], (ulong)sk->keyid[1] );
+ write_status_text (STATUS_ALREADY_SIGNED, buf);
uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
+
+ m_free(user);
}
}
}
@@ -322,25 +462,186 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
}
/* Ask whether we really should sign these user id(s) */
tty_printf("\n");
- show_key_with_all_names( keyblock, 1, 1, 0, 0 );
+ show_key_with_all_names( keyblock, 1, 0, 1, 0, 0 );
tty_printf("\n");
- tty_printf(_(
- "Are you really sure that you want to sign this key\n"
- "with your key: \""));
+
+ if(primary_pk->expiredate && !selfsig)
+ {
+ u32 now=make_timestamp();
+
+ if(primary_pk->expiredate<=now)
+ {
+ tty_printf(_("This key has expired!"));
+
+ if(opt.expert)
+ {
+ tty_printf(" ");
+ if(!cpr_get_answer_is_yes("sign_uid.expired_okay",
+ _("Are you sure you still "
+ "want to sign it? (y/N) ")))
+ continue;
+ }
+ else
+ {
+ tty_printf(_(" Unable to sign.\n"));
+ continue;
+ }
+ }
+ else
+ {
+ char *answer;
+
+ tty_printf(_("This key is due to expire on %s.\n"),
+ expirestr_from_pk(primary_pk));
+
+ answer=cpr_get("sign_uid.expire",
+ _("Do you want your signature to "
+ "expire at the same time? (Y/n) "));
+ if(answer_is_yes_no_default(answer,1))
+ {
+ /* This fixes the signature timestamp we're going
+ to make as now. This is so the expiration date
+ is exactly correct, and not a few seconds off
+ (due to the time it takes to answer the
+ questions, enter the passphrase, etc). */
+ timestamp=now;
+ duration=primary_pk->expiredate-now;
+ force_v4=1;
+ }
+
+ cpr_kill_prompt();
+ m_free(answer);
+ }
+ }
+
+ /* Only ask for duration if we haven't already set it to match
+ the expiration of the pk */
+ if(opt.ask_cert_expire && !duration && !selfsig)
+ duration=ask_expire_interval(1);
+
+ if(duration)
+ force_v4=1;
+
+ /* Is --pgp2 on, it's a v3 key, all the sigs on the key are
+ currently v3 and we're about to sign it with a v4 sig? If
+ so, danger! */
+ if(opt.pgp2 && all_v3 &&
+ (sk->version>3 || force_v4) && primary_pk->version<=3)
+ {
+ tty_printf(_("You may not make an OpenPGP signature on a "
+ "PGP 2.x key while in --pgp2 mode.\n"));
+ tty_printf(_("This would make the key unusable in PGP 2.x.\n"));
+
+ if(opt.expert)
+ {
+ if(!cpr_get_answer_is_yes("sign_uid.v4_on_v3_okay",
+ _("Are you sure you still "
+ "want to sign it? (y/N) ")))
+ continue;
+
+ all_v3=0;
+ }
+ else
+ continue;
+ }
+
+ if(selfsig)
+ ;
+ else if(opt.batch)
+ class=0x10+opt.def_cert_check_level;
+ else
+ {
+ char *answer;
+
+ tty_printf(_("How carefully have you verified the key you are "
+ "about to sign actually belongs\nto the person named "
+ "above? If you don't know what to answer, enter \"0\".\n"));
+ tty_printf("\n");
+ tty_printf(_(" (0) I will not answer.%s\n"),
+ opt.def_cert_check_level==0?" (default)":"");
+ tty_printf(_(" (1) I have not checked at all.%s\n"),
+ opt.def_cert_check_level==1?" (default)":"");
+ tty_printf(_(" (2) I have done casual checking.%s\n"),
+ opt.def_cert_check_level==2?" (default)":"");
+ tty_printf(_(" (3) I have done very careful checking.%s\n"),
+ opt.def_cert_check_level==3?" (default)":"");
+ tty_printf("\n");
+
+ while(class==0)
+ {
+ answer = cpr_get("sign_uid.class",_("Your selection? "));
+
+ if(answer[0]=='\0')
+ class=0x10+opt.def_cert_check_level; /* Default */
+ else if(ascii_strcasecmp(answer,"0")==0)
+ class=0x10; /* Generic */
+ else if(ascii_strcasecmp(answer,"1")==0)
+ class=0x11; /* Persona */
+ else if(ascii_strcasecmp(answer,"2")==0)
+ class=0x12; /* Casual */
+ else if(ascii_strcasecmp(answer,"3")==0)
+ class=0x13; /* Positive */
+ else
+ tty_printf(_("Invalid selection.\n"));
+
+ m_free(answer);
+ }
+ }
+
+ tty_printf(_("Are you really sure that you want to sign this key\n"
+ "with your key: \""));
p = get_user_id( sk_keyid, &n );
tty_print_utf8_string( p, n );
- gcry_free(p); p = NULL;
- tty_printf("\"\n\n");
+ m_free(p); p = NULL;
+ tty_printf("\"\n");
+
+ if(selfsig)
+ {
+ tty_printf(_("\nThis will be a self-signature.\n"));
+
+ if( local )
+ tty_printf(
+ _("\nWarning: the signature will not be marked "
+ "as non-exportable.\n"));
+
+ if( nonrevocable )
+ tty_printf(
+ _("\nWarning: the signature will not be marked "
+ "as non-revocable.\n"));
+ }
+ else
+ {
+ if( local )
+ tty_printf(
+ _("\nThe signature will be marked as non-exportable.\n"));
+
+ if( nonrevocable )
+ tty_printf(
+ _("\nThe signature will be marked as non-revocable.\n"));
+
+ switch(class)
+ {
+ case 0x11:
+ tty_printf(_("\nI have not checked this key at all.\n"));
+ break;
- if( local )
- tty_printf(
- _("The signature will be marked as non-exportable.\n\n"));
+ case 0x12:
+ tty_printf(_("\nI have checked this key casually.\n"));
+ break;
+ case 0x13:
+ tty_printf(_("\nI have checked this key very carefully.\n"));
+ break;
+ }
+ }
+
+ tty_printf("\n");
if( opt.batch && opt.answer_yes )
- ;
+ ;
else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
continue;
+
/* now we can sign the user ids */
reloop: /* (must use this, because we are modifing the list) */
primary_pk = NULL;
@@ -356,33 +657,50 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
assert( primary_pk );
memset( &attrib, 0, sizeof attrib );
attrib.non_exportable = local;
+ attrib.non_revocable = nonrevocable;
node->flag &= ~NODFLG_MARK_A;
- rc = make_keysig_packet( &sig, primary_pk,
- node->pkt->pkt.user_id,
- NULL,
- sk,
- 0x10, 0,
- sign_mk_attrib,
- &attrib );
+
+ /* we force creation of a v4 signature for local
+ * signatures, otherwise we would not generate the
+ * subpacket with v3 keys and the signature becomes
+ * exportable */
+
+ if(selfsig)
+ rc = make_keysig_packet( &sig, primary_pk,
+ node->pkt->pkt.user_id,
+ NULL,
+ sk,
+ 0x13, 0, force_v4?4:0, 0, 0,
+ keygen_add_std_prefs, primary_pk);
+ else
+ rc = make_keysig_packet( &sig, primary_pk,
+ node->pkt->pkt.user_id,
+ NULL,
+ sk,
+ class, 0, force_v4?4:0,
+ timestamp, duration,
+ sign_mk_attrib, &attrib );
if( rc ) {
- log_error(_("signing failed: %s\n"), gpg_errstr(rc));
+ log_error(_("signing failed: %s\n"), g10_errstr(rc));
goto leave;
}
+
*ret_modified = 1; /* we changed the keyblock */
- upd_trust = 1;
+ update_trust = 1;
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
goto reloop;
}
}
- } /* end loop over signators */
- if( upd_trust && primary_pk ) {
- rc = clear_trust_checked_flag( primary_pk );
- }
+ /* Delete any sigs that got promoted */
+ for( node=keyblock; node; node = node->next )
+ if( node->flag & NODFLG_DELSIG)
+ delete_kbnode(node);
+ } /* end loop over signators */
leave:
release_sk_list( sk_list );
@@ -416,7 +734,7 @@ change_passphrase( KBNODE keyblock )
switch( is_secret_key_protected( sk ) ) {
case -1:
- rc = GPGERR_PUBKEY_ALGO;
+ rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf(_("This key is not protected.\n"));
@@ -447,10 +765,11 @@ change_passphrase( KBNODE keyblock )
}
if( rc )
- tty_printf(_("Can't edit this key: %s\n"), gpg_errstr(rc));
+ tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
else {
DEK *dek = NULL;
- STRING2KEY *s2k = gcry_xmalloc_secure( sizeof *s2k );
+ STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
+ const char *errtext = NULL;
tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
@@ -458,9 +777,11 @@ change_passphrase( KBNODE keyblock )
for(;;) {
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo,
+ s2k, 2, errtext);
if( !dek ) {
- tty_printf(_("passphrase not correctly repeated; try again.\n"));
+ errtext = _("passphrase not correctly repeated; try again");
+ tty_printf ("%s.\n", errtext);
}
else if( !dek->keylen ) {
rc = 0;
@@ -487,18 +808,18 @@ change_passphrase( KBNODE keyblock )
}
}
if( rc )
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
else
changed++;
break;
}
}
- gcry_free(s2k);
- gcry_free(dek);
+ m_free(s2k);
+ m_free(dek);
}
leave:
- gcry_free( passphrase );
+ m_free( passphrase );
set_next_passphrase( NULL );
return changed && !rc;
}
@@ -560,11 +881,12 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
{
enum cmdids { cmdNONE = 0,
cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
- cmdLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
- cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
- cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
- cmdENABLEKEY, cmdDISABLEKEY,
- cmdINVCMD, cmdNOP };
+ cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
+ cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID,
+ cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY,
+ cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdENABLEKEY,
+ cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdINVCMD,
+ cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdNOP };
static struct { const char *name;
enum cmdids id;
int need_sk;
@@ -587,30 +909,42 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
{ N_("sign") , cmdSIGN , 0,1,1, N_("sign the key") },
{ N_("s") , cmdSIGN , 0,1,1, NULL },
{ N_("lsign") , cmdLSIGN , 0,1,1, N_("sign the key locally") },
+ { N_("nrsign") , cmdNRSIGN , 0,1,1, N_("sign the key non-revocably") },
+ { N_("nrlsign") , cmdNRLSIGN , 0,1,1, N_("sign the key locally and non-revocably") },
{ N_("debug") , cmdDEBUG , 0,0,0, NULL },
{ N_("adduid") , cmdADDUID , 1,1,0, N_("add a user ID") },
+ { N_("addphoto"), cmdADDPHOTO , 1,1,0, N_("add a photo ID") },
{ N_("deluid") , cmdDELUID , 0,1,0, N_("delete user ID") },
+ /* delphoto is really deluid in disguise */
+ { N_("delphoto"), cmdDELUID , 0,1,0, NULL },
{ N_("addkey") , cmdADDKEY , 1,1,0, N_("add a secondary key") },
{ N_("delkey") , cmdDELKEY , 0,1,0, N_("delete a secondary key") },
+ { N_("addrevoker"),cmdADDREVOKER,1,1,0, N_("add a revocation key") },
{ N_("delsig") , cmdDELSIG , 0,1,0, N_("delete signatures") },
{ N_("expire") , cmdEXPIRE , 1,1,0, N_("change the expire date") },
+ { N_("primary") , cmdPRIMARY , 1,1,0, N_("flag user ID as primary")},
{ N_("toggle") , cmdTOGGLE , 1,0,0, N_("toggle between secret "
"and public key listing") },
{ N_("t" ) , cmdTOGGLE , 1,0,0, NULL },
- { N_("pref") , cmdPREF , 0,1,0, N_("list preferences") },
+ { N_("pref") , cmdPREF , 0,1,0, N_("list preferences (expert)") },
+ { N_("showpref"), cmdSHOWPREF , 0,1,0, N_("list preferences (verbose)") },
+ { N_("setpref") , cmdSETPREF , 1,1,0, N_("set preference list") },
+ { N_("updpref") , cmdUPDPREF , 1,1,0, N_("updated preferences") },
{ N_("passwd") , cmdPASSWD , 1,1,0, N_("change the passphrase") },
{ N_("trust") , cmdTRUST , 0,1,0, N_("change the ownertrust") },
{ N_("revsig") , cmdREVSIG , 0,1,0, N_("revoke signatures") },
{ N_("revkey") , cmdREVKEY , 1,1,0, N_("revoke a secondary key") },
{ N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
{ N_("enable") , cmdENABLEKEY , 0,1,0, N_("enable a key") },
+ { N_("showphoto"),cmdSHOWPHOTO , 0,0,0, N_("show photo ID") },
{ NULL, cmdNONE } };
enum cmdids cmd = 0;
int rc = 0;
KBNODE keyblock = NULL;
- KBPOS keyblockpos;
+ KEYDB_HANDLE kdbhd = NULL;
KBNODE sec_keyblock = NULL;
+ KEYDB_HANDLE sec_kdbhd = NULL;
KBNODE cur_keyblock;
char *answer = NULL;
int redisplay = 1;
@@ -619,34 +953,23 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
int toggle;
int have_commands = !!commands;
-
- if( opt.batch && !have_commands ) {
+ if ( opt.command_fd != -1 )
+ ;
+ else if( opt.batch && !have_commands ) {
log_error(_("can't do that in batchmode\n"));
goto leave;
}
if( sign_mode ) {
commands = NULL;
- append_to_strlist( &commands, sign_mode == 1? "sign":"lsign" );
+ append_to_strlist( &commands, sign_mode == 1? "sign":
+ sign_mode == 2?"lsign":
+ sign_mode == 3?"nrsign":"nrlsign");
have_commands = 1;
}
-
- if( !sign_mode ) {
- /* first try to locate it as secret key */
- rc = find_secret_keyblock_byname( &sec_keyblock, username );
- if( rc && rc != GPGERR_NO_SECKEY )
- log_debug("%s: secret keyblock read problem: %s\n",
- username, gpg_errstr(rc));
- if( !rc ) {
- merge_keys_and_selfsig( sec_keyblock );
- if( fix_keyblock( sec_keyblock ) )
- sec_modified++;
- }
- }
-
- /* and now get the public key */
- rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
+ /* get the public key */
+ rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd);
if( rc )
goto leave;
if( fix_keyblock( keyblock ) )
@@ -654,44 +977,79 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
if( collapse_uids( &keyblock ) )
modified++;
- if( sec_keyblock ) { /* check that they match */
- /* fixme: check that they both match */
+ if( !sign_mode ) {/* see whether we have a matching secret key */
+ PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+
+ sec_kdbhd = keydb_new (1);
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < MAX_FINGERPRINT_LEN)
+ afp[an++] = 0;
+ rc = keydb_search_fpr (sec_kdbhd, afp);
+ }
+ if (!rc) {
+ rc = keydb_get_keyblock (sec_kdbhd, &sec_keyblock);
+ if (rc) {
+ log_error (_("error reading secret keyblock `%s': %s\n"),
+ username, g10_errstr(rc));
+ }
+ else {
+ merge_keys_and_selfsig( sec_keyblock );
+ if( fix_keyblock( sec_keyblock ) )
+ sec_modified++;
+ }
+ }
+
+ if (rc) {
+ sec_keyblock = NULL;
+ keydb_release (sec_kdbhd); sec_kdbhd = NULL;
+ rc = 0;
+ }
+ }
+
+ if( sec_keyblock ) {
tty_printf(_("Secret key is available.\n"));
}
toggle = 0;
cur_keyblock = keyblock;
for(;;) { /* main loop */
- int i, arg_number;
+ int i, arg_number, photo;
+ const char *arg_string = "";
char *p;
+ PKT_public_key *pk=keyblock->pkt->pkt.public_key;
tty_printf("\n");
if( redisplay ) {
- show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
+ show_key_with_all_names( cur_keyblock, 0, 1, 0, 1, 0 );
tty_printf("\n");
redisplay = 0;
}
do {
- gcry_free(answer);
+ m_free(answer);
if( have_commands ) {
if( commands ) {
- answer = gcry_xstrdup( commands->d );
+ answer = m_strdup( commands->d );
commands = commands->next;
}
else if( opt.batch ) {
- answer = gcry_xstrdup("quit");
+ answer = m_strdup("quit");
}
else
have_commands = 0;
}
if( !have_commands ) {
- answer = cpr_get("keyedit.prompt", _("Command> "));
+ answer = cpr_get_no_help("keyedit.prompt", _("Command> "));
cpr_kill_prompt();
}
trim_spaces(answer);
} while( *answer == '#' );
- arg_number = 0; /* Yes, here is the init which egcc complains about*/
+ arg_number = 0; /* Yes, here is the init which egcc complains about */
+ photo = 0; /* This too */
if( !*answer )
cmd = cmdLIST;
else if( *answer == CONTROL_D )
@@ -706,10 +1064,11 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
trim_spaces(answer);
trim_spaces(p);
arg_number = atoi(p);
+ arg_string = p;
}
for(i=0; cmds[i].name; i++ ) {
- if( !stricmp( answer, cmds[i].name ) )
+ if( !ascii_strcasecmp( answer, cmds[i].name ) )
break;
}
if( sign_mode && !cmds[i].signmode )
@@ -764,6 +1123,27 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
case cmdSIGN: /* sign (only the public key) */
case cmdLSIGN: /* sign (only the public key) */
+ case cmdNRSIGN: /* sign (only the public key) */
+ case cmdNRLSIGN: /* sign (only the public key) */
+ if( pk->is_revoked )
+ {
+ tty_printf(_("Key is revoked."));
+
+ if(opt.expert)
+ {
+ tty_printf(" ");
+ if(!cpr_get_answer_is_yes("keyedit.sign_revoked.okay",
+ _("Are you sure you still want "
+ "to sign it? (y/N) ")))
+ break;
+ }
+ else
+ {
+ tty_printf(_(" Unable to sign.\n"));
+ break;
+ }
+ }
+
if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
_("Really sign all user IDs? ")) ) {
@@ -771,14 +1151,11 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
break;
}
}
- if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN )
+ if( !sign_uids( keyblock, locusr, &modified,
+ (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN),
+ (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN))
&& sign_mode )
- goto do_cmd_save;
- /* Actually we should do a update_trust_record() here so that
- * the trust gets displayed correctly. however this is not possible
- * because we would have to save the keyblock first - something
- * we don't want to do without an explicit save command.
- */
+ goto do_cmd_save;
break;
case cmdDEBUG:
@@ -791,18 +1168,23 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
redisplay = 1;
break;
+ case cmdADDPHOTO:
+ if (opt.rfc2440 || opt.rfc1991 || opt.pgp2)
+ {
+ tty_printf(
+ _("This command is not allowed while in %s mode.\n"),
+ opt.rfc2440?"OpenPGP":opt.pgp2?"PGP2":"RFC-1991");
+ break;
+ }
+ photo=1;
+ /* fall through */
+
case cmdADDUID:
- if( menu_adduid( keyblock, sec_keyblock ) ) {
+ if( menu_adduid( keyblock, sec_keyblock, photo ) ) {
redisplay = 1;
sec_modified = modified = 1;
- /* must update the trustdb already here, so that preferences
- * get listed correctly */
- rc = update_trust_record( keyblock, 0, NULL );
- if( rc ) {
- log_error(_("update of trustdb failed: %s\n"),
- gpg_errstr(rc) );
- rc = 0;
- }
+ merge_keys_and_selfsig( sec_keyblock );
+ merge_keys_and_selfsig( keyblock );
}
break;
@@ -811,7 +1193,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
if( !(n1=count_selected_uids(keyblock)) )
tty_printf(_("You must select at least one user ID.\n"));
- else if( count_uids(keyblock) - n1 < 1 )
+ else if( real_uids_left(keyblock) < 1 )
tty_printf(_("You can't delete the last user ID!\n"));
else if( cpr_get_answer_is_yes(
"keyedit.remove.uid.okay",
@@ -844,6 +1226,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
if( generate_subkeypair( keyblock, sec_keyblock ) ) {
redisplay = 1;
sec_modified = modified = 1;
+ merge_keys_and_selfsig( sec_keyblock );
+ merge_keys_and_selfsig( keyblock );
}
break;
@@ -870,6 +1254,15 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
}
break;
+ case cmdADDREVOKER:
+ if( menu_addrevoker( keyblock, sec_keyblock ) ) {
+ redisplay = 1;
+ sec_modified = modified = 1;
+ merge_keys_and_selfsig( sec_keyblock );
+ merge_keys_and_selfsig( keyblock );
+ }
+ break;
+
case cmdREVKEY: {
int n1;
@@ -902,23 +1295,62 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
}
break;
+ case cmdPRIMARY:
+ if( menu_set_primary_uid ( keyblock, sec_keyblock ) ) {
+ merge_keys_and_selfsig( keyblock );
+ modified = 1;
+ redisplay = 1;
+ }
+ break;
+
case cmdPASSWD:
if( change_passphrase( sec_keyblock ) )
sec_modified = 1;
break;
case cmdTRUST:
- show_key_with_all_names( keyblock, 0, 0, 1, 0 );
+ show_key_with_all_names( keyblock, 0, 0, 0, 1, 0 );
tty_printf("\n");
if( edit_ownertrust( find_kbnode( keyblock,
- PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
+ PKT_PUBLIC_KEY )->pkt->pkt.public_key, 1 ) ) {
redisplay = 1;
- /* we don't need to set modified here, as the trustvalues
- * are updated immediately */
+ /* No real need to set update_trust here as
+ edit_ownertrust() calls revalidation_mark()
+ anyway. */
+ update_trust=1;
+ }
break;
case cmdPREF:
- show_key_with_all_names( keyblock, 0, 0, 0, 1 );
+ show_key_with_all_names( keyblock, 0, 0, 0, 0, 1 );
+ break;
+
+ case cmdSHOWPREF:
+ show_key_with_all_names( keyblock, 0, 0, 0, 0, 2 );
+ break;
+
+ case cmdSETPREF:
+ keygen_set_std_prefs ( !*arg_string? "default" : arg_string, 0);
+ break;
+
+ case cmdUPDPREF:
+ {
+ p = keygen_get_std_prefs ();
+ tty_printf (("Current preference list: %s\n"), p);
+ m_free (p);
+ }
+ if (cpr_get_answer_is_yes ("keyedit.updpref.okay",
+ count_selected_uids (keyblock)?
+ _("Really update the preferences"
+ " for the selected user IDs? "):
+ _("Really update the preferences? "))){
+
+ if ( menu_set_preferences (keyblock, sec_keyblock) ) {
+ merge_keys_and_selfsig (keyblock);
+ modified = 1;
+ redisplay = 1;
+ }
+ }
break;
case cmdNOP:
@@ -939,6 +1371,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
}
break;
+ case cmdSHOWPHOTO:
+ menu_showphoto(keyblock);
+ break;
+
case cmdQUIT:
if( have_commands )
goto leave;
@@ -957,32 +1393,29 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
do_cmd_save:
if( modified || sec_modified ) {
if( modified ) {
- rc = update_keyblock( keyblock );
+ rc = keydb_update_keyblock (kdbhd, keyblock);
if( rc ) {
- log_error(_("update failed: %s\n"), gpg_errstr(rc) );
+ log_error(_("update failed: %s\n"), g10_errstr(rc) );
break;
}
}
if( sec_modified ) {
- rc = update_keyblock( sec_keyblock );
+ rc = keydb_update_keyblock (sec_kdbhd, sec_keyblock );
if( rc ) {
- log_error(_("update secret failed: %s\n"),
- gpg_errstr(rc) );
+ log_error( _("update secret failed: %s\n"),
+ g10_errstr(rc) );
break;
}
}
}
else
tty_printf(_("Key not changed so no update needed.\n"));
- /* TODO: we should keep track whether we have changed
- * something relevant to the trustdb */
- if( !modified && sign_mode )
- rc = 0; /* we can skip at least in this case */
- else
- rc = update_trust_record( keyblock, 0, NULL );
- if( rc )
- log_error(_("update of trustdb failed: %s\n"),
- gpg_errstr(rc) );
+
+ if( update_trust )
+ {
+ revalidation_mark ();
+ update_trust=0;
+ }
goto leave;
case cmdINVCMD:
@@ -996,7 +1429,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
leave:
release_kbnode( keyblock );
release_kbnode( sec_keyblock );
- gcry_free(answer);
+ keydb_release (kdbhd);
+ m_free(answer);
}
@@ -1004,45 +1438,246 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
* show preferences of a public keyblock.
*/
static void
-show_prefs( KBNODE keyblock, PKT_user_id *uid )
+show_prefs (PKT_user_id *uid, int verbose)
{
- KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- PKT_public_key *pk;
- byte *p;
+ const prefitem_t fake={0,0};
+ const prefitem_t *prefs;
int i;
- size_t n;
- byte namehash[20];
-
- if( !node )
- return; /* is a secret keyblock */
- pk = node->pkt->pkt.public_key;
- if( !pk->local_id ) {
- log_error("oops: no LID\n");
- return;
- }
- if( uid->photo ) {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->photo,
- uid->photolen );
+ if( !uid )
+ return;
+
+ if( uid->prefs )
+ prefs=uid->prefs;
+ else if(verbose)
+ prefs=&fake;
+ else
+ return;
+
+ if (verbose) {
+ int any, des_seen=0, sha1_seen=0, uncomp_seen=0;
+ tty_printf (" Cipher: ");
+ for(i=any=0; prefs[i].type; i++ ) {
+ if( prefs[i].type == PREFTYPE_SYM ) {
+ const char *s = cipher_algo_to_string (prefs[i].value);
+
+ if (any)
+ tty_printf (", ");
+ any = 1;
+ /* We don't want to display strings for experimental algos */
+ if (s && prefs[i].value < 100 )
+ tty_printf ("%s", s );
+ else
+ tty_printf ("[%d]", prefs[i].value);
+ if (prefs[i].value == CIPHER_ALGO_3DES )
+ des_seen = 1;
+ }
+ }
+ if (!des_seen) {
+ if (any)
+ tty_printf (", ");
+ tty_printf ("%s",cipher_algo_to_string(CIPHER_ALGO_3DES));
+ }
+ tty_printf ("\n Hash: ");
+ for(i=any=0; prefs[i].type; i++ ) {
+ if( prefs[i].type == PREFTYPE_HASH ) {
+ const char *s = digest_algo_to_string (prefs[i].value);
+
+ if (any)
+ tty_printf (", ");
+ any = 1;
+ /* We don't want to display strings for experimental algos */
+ if (s && prefs[i].value < 100 )
+ tty_printf ("%s", s );
+ else
+ tty_printf ("[%d]", prefs[i].value);
+ if (prefs[i].value == DIGEST_ALGO_SHA1 )
+ sha1_seen = 1;
+ }
+ }
+ if (!sha1_seen) {
+ if (any)
+ tty_printf (", ");
+ tty_printf ("%s",digest_algo_to_string(DIGEST_ALGO_SHA1));
+ }
+ tty_printf ("\n Compression: ");
+ for(i=any=0; prefs[i].type; i++ ) {
+ if( prefs[i].type == PREFTYPE_ZIP ) {
+ const char *s=compress_algo_to_string(prefs[i].value);
+
+ if (any)
+ tty_printf (", ");
+ any = 1;
+ /* We don't want to display strings for experimental algos */
+ if (s && prefs[i].value < 100 )
+ tty_printf ("%s", s );
+ else
+ tty_printf ("[%d]", prefs[i].value);
+ if (prefs[i].value == 0 )
+ uncomp_seen = 1;
+ }
+ }
+ if (!uncomp_seen) {
+ if (any)
+ tty_printf (", ");
+ else {
+ tty_printf ("%s",compress_algo_to_string(1));
+ tty_printf (", ");
+ }
+ tty_printf ("%s",compress_algo_to_string(0));
+ }
+ tty_printf ("\n Features: ");
+ if(uid->mdc_feature)
+ tty_printf ("MDC");
+ tty_printf("\n");
}
else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->name, uid->len );
+ tty_printf(" ");
+ for(i=0; prefs[i].type; i++ ) {
+ tty_printf( " %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+ prefs[i].type == PREFTYPE_HASH ? 'H' :
+ prefs[i].type == PREFTYPE_ZIP ? 'Z':'?',
+ prefs[i].value);
+ }
+ if (uid->mdc_feature)
+ tty_printf (" [mdc]");
+ tty_printf("\n");
}
+}
- p = get_pref_data( pk->local_id, namehash, &n );
- if( !p )
- return;
- tty_printf(" ");
- for(i=0; i < n; i+=2 ) {
- if( p[i] )
- tty_printf( " %c%d", p[i] == PREFTYPE_SYM ? 'S' :
- p[i] == PREFTYPE_HASH ? 'H' :
- p[i] == PREFTYPE_COMPR ? 'Z' : '?', p[i+1]);
+/* This is the version of show_key_with_all_names used when
+ opt.with_colons is used. It prints all available data in a easy to
+ parse format and does not translate utf8 */
+static void
+show_key_with_all_names_colon (KBNODE keyblock)
+{
+ KBNODE node;
+ int i, j;
+ byte pk_version=0;
+
+ /* the keys */
+ for ( node = keyblock; node; node = node->next )
+ {
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) )
+ {
+ PKT_public_key *pk = node->pkt->pkt.public_key;
+ int otrust=0, trust=0;
+ u32 keyid[2];
+
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ trust = get_validity_info (pk, NULL);
+ otrust = get_ownertrust_info (pk);
+ pk_version = pk->version;
+ }
+
+ keyid_from_pk (pk, keyid);
+
+ fputs (node->pkt->pkttype == PKT_PUBLIC_KEY?"pub:":"sub:", stdout);
+ if (!pk->is_valid)
+ putchar ('i');
+ else if (pk->is_revoked)
+ putchar ('r');
+ else if (pk->has_expired)
+ putchar ('e');
+ else
+ putchar (trust);
+ printf (":%u:%d:%08lX%08lX:%lu:%lu:",
+ nbits_from_pk (pk),
+ pk->pubkey_algo,
+ (ulong)keyid[0], (ulong)keyid[1],
+ (ulong)pk->timestamp,
+ (ulong)pk->expiredate );
+ if (pk->local_id)
+ printf ("%lu", pk->local_id);
+ putchar (':');
+ putchar (otrust);
+ putchar(':');
+ putchar('\n');
+
+ print_fingerprint (pk, NULL, 0);
+
+ /* print the revoker record */
+ if( !pk->revkey && pk->numrevkeys )
+ BUG();
+ else
+ {
+ for (i=0; i < pk->numrevkeys; i++)
+ {
+ byte *p;
+
+ printf ("rvk:::%d::::::", pk->revkey[i].algid);
+ p = pk->revkey[i].fpr;
+ for (j=0; j < 20; j++, p++ )
+ printf ("%02X", *p);
+ printf (":%02x%c:\n", pk->revkey[i].class,
+ (pk->revkey[i].class&0x40)? 'l':'x');
+ }
+ }
+ }
}
- tty_printf("\n");
+
+ /* the user ids */
+ i = 0;
+ for (node = keyblock; node; node = node->next)
+ {
+ if ( node->pkt->pkttype == PKT_USER_ID )
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ int trustletter = '?';
- gcry_free(p);
+ ++i;
+ if(uid->attrib_data)
+ {
+ printf ("uat:%c::::::::%u %lu", trustletter,
+ uid->numattribs,uid->attrib_len);
+ }
+ else
+ {
+ printf ("uid:%c::::::::", trustletter);
+ print_string (stdout, uid->name, uid->len, ':');
+ }
+ putchar (':');
+ /* signature class */
+ putchar (':');
+ /* capabilities */
+ putchar (':');
+ /* preferences */
+ if (pk_version>3 || uid->selfsigversion>3)
+ {
+ const prefitem_t *prefs = uid->prefs;
+
+ for (j=0; prefs && prefs[j].type; j++)
+ {
+ if (j)
+ putchar (' ');
+ printf ("%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' :
+ prefs[j].type == PREFTYPE_HASH ? 'H' :
+ prefs[j].type == PREFTYPE_ZIP ? 'Z':'?',
+ prefs[j].value);
+ }
+ if (uid->mdc_feature)
+ printf (",mdc");
+ }
+ putchar (':');
+ /* flags */
+ printf ("%d,", i);
+ if (uid->is_primary)
+ putchar ('p');
+ if (uid->is_revoked)
+ putchar ('r');
+ if (uid->is_expired)
+ putchar ('e');
+ if ((node->flag & NODFLG_SELUID))
+ putchar ('s');
+ if ((node->flag & NODFLG_MARK_A))
+ putchar ('m');
+ putchar (':');
+ putchar('\n');
+ }
+ }
}
@@ -1051,11 +1686,19 @@ show_prefs( KBNODE keyblock, PKT_user_id *uid )
* so for user ids with mark A flag set and dont display the index number
*/
static void
-show_key_with_all_names( KBNODE keyblock, int only_marked,
+show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
int with_fpr, int with_subkeys, int with_prefs )
{
KBNODE node;
int i, rc;
+ int do_warn = 0;
+ byte pk_version=0;
+
+ if (opt.with_colons)
+ {
+ show_key_with_all_names_colon (keyblock);
+ return;
+ }
/* the keys */
for( node = keyblock; node; node = node->next ) {
@@ -1067,10 +1710,43 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
/* do it here, so that debug messages don't clutter the
* output */
- trust = query_trust_info(pk, NULL);
- otrust = get_ownertrust_info( pk->local_id );
+ static int did_warn = 0;
+
+ trust = get_validity_info (pk, NULL);
+ otrust = get_ownertrust_info (pk);
+
+ /* Show a warning once */
+ if (!did_warn
+ && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK)) {
+ did_warn = 1;
+ do_warn = 1;
+ }
+
+ pk_version=pk->version;
}
+ if(with_revoker) {
+ if( !pk->revkey && pk->numrevkeys )
+ BUG();
+ else
+ for(i=0;i<pk->numrevkeys;i++) {
+ u32 r_keyid[2];
+ char *user;
+
+ keyid_from_fingerprint(pk->revkey[i].fpr,
+ MAX_FINGERPRINT_LEN,r_keyid);
+
+ user=get_user_id_string (r_keyid);
+ tty_printf (_("This key may be revoked by %s key "),
+ pubkey_algo_to_string (pk->revkey[i].algid));
+ tty_print_utf8_string (user, strlen (user));
+ if ((pk->revkey[i].class&0x40))
+ tty_printf (_(" (sensitive)"));
+ tty_printf ("\n");
+ m_free(user);
+ }
+ }
+
tty_printf(_("%s%c %4u%c/%08lX created: %s expires: %s"),
node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
(node->flag & NODFLG_SELKEY)? '*':' ',
@@ -1082,14 +1758,14 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
tty_printf(_(" trust: %c/%c"), otrust, trust );
if( node->pkt->pkttype == PKT_PUBLIC_KEY
- && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) {
+ && (get_ownertrust (pk)&TRUST_FLAG_DISABLED)) {
tty_printf("\n*** ");
tty_printf(_("This key has been disabled"));
}
if( with_fpr ) {
tty_printf("\n");
- show_fingerprint( pk );
+ print_fingerprint ( pk, NULL, 2 );
}
}
tty_printf("\n");
@@ -1115,11 +1791,11 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
if( !rc )
tty_printf( _("rev! subkey has been revoked: %s\n"),
datestr_from_sig( sig ) );
- else if( rc == GPGERR_BAD_SIGN )
+ else if( rc == G10ERR_BAD_SIGN )
tty_printf( _("rev- faked revocation found\n") );
else if( rc )
tty_printf( _("rev? problem checking revocation: %s\n"),
- gpg_errstr(rc) );
+ g10_errstr(rc) );
}
}
/* the user ids */
@@ -1133,15 +1809,33 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
tty_printf(" ");
else if( node->flag & NODFLG_SELUID )
tty_printf("(%d)* ", i);
+ else if( uid->is_primary )
+ tty_printf("(%d). ", i);
else
tty_printf("(%d) ", i);
+ if ( uid->is_revoked )
+ tty_printf ("[revoked] ");
+ if ( uid->is_expired )
+ tty_printf ("[expired] ");
tty_print_utf8_string( uid->name, uid->len );
tty_printf("\n");
if( with_prefs )
- show_prefs( keyblock, uid );
+ {
+ if(pk_version>3 || uid->selfsigversion>3)
+ show_prefs (uid, with_prefs == 2);
+ else
+ tty_printf(_("There are no preferences on a "
+ "PGP 2.x-style key.\n"));
+ }
}
}
}
+
+ if (do_warn)
+ tty_printf (_("Please note that the shown key validity "
+ "is not necessarily correct\n"
+ "unless you restart the program.\n"));
+
}
static void
@@ -1167,44 +1861,18 @@ show_key_and_fingerprint( KBNODE keyblock )
}
tty_printf("\n");
if( pk )
- show_fingerprint( pk );
+ print_fingerprint( pk, NULL, 2 );
}
-static void
-show_fingerprint( PKT_public_key *pk )
-{
- byte array[MAX_FINGERPRINT_LEN], *p;
- size_t i, n;
-
- fingerprint_from_pk( pk, array, &n );
- p = array;
- tty_printf(_(" Fingerprint:"));
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- tty_printf(" ");
- tty_printf(" %02X%02X", *p, p[1] );
- }
- }
- else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- tty_printf(" ");
- tty_printf(" %02X", *p );
- }
- }
- tty_printf("\n");
-}
-
/****************
- * Ask for a new user id , do the selfsignature and put it into
+ * Ask for a new user id, do the selfsignature and put it into
* both keyblocks.
* Return true if there is a new user id
*/
static int
-menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
+menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
{
PKT_user_id *uid;
PKT_public_key *pk=NULL;
@@ -1215,10 +1883,6 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
KBNODE pub_where=NULL, sec_where=NULL;
int rc;
- uid = generate_user_id();
- if( !uid )
- return 0;
-
for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
if( node->pkt->pkttype == PKT_PUBLIC_KEY )
pk = node->pkt->pkt.public_key;
@@ -1235,27 +1899,69 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
}
if( !node ) /* no subkey */
sec_where = NULL;
- assert(pk && sk );
+ assert(pk && sk);
+
+ if(photo) {
+ int hasattrib=0;
+
+ for( node = pub_keyblock; node; node = node->next )
+ if( node->pkt->pkttype == PKT_USER_ID &&
+ node->pkt->pkt.user_id->attrib_data!=NULL)
+ {
+ hasattrib=1;
+ break;
+ }
+
+ /* It is legal but bad for compatibility to add a photo ID to a
+ v3 key as it means that PGP2 will not be able to use that key
+ anymore. Don't bother to ask this if the key already has a
+ photo - any damage has already been done at that point. -dms */
+ if(pk->version==3 && !hasattrib)
+ {
+ if(opt.expert)
+ {
+ tty_printf(_("WARNING: This is a PGP2-style key. "
+ "Adding a photo ID may cause some versions\n"
+ " of PGP to reject this key.\n"));
+
+ if(!cpr_get_answer_is_yes("keyedit.v3_photo.okay",
+ _("Are you sure you still want "
+ "to add it? (y/N) ")))
+ return 0;
+ }
+ else
+ {
+ tty_printf(_("You may not add a photo ID to "
+ "a PGP2-style key.\n"));
+ return 0;
+ }
+ }
- rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
+ uid = generate_photo_id(pk);
+ } else
+ uid = generate_user_id();
+ if( !uid )
+ return 0;
+
+ rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
keygen_add_std_prefs, pk );
free_secret_key( sk );
if( rc ) {
- log_error("signing failed: %s\n", gpg_errstr(rc) );
+ log_error("signing failed: %s\n", g10_errstr(rc) );
free_user_id(uid);
return 0;
}
/* insert/append to secret keyblock */
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_USER_ID;
- pkt->pkt.user_id = copy_user_id(NULL, uid);
+ pkt->pkt.user_id = scopy_user_id(uid);
node = new_kbnode(pkt);
if( sec_where )
insert_kbnode( sec_where, node, 0 );
else
add_kbnode( sec_keyblock, node );
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = copy_signature(NULL, sig);
if( sec_where )
@@ -1263,7 +1969,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
else
add_kbnode( sec_keyblock, new_kbnode(pkt) );
/* insert/append to public keyblock */
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_USER_ID;
pkt->pkt.user_id = uid;
node = new_kbnode(pkt);
@@ -1271,7 +1977,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
insert_kbnode( pub_where, node, 0 );
else
add_kbnode( pub_keyblock, node );
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = copy_signature(NULL, sig);
if( pub_where )
@@ -1295,6 +2001,10 @@ menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
if( node->pkt->pkttype == PKT_USER_ID ) {
selected = node->flag & NODFLG_SELUID;
if( selected ) {
+ /* Only cause a trust update if we delete a
+ non-revoked user id */
+ if(!node->pkt->pkt.user_id->is_revoked)
+ update_trust=1;
delete_kbnode( node );
if( sec_keyblock ) {
KBNODE snode;
@@ -1353,10 +2063,16 @@ menu_delsig( KBNODE pub_keyblock )
&inv_sig, &no_key, &other_err,
&selfsig, 1 );
- if( valid )
+ if( valid ) {
okay = cpr_get_answer_yes_no_quit(
"keyedit.delsig.valid",
_("Delete this good signature? (y/N/q)"));
+
+ /* Only update trust if we delete a good signature.
+ The other two cases do not affect trust. */
+ if(okay)
+ update_trust=1;
+ }
else if( inv_sig || other_err )
okay = cpr_get_answer_yes_no_quit(
"keyedit.delsig.invalid",
@@ -1440,9 +2156,147 @@ menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
commit_kbnode( &pub_keyblock );
if( sec_keyblock )
commit_kbnode( &sec_keyblock );
+
+ /* No need to set update_trust here since signing keys no longer
+ are used to certify other keys, so there is no change in trust
+ when revoking/removing them */
}
+/****************
+ * Ask for a new revoker, do the selfsignature and put it into
+ * both keyblocks.
+ * Return true if there is a new revoker
+ */
+static int
+menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ PKT_public_key *pk=NULL,*revoker_pk=NULL;
+ PKT_secret_key *sk=NULL;
+ PKT_signature *sig=NULL;
+ PACKET *pkt;
+ struct revocation_key revkey;
+ size_t fprlen;
+ int rc;
+
+ assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+ assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
+
+ pk=pub_keyblock->pkt->pkt.public_key;
+ sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
+
+ for(;;)
+ {
+ char *answer;
+ u32 keyid[2];
+ char *p;
+ size_t n;
+
+ if(revoker_pk)
+ free_public_key(revoker_pk);
+
+ revoker_pk=m_alloc_clear(sizeof(*revoker_pk));
+
+ tty_printf("\n");
+
+ answer=cpr_get_utf8("keyedit.add_revoker",
+ _("Enter the user ID of the designated revoker: "));
+ if(answer[0]=='\0' || answer[0]=='\004')
+ goto fail;
+
+ rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL);
+
+ if(rc)
+ {
+ log_error (_("key `%s' not found: %s\n"),answer,g10_errstr(rc));
+ continue;
+ }
+
+ fingerprint_from_pk(revoker_pk,revkey.fpr,&fprlen);
+ if(fprlen!=20)
+ {
+ log_error(_("cannot appoint a PGP 2.x style key as a "
+ "designated revoker\n"));
+ continue;
+ }
+
+ if(cmp_public_keys(revoker_pk,pk)==0)
+ {
+ /* This actually causes no harm (after all, a key that
+ designates itself as a revoker is the same as a
+ regular key), but it's easy enough to check. */
+ log_error(_("you cannot appoint a key as its own "
+ "designated revoker\n"));
+ continue;
+ }
+
+ keyid_from_pk(revoker_pk,keyid);
+
+ tty_printf("\npub %4u%c/%08lX %s ",
+ nbits_from_pk( revoker_pk ),
+ pubkey_letter( revoker_pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk(pk) );
+
+ p = get_user_id( keyid, &n );
+ tty_print_utf8_string( p, n );
+ m_free(p);
+ tty_printf("\n");
+ print_fingerprint(revoker_pk,NULL,2);
+ tty_printf("\n");
+
+ tty_printf("WARNING: appointing a key as a designated revoker "
+ "cannot be undone!\n");
+
+ tty_printf("\n");
+
+ if(!cpr_get_answer_is_yes("keyedit.add_revoker.okay",
+ "Are you sure you want to appoint this "
+ "key as a designated revoker? (y/N): "))
+ continue;
+
+ /* todo: handle 0x40 sensitive flag here */
+ revkey.class=0x80;
+ revkey.algid=revoker_pk->pubkey_algo;
+ free_public_key(revoker_pk);
+ break;
+ }
+
+ rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 0, 0, 0,
+ keygen_add_revkey,&revkey );
+ if( rc )
+ {
+ log_error("signing failed: %s\n", g10_errstr(rc) );
+ goto fail;
+ }
+
+ free_secret_key(sk);
+ sk=NULL;
+
+ /* insert into secret keyblock */
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = copy_signature(NULL, sig);
+ insert_kbnode( sec_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
+
+ /* insert into public keyblock */
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ insert_kbnode( pub_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
+
+ return 1;
+
+ fail:
+ if(sk)
+ free_secret_key(sk);
+ if(sig)
+ free_seckey_enc(sig);
+ if(revoker_pk)
+ free_public_key(revoker_pk);
+
+ return 0;
+}
+
static int
menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
@@ -1495,7 +2349,7 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
else if( node->pkt->pkttype == PKT_USER_ID )
uid = node->pkt->pkt.user_id;
else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE
- && (mainkey || sub_pk ) ) {
+ && ( mainkey || sub_pk ) ) {
PKT_signature *sig = node->pkt->pkt.signature;
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
&& ( (mainkey && uid && (sig->sig_class&~3) == 0x10)
@@ -1532,31 +2386,31 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
/* create new self signature */
if( mainkey )
rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
- sk, 0x13, 0,
+ sk, 0x13, 0, 0, 0, 0,
keygen_add_std_prefs, main_pk );
else
rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
- sk, 0x18, 0,
+ sk, 0x18, 0, 0, 0, 0,
keygen_add_key_expire, sub_pk );
if( rc ) {
log_error("make_keysig_packet failed: %s\n",
- gpg_errstr(rc));
+ g10_errstr(rc));
free_secret_key( sk );
return 0;
}
/* replace the packet */
- newpkt = gcry_xcalloc( 1, sizeof *newpkt );
+ newpkt = m_alloc_clear( sizeof *newpkt );
newpkt->pkttype = PKT_SIGNATURE;
newpkt->pkt.signature = newsig;
free_packet( node->pkt );
- gcry_free( node->pkt );
+ m_free( node->pkt );
node->pkt = newpkt;
if( sn ) {
- newpkt = gcry_xcalloc( 1, sizeof *newpkt );
+ newpkt = m_alloc_clear( sizeof *newpkt );
newpkt->pkttype = PKT_SIGNATURE;
newpkt->pkt.signature = copy_signature( NULL, newsig );
free_packet( sn->pkt );
- gcry_free( sn->pkt );
+ m_free( sn->pkt );
sn->pkt = newpkt;
}
sub_pk = NULL;
@@ -1565,9 +2419,235 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
}
free_secret_key( sk );
+ update_trust=1;
return 1;
}
+static int
+change_primary_uid_cb ( PKT_signature *sig, void *opaque )
+{
+ byte buf[1];
+
+ /* first clear all primary uid flags so that we are sure none are
+ * lingering around */
+ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID);
+ delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID);
+
+ /* if opaque is set,we want to set the primary id */
+ if (opaque) {
+ buf[0] = 1;
+ build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1 );
+ }
+
+ return 0;
+}
+
+
+/*
+ * Set the primary uid flag for the selected UID. We will also reset
+ * all other primary uid flags. For this to work with have to update
+ * all the signature timestamps. If we would do this with the current
+ * time, we lose quite a lot of information, so we use a a kludge to
+ * do this: Just increment the timestamp by one second which is
+ * sufficient to updated a signature during import.
+ */
+static int
+menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ PKT_secret_key *sk; /* copy of the main sk */
+ PKT_public_key *main_pk;
+ PKT_user_id *uid;
+ KBNODE node;
+ u32 keyid[2];
+ int selected;
+ int attribute = 0;
+ int modified = 0;
+
+ if ( count_selected_uids (pub_keyblock) != 1 ) {
+ tty_printf(_("Please select exactly one user ID.\n"));
+ return 0;
+ }
+
+ node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
+ sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
+
+ /* Now we can actually change the self signature(s) */
+ main_pk = NULL;
+ uid = NULL;
+ selected = 0;
+
+ /* Is our selected uid an attribute packet? */
+ for ( node=pub_keyblock; node; node = node->next )
+ if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID)
+ attribute = (node->pkt->pkt.user_id->attrib_data!=NULL);
+
+ for ( node=pub_keyblock; node; node = node->next ) {
+ if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+
+ if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ main_pk = node->pkt->pkt.public_key;
+ keyid_from_pk( main_pk, keyid );
+ }
+ else if ( node->pkt->pkttype == PKT_USER_ID ) {
+ uid = node->pkt->pkt.user_id;
+ selected = node->flag & NODFLG_SELUID;
+ }
+ else if ( main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE ) {
+ PKT_signature *sig = node->pkt->pkt.signature;
+ if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
+ && (uid && (sig->sig_class&~3) == 0x10)
+ && attribute == (uid->attrib_data!=NULL)) {
+ if(sig->version < 4) {
+ char *user=utf8_to_native(uid->name,strlen(uid->name),0);
+
+ log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
+ user);
+ m_free(user);
+ }
+ else {
+ /* This is a selfsignature which is to be replaced.
+ We can just ignore v3 signatures because they are
+ not able to carry the primary ID flag. We also
+ ignore self-sigs on user IDs that are not of the
+ same type that we are making primary. That is, if
+ we are making a user ID primary, we alter user IDs.
+ If we are making an attribute packet primary, we
+ alter attribute packets. */
+
+ /* FIXME: We must make sure that we only have one
+ self-signature per user ID here (not counting
+ revocations) */
+ PKT_signature *newsig;
+ PACKET *newpkt;
+ const byte *p;
+ int action;
+
+ /* see whether this signature has the primary UID flag */
+ p = parse_sig_subpkt (sig->hashed,
+ SIGSUBPKT_PRIMARY_UID, NULL );
+ if ( !p )
+ p = parse_sig_subpkt (sig->unhashed,
+ SIGSUBPKT_PRIMARY_UID, NULL );
+ if ( p && *p ) /* yes */
+ action = selected? 0 : -1;
+ else /* no */
+ action = selected? 1 : 0;
+
+ if (action) {
+ int rc = update_keysig_packet (&newsig, sig,
+ main_pk, uid,
+ sk,
+ change_primary_uid_cb,
+ action > 0? "x":NULL );
+ if( rc ) {
+ log_error ("update_keysig_packet failed: %s\n",
+ g10_errstr(rc));
+ free_secret_key( sk );
+ return 0;
+ }
+ /* replace the packet */
+ newpkt = m_alloc_clear( sizeof *newpkt );
+ newpkt->pkttype = PKT_SIGNATURE;
+ newpkt->pkt.signature = newsig;
+ free_packet( node->pkt );
+ m_free( node->pkt );
+ node->pkt = newpkt;
+ modified = 1;
+ }
+ }
+ }
+ }
+ }
+
+ free_secret_key( sk );
+ return modified;
+}
+
+
+/*
+ * Set preferences to new values for the selected user IDs
+ */
+static int
+menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+ PKT_secret_key *sk; /* copy of the main sk */
+ PKT_public_key *main_pk;
+ PKT_user_id *uid;
+ KBNODE node;
+ u32 keyid[2];
+ int selected, select_all;
+ int modified = 0;
+
+ select_all = !count_selected_uids (pub_keyblock);
+
+ node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
+ sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
+
+ /* Now we can actually change the self signature(s) */
+ main_pk = NULL;
+ uid = NULL;
+ selected = 0;
+ for ( node=pub_keyblock; node; node = node->next ) {
+ if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+
+ if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ main_pk = node->pkt->pkt.public_key;
+ keyid_from_pk( main_pk, keyid );
+ }
+ else if ( node->pkt->pkttype == PKT_USER_ID ) {
+ uid = node->pkt->pkt.user_id;
+ selected = select_all || (node->flag & NODFLG_SELUID);
+ }
+ else if ( main_pk && uid && selected
+ && node->pkt->pkttype == PKT_SIGNATURE ) {
+ PKT_signature *sig = node->pkt->pkt.signature;
+ if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
+ && (uid && (sig->sig_class&~3) == 0x10) ) {
+ if( sig->version < 4 ) {
+ char *user=utf8_to_native(uid->name,strlen(uid->name),0);
+
+ log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
+ user);
+ m_free(user);
+ }
+ else {
+ /* This is a selfsignature which is to be replaced
+ * We have to ignore v3 signatures because they are
+ * not able to carry the preferences */
+ PKT_signature *newsig;
+ PACKET *newpkt;
+ int rc;
+
+ rc = update_keysig_packet (&newsig, sig,
+ main_pk, uid,
+ sk,
+ keygen_upd_std_prefs,
+ NULL );
+ if( rc ) {
+ log_error ("update_keysig_packet failed: %s\n",
+ g10_errstr(rc));
+ free_secret_key( sk );
+ return 0;
+ }
+ /* replace the packet */
+ newpkt = m_alloc_clear( sizeof *newpkt );
+ newpkt->pkttype = PKT_SIGNATURE;
+ newpkt->pkt.signature = newsig;
+ free_packet( node->pkt );
+ m_free( node->pkt );
+ node->pkt = newpkt;
+ modified = 1;
+ }
+ }
+ }
+ }
+
+ free_secret_key( sk );
+ return modified;
+}
+
/****************
* Select one user id or remove all selection if index is 0.
@@ -1717,6 +2797,21 @@ count_selected_keys( KBNODE keyblock )
return count_keys_with_flag( keyblock, NODFLG_SELKEY);
}
+/* returns how many real (i.e. not attribute) uids are unmarked */
+static int
+real_uids_left( KBNODE keyblock )
+{
+ KBNODE node;
+ int real=0;
+
+ for(node=keyblock;node;node=node->next)
+ if(node->pkt->pkttype==PKT_USER_ID && !(node->flag&NODFLG_SELUID) &&
+ !node->pkt->pkt.user_id->attrib_data)
+ real++;
+
+ return real;
+}
+
/*
* Ask whether the signature should be revoked. If the user commits this,
* flag bit MARK_A is set on the signature and the user ID.
@@ -1724,6 +2819,7 @@ count_selected_keys( KBNODE keyblock )
static void
ask_revoke_sig( KBNODE keyblock, KBNODE node )
{
+ int doit=0;
PKT_signature *sig = node->pkt->pkt.signature;
KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
@@ -1735,13 +2831,29 @@ ask_revoke_sig( KBNODE keyblock, KBNODE node )
tty_printf(_("user ID: \""));
tty_print_utf8_string( unode->pkt->pkt.user_id->name,
unode->pkt->pkt.user_id->len );
- tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
- sig->keyid[1], datestr_from_sig(sig) );
- if( cpr_get_answer_is_yes("ask_revoke_sig.one",
- _("Create a revocation certificate for this signature? (y/N)")) ) {
- node->flag |= NODFLG_MARK_A;
- unode->flag |= NODFLG_MARK_A;
+ if(sig->flags.exportable)
+ tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
+ (ulong)sig->keyid[1], datestr_from_sig(sig) );
+ else
+ tty_printf(_("\"\nlocally signed with your key %08lX at %s\n"),
+ (ulong)sig->keyid[1], datestr_from_sig(sig) );
+
+ if(sig->flags.expired)
+ {
+ tty_printf(_("This signature expired on %s.\n"),
+ expirestr_from_sig(sig));
+ /* Use a different question so we can have different help text */
+ doit=cpr_get_answer_is_yes("ask_revoke_sig.expired",
+ _("Are you sure you still want to revoke it? (y/N) "));
+ }
+ else
+ doit=cpr_get_answer_is_yes("ask_revoke_sig.one",
+ _("Create a revocation certificate for this signature? (y/N) "));
+
+ if(doit) {
+ node->flag |= NODFLG_MARK_A;
+ unode->flag |= NODFLG_MARK_A;
}
}
@@ -1758,7 +2870,6 @@ menu_revsig( KBNODE keyblock )
PKT_public_key *primary_pk;
KBNODE node;
int changed = 0;
- int upd_trust = 0;
int rc, any;
struct revocation_reason_info *reason = NULL;
@@ -1775,15 +2886,18 @@ menu_revsig( KBNODE keyblock )
}
else if( node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->pkt.signature),
- !seckey_available( sig->keyid ) ) ) {
+ !seckey_available(sig->keyid) ) ) {
if( (sig->sig_class&~3) == 0x10 ) {
- tty_printf(_(" signed by %08lX at %s\n"),
- sig->keyid[1], datestr_from_sig(sig) );
- node->flag |= NODFLG_SELSIG;
+ tty_printf(_(" signed by %08lX at %s%s%s\n"),
+ (ulong)sig->keyid[1], datestr_from_sig(sig),
+ sig->flags.exportable?"":" (non-exportable)",
+ sig->flags.revocable?"":" (non-revocable)");
+ if(sig->flags.revocable)
+ node->flag |= NODFLG_SELSIG;
}
else if( sig->sig_class == 0x30 ) {
tty_printf(_(" revoked by %08lX at %s\n"),
- sig->keyid[1], datestr_from_sig(sig) );
+ (ulong)sig->keyid[1], datestr_from_sig(sig) );
}
}
}
@@ -1812,15 +2926,16 @@ menu_revsig( KBNODE keyblock )
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
sig = node->pkt->pkt.signature;
- tty_printf(_(" signed by %08lX at %s\n"),
- sig->keyid[1], datestr_from_sig(sig) );
+ tty_printf(_(" signed by %08lX at %s%s\n"),
+ (ulong)sig->keyid[1], datestr_from_sig(sig),
+ sig->flags.exportable?"":_(" (non-exportable)") );
}
}
if( !any )
return 0; /* none selected */
if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
- _("Really create the revocation certificates? (y/N)")) )
+ _("Really create the revocation certificates? (y/N) ")) )
return 0; /* forget it */
reason = ask_revocation_reason( 0, 1, 0 );
@@ -1845,9 +2960,10 @@ menu_revsig( KBNODE keyblock )
memset( &attrib, 0, sizeof attrib );
attrib.reason = reason;
+ attrib.non_exportable=!node->pkt->pkt.signature->flags.exportable;
node->flag &= ~NODFLG_MARK_A;
- sk = gcry_xcalloc_secure( 1, sizeof *sk );
+ sk = m_alloc_secure_clear( sizeof *sk );
if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
log_info(_("no secret key\n"));
continue;
@@ -1856,27 +2972,25 @@ menu_revsig( KBNODE keyblock )
unode->pkt->pkt.user_id,
NULL,
sk,
- 0x30, 0,
+ 0x30, 0, 0, 0, 0,
sign_mk_attrib,
&attrib );
free_secret_key(sk);
if( rc ) {
- log_error(_("signing failed: %s\n"), gpg_errstr(rc));
+ log_error(_("signing failed: %s\n"), g10_errstr(rc));
release_revocation_reason_info( reason );
return changed;
}
changed = 1; /* we changed the keyblock */
- upd_trust = 1;
+ update_trust = 1;
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
insert_kbnode( unode, new_kbnode(pkt), 0 );
goto reloop;
}
- if( upd_trust )
- clear_trust_checked_flag( primary_pk );
release_revocation_reason_info( reason );
return changed;
}
@@ -1892,7 +3006,6 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
PKT_public_key *mainpk;
KBNODE node;
int changed = 0;
- int upd_trust = 0;
int rc;
struct revocation_reason_info *reason = NULL;
@@ -1918,19 +3031,18 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
node->flag &= ~NODFLG_SELKEY;
sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
- rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0,
- sign_mk_attrib,
- &attrib );
+ rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk,
+ 0x28, 0, 0, 0, 0,
+ sign_mk_attrib, &attrib );
free_secret_key(sk);
if( rc ) {
- log_error(_("signing failed: %s\n"), gpg_errstr(rc));
+ log_error(_("signing failed: %s\n"), g10_errstr(rc));
release_revocation_reason_info( reason );
return changed;
}
changed = 1; /* we changed the keyblock */
- upd_trust = 1;
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
insert_kbnode( node, new_kbnode(pkt), 0 );
@@ -1940,8 +3052,9 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
commit_kbnode( &pub_keyblock );
/*commit_kbnode( &sec_keyblock );*/
- if( upd_trust )
- clear_trust_checked_flag( mainpk );
+ /* No need to set update_trust here since signing keys no longer
+ are used to certify other keys, so there is no change in trust
+ when revoking/removing them */
release_revocation_reason_info( reason );
return changed;
@@ -1951,20 +3064,67 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
static int
enable_disable_key( KBNODE keyblock, int disable )
{
- ulong lid = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key->local_id;
+ PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
+ ->pkt->pkt.public_key;
unsigned int trust, newtrust;
- /* Note: Because the keys have beed displayed, we have
- * ensured that local_id has been set */
- trust = newtrust = get_ownertrust( lid );
+ trust = newtrust = get_ownertrust (pk);
newtrust &= ~TRUST_FLAG_DISABLED;
if( disable )
newtrust |= TRUST_FLAG_DISABLED;
if( trust == newtrust )
return 0; /* already in that state */
- if( !update_ownertrust( lid, newtrust ) )
- return 1;
+ update_ownertrust(pk, newtrust );
return 0;
}
+
+static void
+menu_showphoto( KBNODE keyblock )
+{
+ KBNODE node;
+ int select_all = !count_selected_uids(keyblock);
+ int count=0;
+ PKT_public_key *pk=NULL;
+ u32 keyid[2];
+
+ /* Look for the public key first. We have to be really, really,
+ explicit as to which photo this is, and what key it is a UID on
+ since people may want to sign it. */
+
+ for( node = keyblock; node; node = node->next )
+ {
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+ {
+ pk = node->pkt->pkt.public_key;
+ keyid_from_pk(pk, keyid);
+ }
+ else if( node->pkt->pkttype == PKT_USER_ID )
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ count++;
+
+ if((select_all || (node->flag & NODFLG_SELUID)) &&
+ uid->attribs!=NULL)
+ {
+ int i;
+
+ for(i=0;i<uid->numattribs;i++)
+ {
+ byte type;
+ u32 size;
+
+ if(uid->attribs[i].type==ATTRIB_IMAGE &&
+ parse_image_header(&uid->attribs[i],&type,&size))
+ {
+ tty_printf(_("Displaying %s photo ID of size %ld for "
+ "key 0x%08lX (uid %d)\n"),
+ image_type_to_string(type,1),
+ (ulong)size,(ulong)keyid[1],count);
+ show_photos(&uid->attribs[i],1,pk,NULL);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/g10/keygen.c b/g10/keygen.c
index 1e2accd0c..b8398b88a 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1,5 +1,5 @@
/* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -26,23 +26,31 @@
#include <errno.h>
#include <assert.h>
#include "util.h"
-#include <gcrypt.h>
#include "main.h"
#include "packet.h"
+#include "cipher.h"
#include "ttyio.h"
#include "options.h"
#include "keydb.h"
+#include "trustdb.h"
#include "status.h"
#include "i18n.h"
+#define MAX_PREFS 30
+
+
enum para_name {
pKEYTYPE,
pKEYLENGTH,
+ pKEYUSAGE,
pSUBKEYTYPE,
pSUBKEYLENGTH,
+ pSUBKEYUSAGE,
pNAMEREAL,
pNAMEEMAIL,
pNAMECOMMENT,
+ pPREFERENCES,
+ pREVOKER,
pUSERID,
pEXPIREDATE,
pKEYEXPIRE, /* in n seconds */
@@ -57,10 +65,12 @@ struct para_data_s {
int lnr;
enum para_name key;
union {
- DEK *dek;
- STRING2KEY *s2k;
- u32 expire;
- char value[1];
+ DEK *dek;
+ STRING2KEY *s2k;
+ u32 expire;
+ unsigned int usage;
+ struct revocation_key revkey;
+ char value[1];
} u;
};
@@ -83,6 +93,21 @@ struct output_control_s {
};
+struct opaque_data_usage_and_pk {
+ unsigned int usage;
+ PKT_public_key *pk;
+};
+
+
+static int prefs_initialized = 0;
+static byte sym_prefs[MAX_PREFS];
+static int nsym_prefs;
+static byte hash_prefs[MAX_PREFS];
+static int nhash_prefs;
+static byte zip_prefs[MAX_PREFS];
+static int nzip_prefs;
+static int mdc_available;
+
static void do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl );
static int write_keyblock( IOBUF out, KBNODE node );
@@ -91,16 +116,32 @@ static int write_keyblock( IOBUF out, KBNODE node );
static void
write_uid( KBNODE root, const char *s )
{
- PACKET *pkt = gcry_xcalloc( 1,sizeof *pkt );
+ PACKET *pkt = m_alloc_clear(sizeof *pkt );
size_t n = strlen(s);
pkt->pkttype = PKT_USER_ID;
- pkt->pkt.user_id = gcry_xcalloc( 1, sizeof *pkt->pkt.user_id + n - 1 );
+ pkt->pkt.user_id = m_alloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
pkt->pkt.user_id->len = n;
+ pkt->pkt.user_id->ref = 1;
strcpy(pkt->pkt.user_id->name, s);
add_kbnode( root, new_kbnode( pkt ) );
}
+static void
+do_add_key_flags (PKT_signature *sig, unsigned int use)
+{
+ byte buf[1];
+
+ if (!use)
+ return;
+
+ buf[0] = 0;
+ if (use & PUBKEY_USAGE_SIG)
+ buf[0] |= 0x01 | 0x02;
+ if (use & PUBKEY_USAGE_ENC)
+ buf[0] |= 0x04 | 0x08;
+ build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
+}
int
@@ -123,34 +164,318 @@ keygen_add_key_expire( PKT_signature *sig, void *opaque )
return 0;
}
+static int
+keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
+{
+ struct opaque_data_usage_and_pk *oduap = opaque;
+
+ do_add_key_flags (sig, oduap->usage);
+ return keygen_add_key_expire (sig, oduap->pk);
+}
+
+static int
+set_one_pref (ulong val, int type, int (*cf)(int), byte *buf, int *nbuf)
+{
+ int i;
+
+ if (cf (val)) {
+ log_info (_("preference %c%lu is not valid\n"), type, val);
+ if(type=='S' && val==CIPHER_ALGO_IDEA)
+ idea_cipher_warn(1);
+ return -1;
+ }
+ for (i=0; i < *nbuf; i++ ) {
+ if (buf[i] == val) {
+ log_info (_("preference %c%lu duplicated\n"), type, val);
+ return -1;
+ }
+ }
+ if (*nbuf >= MAX_PREFS) {
+ log_info (_("too many `%c' preferences\n"), type);
+ return -1;
+ }
+ buf[(*nbuf)++] = val;
+ return 0;
+}
+
+
+/*
+ * Parse the supplied string and use it to set the standard preferences.
+ * The String is expected to be in a forma like the one printed by "prefs",
+ * something like: "S10 S3 H3 H2 Z2 Z1". Use NULL to set the default
+ * preferences.
+ * Returns: 0 = okay
+ */
+int
+keygen_set_std_prefs (const char *string,int personal)
+{
+ byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
+ int nsym=0, nhash=0, nzip=0, mdc=1; /* mdc defaults on */
+ ulong val;
+ const char *s, *s2;
+ int rc = 0;
+
+ if (!string || !ascii_strcasecmp (string, "default")) {
+ if (opt.def_preference_list)
+ string=opt.def_preference_list;
+ else if ( !check_cipher_algo(CIPHER_ALGO_IDEA) )
+ string = "S7 S3 S2 S1 H2 H3 Z2 Z1";
+ else
+ string = "S7 S3 S2 H2 H3 Z2 Z1";
+
+ /* If we have it, IDEA goes *after* 3DES so it won't be used
+ unless we're encrypting along with a V3 key. Ideally, we
+ would only put the S1 preference in if the key was RSA and
+ <=2048 bits, as that is what won't break PGP2, but that is
+ difficult with the current code, and not really worth
+ checking as a non-RSA <=2048 bit key wouldn't be usable by
+ PGP2 anyway -dms */
+ }
+ else if (!ascii_strcasecmp (string, "none"))
+ string = "";
+
+ for (s=string; *s; s = s2) {
+ if ((*s=='s' || *s == 'S') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'S', check_cipher_algo, sym, &nsym))
+ rc = -1;
+ }
+ else if ((*s=='h' || *s == 'H') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'H', check_digest_algo, hash, &nhash))
+ rc = -1;
+ }
+ else if ((*s=='z' || *s == 'Z') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'Z', check_compress_algo, zip, &nzip))
+ rc = -1;
+ }
+ else if (ascii_strcasecmp(s,"mdc")==0) {
+ mdc=1;
+ s2=s+3;
+ }
+ else if (ascii_strcasecmp(s,"no-mdc")==0) {
+ mdc=0;
+ s2=s+6;
+ }
+ else if (isspace (*s))
+ s2 = s+1;
+ else {
+ log_info (_("invalid character in preference string\n"));
+ return -1;
+ }
+ }
+
+ if (!rc)
+ {
+ if(personal)
+ {
+ if(personal==PREFTYPE_SYM)
+ {
+ m_free(opt.personal_cipher_prefs);
+
+ if(nsym==0)
+ opt.personal_cipher_prefs=NULL;
+ else
+ {
+ int i;
+
+ opt.personal_cipher_prefs=
+ m_alloc(sizeof(prefitem_t *)*(nsym+1));
+
+ for (i=0; i<nsym; i++)
+ {
+ opt.personal_cipher_prefs[i].type = PREFTYPE_SYM;
+ opt.personal_cipher_prefs[i].value = sym[i];
+ }
+
+ opt.personal_cipher_prefs[i].type = PREFTYPE_NONE;
+ opt.personal_cipher_prefs[i].value = 0;
+ }
+ }
+ else if(personal==PREFTYPE_HASH)
+ {
+ m_free(opt.personal_digest_prefs);
+
+ if(nhash==0)
+ opt.personal_digest_prefs=NULL;
+ else
+ {
+ int i;
+
+ opt.personal_digest_prefs=
+ m_alloc(sizeof(prefitem_t *)*(nhash+1));
+
+ for (i=0; i<nhash; i++)
+ {
+ opt.personal_digest_prefs[i].type = PREFTYPE_HASH;
+ opt.personal_digest_prefs[i].value = hash[i];
+ }
+
+ opt.personal_digest_prefs[i].type = PREFTYPE_NONE;
+ opt.personal_digest_prefs[i].value = 0;
+ }
+ }
+ else if(personal==PREFTYPE_ZIP)
+ {
+ m_free(opt.personal_compress_prefs);
+
+ if(nzip==0)
+ opt.personal_compress_prefs=NULL;
+ else
+ {
+ int i;
+
+ opt.personal_compress_prefs=
+ m_alloc(sizeof(prefitem_t *)*(nzip+1));
+
+ for (i=0; i<nzip; i++)
+ {
+ opt.personal_compress_prefs[i].type = PREFTYPE_ZIP;
+ opt.personal_compress_prefs[i].value = zip[i];
+ }
+
+ opt.personal_compress_prefs[i].type = PREFTYPE_NONE;
+ opt.personal_compress_prefs[i].value = 0;
+ }
+ }
+ }
+ else
+ {
+ memcpy (sym_prefs, sym, (nsym_prefs=nsym));
+ memcpy (hash_prefs, hash, (nhash_prefs=nhash));
+ memcpy (zip_prefs, zip, (nzip_prefs=nzip));
+ mdc_available = mdc;
+ prefs_initialized = 1;
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * Return a printable list of preferences. Caller must free.
+ */
+char *
+keygen_get_std_prefs ()
+{
+ char *buf;
+ int i;
+
+ if (!prefs_initialized)
+ keygen_set_std_prefs (NULL,0);
+
+ buf = m_alloc ( MAX_PREFS*3*5 + 5 + 1);
+ *buf = 0;
+ for (i=0; i < nsym_prefs; i++ )
+ sprintf (buf+strlen(buf), "S%d ", sym_prefs[i]);
+ for (i=0; i < nhash_prefs; i++ )
+ sprintf (buf+strlen(buf), "H%d ", hash_prefs[i]);
+ for (i=0; i < nzip_prefs; i++ )
+ sprintf (buf+strlen(buf), "Z%d ", zip_prefs[i]);
+
+ if(mdc_available)
+ sprintf(buf+strlen(buf),"[mdc]");
+ else if (*buf) /* trim the trailing space */
+ buf[strlen(buf)-1] = 0;
+
+ return buf;
+}
+
+
+static void
+add_feature_mdc (PKT_signature *sig,int enabled)
+{
+ const byte *s;
+ size_t n;
+ int i;
+ char *buf;
+
+ s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ /* Already set or cleared */
+ if (s && n &&
+ ((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01))))
+ return;
+
+ if (!s || !n) { /* create a new one */
+ n = 1;
+ buf = m_alloc_clear (n);
+ }
+ else {
+ buf = m_alloc (n);
+ memcpy (buf, s, n);
+ }
+
+ if(enabled)
+ buf[0] |= 0x01; /* MDC feature */
+ else
+ buf[0] &= ~0x01;
+
+ /* Are there any bits set? */
+ for(i=0;i<n;i++)
+ if(buf[i]!=0)
+ break;
+
+ if(i==n)
+ delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
+ else
+ build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
+
+ m_free (buf);
+}
+
+int
+keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
+{
+ if (!prefs_initialized)
+ keygen_set_std_prefs (NULL, 0);
+
+ if (nsym_prefs)
+ build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
+ else
+ {
+ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
+ delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
+ }
+
+ if (nhash_prefs)
+ build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
+ else
+ {
+ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
+ delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
+ }
+
+ if (nzip_prefs)
+ build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
+ else
+ {
+ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
+ delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
+ }
+
+ /* Make sure that the MDC feature flag is set if needed */
+ add_feature_mdc (sig,mdc_available);
+
+ return 0;
+}
+
/****************
* Add preference to the self signature packet.
* This is only called for packets with version > 3.
+
*/
int
keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{
+ PKT_public_key *pk = opaque;
byte buf[8];
+ do_add_key_flags (sig, pk->pubkey_usage);
keygen_add_key_expire( sig, opaque );
-
- buf[0] = GCRY_CIPHER_RIJNDAEL;
- buf[1] = GCRY_CIPHER_TWOFISH;
- buf[2] = GCRY_CIPHER_CAST5;
- buf[3] = GCRY_CIPHER_BLOWFISH;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 4 );
-
- buf[0] = GCRY_MD_RMD160;
- buf[1] = GCRY_MD_SHA1;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_HASH, buf, 2 );
-
- buf[0] = 2;
- buf[1] = 1;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_COMPR, buf, 2 );
-
- buf[0] = 1; /* supports MDC packets (15 + 16) */
- build_sig_subpkt( sig, SIGSUBPKT_FEATURES, buf, 1 );
+ keygen_upd_std_prefs (sig, opaque);
buf[0] = 0x80; /* no modify - It is reasonable that a key holder
* has the possibility to reject signatures from users
@@ -163,10 +488,69 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
return 0;
}
+int
+keygen_add_revkey(PKT_signature *sig, void *opaque)
+{
+ struct revocation_key *revkey=opaque;
+ byte buf[2+MAX_FINGERPRINT_LEN];
+
+ buf[0]=revkey->class;
+ buf[1]=revkey->algid;
+ memcpy(&buf[2],revkey->fpr,MAX_FINGERPRINT_LEN);
+
+ build_sig_subpkt(sig,SIGSUBPKT_REV_KEY,buf,2+MAX_FINGERPRINT_LEN);
+ /* All sigs with revocation keys set are nonrevocable */
+ sig->flags.revocable=0;
+ buf[0] = 0;
+ build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
+
+ parse_revkeys(sig);
+
+ return 0;
+}
static int
-write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
+write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+ struct revocation_key *revkey )
+{
+ PACKET *pkt;
+ PKT_signature *sig;
+ int rc=0;
+ KBNODE node;
+ PKT_public_key *pk;
+
+ if( opt.verbose )
+ log_info(_("writing direct signature\n"));
+
+ /* get the pk packet from the pub_tree */
+ node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
+ if( !node )
+ BUG();
+ pk = node->pkt->pkt.public_key;
+
+ /* we have to cache the key, so that the verification of the signature
+ * creation is able to retrieve the public key */
+ cache_public_key (pk);
+
+ /* and make the signature */
+ rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,0,0,
+ keygen_add_revkey,revkey);
+ if( rc ) {
+ log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ add_kbnode( root, new_kbnode( pkt ) );
+ return rc;
+}
+
+static int
+write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+ unsigned int use )
{
PACKET *pkt;
PKT_signature *sig;
@@ -188,16 +572,20 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
if( !node )
BUG();
pk = node->pkt->pkt.public_key;
+ pk->pubkey_usage = use;
+ /* we have to cache the key, so that the verification of the signature
+ * creation is able to retrieve the public key */
+ cache_public_key (pk);
/* and make the signature */
- rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
- keygen_add_std_prefs, pk );
+ rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
+ keygen_add_std_prefs, pk );
if( rc ) {
- log_error("make_keysig_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode( root, new_kbnode( pkt ) );
@@ -205,13 +593,15 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
}
static int
-write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
+write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+ unsigned int use )
{
PACKET *pkt;
PKT_signature *sig;
int rc=0;
KBNODE node;
PKT_public_key *pk, *subpk;
+ struct opaque_data_usage_and_pk oduap;
if( opt.verbose )
log_info(_("writing key binding signature\n"));
@@ -221,6 +611,10 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
if( !node )
BUG();
pk = node->pkt->pkt.public_key;
+ /* we have to cache the key, so that the verification of the signature
+ * creation is able to retrieve the public key */
+ cache_public_key (pk);
+
/* find the last subkey */
subpk = NULL;
for(node=pub_root; node; node = node->next ) {
@@ -231,14 +625,16 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
BUG();
/* and make the signature */
- rc = make_keysig_packet( &sig, pk, NULL, subpk, sk, 0x18, 0,
- keygen_add_key_expire, subpk );
+ oduap.usage = use;
+ oduap.pk = subpk;
+ rc = make_keysig_packet( &sig, pk, NULL, subpk, sk, 0x18, 0, 0, 0, 0,
+ keygen_add_key_flags_and_expire, &oduap );
if( rc ) {
- log_error("make_keysig_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode( root, new_kbnode( pkt ) );
@@ -246,63 +642,17 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
}
-
-static int
-key_from_sexp( GCRY_MPI *array,
- GCRY_SEXP sexp, const char *topname, const char *elems )
-{
- GCRY_SEXP list, l2;
- const char *s;
- int i, idx;
-
- list = gcry_sexp_find_token( sexp, topname, 0 );
- if( !list )
- return GCRYERR_INV_OBJ;
- l2 = gcry_sexp_cadr( list );
- gcry_sexp_release ( list );
- list = l2;
- if( !list )
- return GCRYERR_NO_OBJ;
-
- idx = 0;
- for(s=elems; *s; s++, idx++ ) {
- l2 = gcry_sexp_find_token( list, s, 1 );
- if( !l2 ) {
- for(i=0; i<idx; i++) {
- gcry_free( array[i] );
- array[i] = NULL;
- }
- gcry_sexp_release ( list );
- return GCRYERR_NO_OBJ; /* required parameter not found */
- }
- array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
- gcry_sexp_release ( l2 );
- if( !array[idx] ) {
- for(i=0; i<idx; i++) {
- gcry_free( array[i] );
- array[i] = NULL;
- }
- gcry_sexp_release ( list );
- return GCRYERR_INV_OBJ; /* required parameter is invalid */
- }
- }
- gcry_sexp_release ( list );
-
- return 0;
-}
-
-
-
static int
gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
+ int i;
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- GCRY_SEXP misc_key_info;
- GCRY_SEXP s_parms, s_key;
+ MPI skey[4];
+ MPI *factors;
assert( is_ELGAMAL(algo) );
@@ -316,46 +666,31 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
- if ( gcry_sexp_build ( &s_parms, NULL,
- "(genkey(%s(nbits %d)))",
- algo == GCRY_PK_ELG_E ? "openpgp-elg" :
- algo == GCRY_PK_ELG ? "elg" : "x-oops" ,
- (int)nbits ) )
- BUG ();
- rc = gcry_pk_genkey( &s_key, s_parms );
- gcry_sexp_release( s_parms );
+ rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
- log_error("pk_genkey failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
-
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->version = pk->version = 4;
if( expireval ) {
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
}
sk->pubkey_algo = pk->pubkey_algo = algo;
-
- rc = key_from_sexp( pk->pkey, s_key, "public-key", "pgy" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- rc = key_from_sexp( sk->skey, s_key, "private-key", "pgyx" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- misc_key_info = gcry_sexp_find_token( s_key, "misc-key-info", 0 );
- gcry_sexp_release ( s_key );
-
+ pk->pkey[0] = mpi_copy( skey[0] );
+ pk->pkey[1] = mpi_copy( skey[1] );
+ pk->pkey[2] = mpi_copy( skey[2] );
+ sk->skey[0] = skey[0];
+ sk->skey[1] = skey[1];
+ sk->skey[2] = skey[2];
+ sk->skey[3] = skey[3];
sk->is_protected = 0;
sk->protect.algo = 0;
- sk->csum = checksum_mpi( sk->skey[3] );
+ sk->csum = checksum_mpi_counted_nbits( sk->skey[3] );
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
*ret_sk = copy_secret_key( NULL, sk );
@@ -364,39 +699,27 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
add_kbnode(pub_root, new_kbnode( pkt ));
/* don't know whether it makes sense to have the factors, so for now
* we store them in the secret keyring (but they are not secret) */
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
- if ( misc_key_info ) {
- size_t n;
- char *buf;
-
- n = gcry_sexp_sprint ( misc_key_info, 0, NULL, 0 );
- buf = gcry_xmalloc ( n+4 );
- strcpy ( buf, "#::" );
- n = gcry_sexp_sprint ( misc_key_info, 0, buf+3, n );
- if ( n ) {
- n += 3;
- add_kbnode( sec_root, make_comment_node_from_buffer( buf, n ));
- }
- gcry_free ( buf );
- gcry_sexp_release (misc_key_info);
- }
+ for(i=0; factors[i]; i++ )
+ add_kbnode( sec_root,
+ make_mpi_comment_node("#:ELG_factor:", factors[i] ));
return 0;
}
@@ -410,11 +733,12 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
+ int i;
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- GCRY_SEXP misc_key_info;
- GCRY_SEXP s_parms, s_key;
+ MPI skey[5];
+ MPI *factors;
if( nbits > 1024 || nbits < 512 ) {
nbits = 1024;
@@ -426,44 +750,33 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
- if ( gcry_sexp_build ( &s_parms, NULL,
- "(genkey(dsa(nbits %d)))", (int)nbits ) )
- BUG ();
-
- rc = gcry_pk_genkey( &s_key, s_parms );
- gcry_sexp_release( s_parms );
+ rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
if( rc ) {
- log_error("pk_genkey failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
-
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->version = pk->version = 4;
if( expireval ) {
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
}
- sk->pubkey_algo = pk->pubkey_algo = GCRY_PK_DSA;
-
- rc = key_from_sexp( pk->pkey, s_key, "public-key", "pqgy" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- rc = key_from_sexp( sk->skey, s_key, "private-key", "pqgyx" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- misc_key_info = gcry_sexp_find_token( s_key, "misc-key-info", 0 );
- gcry_sexp_release ( s_key );
-
+ sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
+ pk->pkey[0] = mpi_copy( skey[0] );
+ pk->pkey[1] = mpi_copy( skey[1] );
+ pk->pkey[2] = mpi_copy( skey[2] );
+ pk->pkey[3] = mpi_copy( skey[3] );
+ sk->skey[0] = skey[0];
+ sk->skey[1] = skey[1];
+ sk->skey[2] = skey[2];
+ sk->skey[3] = skey[3];
+ sk->skey[4] = skey[4];
sk->is_protected = 0;
sk->protect.algo = 0;
- sk->csum = checksum_mpi( sk->skey[4] );
+ sk->csum = checksum_mpi_counted_nbits( sk->skey[4] );
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
*ret_sk = copy_secret_key( NULL, sk );
@@ -472,47 +785,39 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
- gcry_sexp_release (misc_key_info);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
add_kbnode(pub_root, new_kbnode( pkt ));
/* don't know whether it makes sense to have the factors, so for now
* we store them in the secret keyring (but they are not secret)
+ * p = 2 * q * f1 * f2 * ... * fn
+ * We store only f1 to f_n-1; fn can be calculated because p and q
+ * are known.
*/
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
- if ( misc_key_info ) {
- size_t n;
- char *buf;
-
- n = gcry_sexp_sprint ( misc_key_info, 0, NULL, 0 );
- buf = gcry_xmalloc ( n+4 );
- strcpy ( buf, "#::" );
- n = gcry_sexp_sprint ( misc_key_info, 0, buf+3, n );
- if ( n ) {
- n += 3;
- add_kbnode( sec_root, make_comment_node_from_buffer( buf, n ));
- }
- gcry_free ( buf );
- gcry_sexp_release (misc_key_info);
- }
- /* fixme: Merge this with the elg-generate function and release
- * some more stuff (memory-leak) */
+ for(i=1; factors[i]; i++ ) /* the first one is q */
+ add_kbnode( sec_root,
+ make_mpi_comment_node("#:DSA_factor:", factors[i] ));
+
return 0;
}
-#if 0
+
+/*
+ * Generate an RSA key.
+ */
static int
gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
@@ -521,7 +826,7 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- MPI skey[4];
+ MPI skey[6];
MPI *factors;
assert( is_RSA(algo) );
@@ -538,12 +843,12 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
- log_error("pubkey_generate failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->version = pk->version = 4;
if( expireval ) {
@@ -573,26 +878,25 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
add_kbnode(pub_root, new_kbnode( pkt ));
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
return 0;
}
-#endif
/****************
@@ -625,55 +929,69 @@ check_valid_days( const char *s )
/****************
* Returns: 0 to create both a DSA and a ElGamal key.
+ * and only if key flags are to be written the desired usage.
*/
static int
-ask_algo( int addmode )
+ask_algo (int addmode, unsigned int *r_usage)
{
char *answer;
int algo;
+ *r_usage = 0;
tty_printf(_("Please select what kind of key you want:\n"));
if( !addmode )
tty_printf(_(" (%d) DSA and ElGamal (default)\n"), 1 );
tty_printf( _(" (%d) DSA (sign only)\n"), 2 );
if( addmode )
tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 );
- tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 );
- #if 0
- tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 5 );
- #endif
+ if (opt.expert)
+ tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 );
+ tty_printf( _(" (%d) RSA (sign only)\n"), 5 );
+ if (addmode)
+ tty_printf( _(" (%d) RSA (encrypt only)\n"), 6 );
+ if (opt.expert)
+ tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 7 );
for(;;) {
answer = cpr_get("keygen.algo",_("Your selection? "));
cpr_kill_prompt();
algo = *answer? atoi(answer): 1;
- gcry_free(answer);
+ m_free(answer);
if( algo == 1 && !addmode ) {
algo = 0; /* create both keys */
break;
}
- #if 0
+ else if( algo == 7 && opt.expert ) {
+ if (cpr_get_answer_is_yes ("keygen.algo.rsa_se",_(
+ "The use of this algorithm is deprecated - create anyway? "))){
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG;
+ break;
+ }
+ }
+ else if( algo == 6 && addmode ) {
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_ENC;
+ break;
+ }
else if( algo == 5 ) {
- if( cpr_get_answer_is_yes("keygen.algo.rsa_se",_(
- "Do you really want to create a sign and encrypt key? "))) {
- algo = GCRY_PK_RSA;
- break;
- }
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_SIG;
+ break;
}
- #endif
- else if( algo == 4 ) {
+ else if( algo == 4 && opt.expert) {
if( cpr_get_answer_is_yes("keygen.algo.elg_se",_(
- "Do you really want to create a sign and encrypt key? "))) {
- algo = GCRY_PK_ELG;
+ "The use of this algorithm is deprecated - create anyway? "))){
+ algo = PUBKEY_ALGO_ELGAMAL;
break;
}
}
else if( algo == 3 && addmode ) {
- algo = GCRY_PK_ELG_E;
+ algo = PUBKEY_ALGO_ELGAMAL_E;
break;
}
else if( algo == 2 ) {
- algo = GCRY_PK_DSA;
+ algo = PUBKEY_ALGO_DSA;
break;
}
else
@@ -689,24 +1007,28 @@ ask_keysize( int algo )
char *answer;
unsigned nbits;
- tty_printf(_("About to generate a new %s keypair.\n"
- " minimum keysize is 768 bits\n"
- " default keysize is 1024 bits\n"
- " highest suggested keysize is 2048 bits\n"),
- gcry_pk_algo_name(algo) );
+ if (algo != PUBKEY_ALGO_DSA && algo != PUBKEY_ALGO_RSA) {
+ tty_printf (_("About to generate a new %s keypair.\n"
+ " minimum keysize is 768 bits\n"
+ " default keysize is 1024 bits\n"
+ " highest suggested keysize is 2048 bits\n"),
+ pubkey_algo_to_string(algo) );
+ }
+
for(;;) {
answer = cpr_get("keygen.size",
_("What keysize do you want? (1024) "));
cpr_kill_prompt();
nbits = *answer? atoi(answer): 1024;
- gcry_free(answer);
- if( algo == GCRY_PK_DSA && (nbits < 512 || nbits > 1024) )
+ m_free(answer);
+ if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
tty_printf(_("DSA only allows keysizes from 512 to 1024\n"));
- else if( nbits < 768 )
- tty_printf(_("keysize too small; 768 is smallest value allowed.\n"));
- else if( algo == GCRY_PK_RSA && nbits < 1024 )
+ else if( algo == PUBKEY_ALGO_RSA && nbits < 1024 )
tty_printf(_("keysize too small;"
" 1024 is smallest value allowed for RSA.\n"));
+ else if( nbits < 768 )
+ tty_printf(_("keysize too small;"
+ " 768 is smallest value allowed.\n"));
else if( nbits > 4096 ) {
/* It is ridiculous and an annoyance to use larger key sizes!
* GnuPG can handle much larger sizes; but it takes an eternity
@@ -731,16 +1053,11 @@ ask_keysize( int algo )
break;
}
}
- else if( nbits > 1536 && !cpr_enabled() && algo != GCRY_PK_RSA ) {
- if( cpr_get_answer_is_yes("keygen.size.large.okay",_(
- "Do you really need such a large keysize? ")) )
- break;
- }
else
break;
}
tty_printf(_("Requested keysize is %u bits\n"), nbits );
- if( algo == GCRY_PK_DSA && (nbits % 64) ) {
+ if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
nbits = ((nbits + 63) / 64) * 64;
tty_printf(_("rounded up to %u bits\n"), nbits );
}
@@ -786,20 +1103,38 @@ parse_expire_string( const char *string )
return valid_days;
}
-
-static u32
-ask_expire_interval(void)
+/* object == 0 for a key, and 1 for a sig */
+u32
+ask_expire_interval(int object)
{
char *answer;
int valid_days=0;
u32 interval = 0;
- tty_printf(_("Please specify how long the key should be valid.\n"
- " 0 = key does not expire\n"
- " <n> = key expires in n days\n"
- " <n>w = key expires in n weeks\n"
- " <n>m = key expires in n months\n"
- " <n>y = key expires in n years\n"));
+ switch(object)
+ {
+ case 0:
+ tty_printf(_("Please specify how long the key should be valid.\n"
+ " 0 = key does not expire\n"
+ " <n> = key expires in n days\n"
+ " <n>w = key expires in n weeks\n"
+ " <n>m = key expires in n months\n"
+ " <n>y = key expires in n years\n"));
+ break;
+
+ case 1:
+ tty_printf(_("Please specify how long the signature should be valid.\n"
+ " 0 = signature does not expire\n"
+ " <n> = signature expires in n days\n"
+ " <n>w = signature expires in n weeks\n"
+ " <n>m = signature expires in n months\n"
+ " <n>y = signature expires in n years\n"));
+ break;
+
+ default:
+ BUG();
+ }
+
/* Note: The elgamal subkey for DSA has no expiration date because
* it must be signed with the DSA key and this one has the expiration
* date */
@@ -808,8 +1143,11 @@ ask_expire_interval(void)
for(;;) {
u32 curtime=make_timestamp();
- gcry_free(answer);
- answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
+ m_free(answer);
+ if(object==0)
+ answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
+ else
+ answer = cpr_get("siggen.valid",_("Signature is valid for? (0) "));
cpr_kill_prompt();
trim_spaces(answer);
valid_days = parse_expire_string( answer );
@@ -819,14 +1157,18 @@ ask_expire_interval(void)
}
if( !valid_days ) {
- tty_printf(_("Key does not expire at all\n"));
+ tty_printf(_("%s does not expire at all\n"),
+ object==0?"Key":"Signature");
interval = 0;
}
else {
interval = valid_days * 86400L;
/* print the date when the key expires */
- tty_printf(_("Key expires at %s\n"),
+ tty_printf(_("%s expires at %s\n"),
+ object==0?"Key":"Signature",
asctimestamp((ulong)(curtime + interval) ) );
+ /* FIXME: This check yields warning on alhas:
+ write a configure check and to this check here only for 32 bit machines */
if( (time_t)((ulong)(curtime+interval)) < 0 )
tty_printf(_("Your system can't display dates beyond 2038.\n"
"However, it will be correctly handled up to 2106.\n"));
@@ -836,14 +1178,14 @@ ask_expire_interval(void)
_("Is this correct (y/n)? ")) )
break;
}
- gcry_free(answer);
+ m_free(answer);
return interval;
}
u32
ask_expiredate()
{
- u32 x = ask_expire_interval();
+ u32 x = ask_expire_interval(0);
return x? make_timestamp() + x : 0;
}
@@ -887,7 +1229,7 @@ ask_user_id( int mode )
if( !aname ) {
for(;;) {
- gcry_free(aname);
+ m_free(aname);
aname = cpr_get("keygen.name",_("Real name: "));
trim_spaces(aname);
cpr_kill_prompt();
@@ -907,7 +1249,7 @@ ask_user_id( int mode )
}
if( !amail ) {
for(;;) {
- gcry_free(amail);
+ m_free(amail);
amail = cpr_get("keygen.email",_("Email address: "));
trim_spaces(amail);
cpr_kill_prompt();
@@ -926,7 +1268,7 @@ ask_user_id( int mode )
}
if( !acomment ) {
for(;;) {
- gcry_free(acomment);
+ m_free(acomment);
acomment = cpr_get("keygen.comment",_("Comment: "));
trim_spaces(acomment);
cpr_kill_prompt();
@@ -940,8 +1282,8 @@ ask_user_id( int mode )
}
- gcry_free(uid);
- uid = p = gcry_xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
+ m_free(uid);
+ uid = p = m_alloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
p = stpcpy(p, aname );
if( *acomment )
p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
@@ -950,10 +1292,8 @@ ask_user_id( int mode )
/* append a warning if we do not have dev/random
* or it is switched into quick testmode */
- #if 0
if( quick_random_gen(-1) )
strcpy(p, " (INSECURE!)" );
- #endif
/* print a note in case that UTF8 mapping has to be done */
for(p=uid; *p; p++ ) {
@@ -973,12 +1313,12 @@ ask_user_id( int mode )
}
for(;;) {
- char *ansstr = _("NnCcEeOoQq");
+ const char *ansstr = _("NnCcEeOoQq");
if( strlen(ansstr) != 10 )
BUG();
if( cpr_enabled() ) {
- answer = gcry_xstrdup(ansstr+6);
+ answer = m_strdup(ansstr+6);
answer[1] = 0;
}
else {
@@ -990,15 +1330,15 @@ ask_user_id( int mode )
if( strlen(answer) > 1 )
;
else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
- gcry_free(aname); aname = NULL;
+ m_free(aname); aname = NULL;
break;
}
else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
- gcry_free(acomment); acomment = NULL;
+ m_free(acomment); acomment = NULL;
break;
}
else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
- gcry_free(amail); amail = NULL;
+ m_free(amail); amail = NULL;
break;
}
else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
@@ -1006,29 +1346,29 @@ ask_user_id( int mode )
tty_printf(_("Please correct the error first\n"));
}
else {
- gcry_free(aname); aname = NULL;
- gcry_free(acomment); acomment = NULL;
- gcry_free(amail); amail = NULL;
+ m_free(aname); aname = NULL;
+ m_free(acomment); acomment = NULL;
+ m_free(amail); amail = NULL;
break;
}
}
else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
- gcry_free(aname); aname = NULL;
- gcry_free(acomment); acomment = NULL;
- gcry_free(amail); amail = NULL;
- gcry_free(uid); uid = NULL;
+ m_free(aname); aname = NULL;
+ m_free(acomment); acomment = NULL;
+ m_free(amail); amail = NULL;
+ m_free(uid); uid = NULL;
break;
}
- gcry_free(answer);
+ m_free(answer);
}
- gcry_free(answer);
+ m_free(answer);
if( !amail && !acomment && !amail )
break;
- gcry_free(uid); uid = NULL;
+ m_free(uid); uid = NULL;
}
if( uid ) {
char *p = native_to_utf8( uid );
- gcry_free( uid );
+ m_free( uid );
uid = p;
}
return uid;
@@ -1040,20 +1380,22 @@ ask_passphrase( STRING2KEY **ret_s2k )
{
DEK *dek = NULL;
STRING2KEY *s2k;
+ const char *errtext = NULL;
tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
for(;;) {
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,errtext);
if( !dek ) {
- tty_printf(_("passphrase not correctly repeated; try again.\n"));
+ errtext = _("passphrase not correctly repeated; try again");
+ tty_printf(_("%s.\n"), errtext);
}
else if( !dek->keylen ) {
- gcry_free(dek); dek = NULL;
- gcry_free(s2k); s2k = NULL;
+ m_free(dek); dek = NULL;
+ m_free(s2k); s2k = NULL;
tty_printf(_(
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
@@ -1069,7 +1411,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
static int
-do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
+do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate )
{
int rc=0;
@@ -1081,14 +1423,12 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
"disks) during the prime generation; this gives the random number\n"
"generator a better chance to gain enough entropy.\n") );
- if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E )
+ if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E )
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- else if( algo == GCRY_PK_DSA )
+ else if( algo == PUBKEY_ALGO_DSA )
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- #if 0
- else if( algo == GCRY_PK_RSA )
+ else if( algo == PUBKEY_ALGO_RSA )
rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- #endif
else
BUG();
@@ -1120,9 +1460,10 @@ generate_user_id()
if( !p )
return NULL;
n = strlen(p);
- uid = gcry_xcalloc( 1, sizeof *uid + n - 1 );
+ uid = m_alloc_clear( sizeof *uid + n - 1 );
uid->len = n;
strcpy(uid->name, p);
+ uid->ref = 1;
return uid;
}
@@ -1135,11 +1476,11 @@ release_parameter_list( struct para_data_s *r )
for( ; r ; r = r2 ) {
r2 = r->next;
if( r->key == pPASSPHRASE_DEK )
- gcry_free( r->u.dek );
+ m_free( r->u.dek );
else if( r->key == pPASSPHRASE_S2K )
- gcry_free( r->u.s2k );
+ m_free( r->u.s2k );
- gcry_free(r);
+ m_free(r);
}
}
@@ -1163,12 +1504,102 @@ get_parameter_value( struct para_data_s *para, enum para_name key )
static int
get_parameter_algo( struct para_data_s *para, enum para_name key )
{
+ int i;
struct para_data_s *r = get_parameter( para, key );
if( !r )
return -1;
if( isdigit( *r->u.value ) )
- return atoi( r->u.value );
- return gcry_pk_map_name( r->u.value );
+ i = atoi( r->u.value );
+ else
+ i = string_to_pubkey_algo( r->u.value );
+ if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
+ i = 0; /* we don't want to allow generation of these algorithms */
+ return i;
+}
+
+/*
+ * parse the usage parameter and set the keyflags. Return true on error.
+ */
+static int
+parse_parameter_usage (const char *fname,
+ struct para_data_s *para, enum para_name key)
+{
+ struct para_data_s *r = get_parameter( para, key );
+ char *p, *pn;
+ unsigned int use;
+
+ if( !r )
+ return 0; /* none (this is an optional parameter)*/
+
+ use = 0;
+ pn = r->u.value;
+ while ( (p = strsep (&pn, " \t,")) ) {
+ if ( !*p)
+ ;
+ else if ( !ascii_strcasecmp (p, "sign") )
+ use |= PUBKEY_USAGE_SIG;
+ else if ( !ascii_strcasecmp (p, "encrypt") )
+ use |= PUBKEY_USAGE_ENC;
+ else {
+ log_error("%s:%d: invalid usage list\n", fname, r->lnr );
+ return -1; /* error */
+ }
+ }
+ r->u.usage = use;
+ return 0;
+}
+
+static int
+parse_revocation_key (const char *fname,
+ struct para_data_s *para, enum para_name key)
+{
+ struct para_data_s *r = get_parameter( para, key );
+ struct revocation_key revkey;
+ char *pn;
+ int i;
+
+ if( !r )
+ return 0; /* none (this is an optional parameter) */
+
+ pn = r->u.value;
+
+ revkey.class=0x80;
+ revkey.algid=atoi(pn);
+ if(!revkey.algid)
+ goto fail;
+
+ /* Skip to the fpr */
+ while(*pn && *pn!=':')
+ pn++;
+
+ if(*pn!=':')
+ goto fail;
+
+ pn++;
+
+ for(i=0;i<MAX_FINGERPRINT_LEN && *pn;i++,pn+=2)
+ {
+ int c=hextobyte(pn);
+ if(c==-1)
+ goto fail;
+
+ revkey.fpr[i]=c;
+ }
+
+ /* skip to the tag */
+ while(*pn && *pn!='s' && *pn!='S')
+ pn++;
+
+ if(ascii_strcasecmp(pn,"sensitive")==0)
+ revkey.class|=0x40;
+
+ memcpy(&r->u.revkey,&revkey,sizeof(struct revocation_key));
+
+ return 0;
+
+ fail:
+ log_error("%s:%d: invalid revocation key\n", fname, r->lnr );
+ return -1; /* error */
}
@@ -1181,6 +1612,8 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
return 0;
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
return r->u.expire;
+ if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
+ return r->u.usage;
return (unsigned int)strtoul( r->u.value, NULL, 10 );
}
@@ -1205,10 +1638,16 @@ get_parameter_s2k( struct para_data_s *para, enum para_name key )
return r? r->u.s2k : NULL;
}
+static struct revocation_key *
+get_parameter_revkey( struct para_data_s *para, enum para_name key )
+{
+ struct para_data_s *r = get_parameter( para, key );
+ return r? &r->u.revkey : NULL;
+}
static int
proc_parameter_file( struct para_data_s *para, const char *fname,
- struct output_control_s *outctrl )
+ struct output_control_s *outctrl )
{
struct para_data_s *r;
const char *s1, *s2, *s3;
@@ -1219,18 +1658,24 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
/* check that we have all required parameters */
assert( get_parameter( para, pKEYTYPE ) );
i = get_parameter_algo( para, pKEYTYPE );
- if( i < 1 || openpgp_pk_test_algo( i, GCRY_PK_USAGE_SIGN ) ) {
+ if( i < 1 || check_pubkey_algo2( i, PUBKEY_USAGE_SIG ) ) {
r = get_parameter( para, pKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
+ if (parse_parameter_usage (fname, para, pKEYUSAGE))
+ return -1;
+
i = get_parameter_algo( para, pSUBKEYTYPE );
- if( i > 1 && openpgp_pk_test_algo( i, 0 ) ) {
+ if( i > 0 && check_pubkey_algo( i ) ) {
r = get_parameter( para, pSUBKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
+ if (i > 0 && parse_parameter_usage (fname, para, pSUBKEYUSAGE))
+ return -1;
+
if( !get_parameter_value( para, pUSERID ) ) {
/* create the formatted user ID */
@@ -1239,7 +1684,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
s3 = get_parameter_value( para, pNAMEEMAIL );
if( s1 || s2 || s3 ) {
n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0);
- r = gcry_xcalloc( 1, sizeof *r + n + 20 );
+ r = m_alloc_clear( sizeof *r + n + 20 );
r->key = pUSERID;
p = r->u.value;
if( s1 )
@@ -1253,6 +1698,13 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
}
}
+ /* Set preferences, if any. */
+ keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0);
+
+ /* Set revoker, if any. */
+ if (parse_revocation_key (fname, para, pREVOKER))
+ return -1;
+
/* make DEK and S2K from the Passphrase */
r = get_parameter( para, pPASSPHRASE );
if( r && *r->u.value ) {
@@ -1262,21 +1714,21 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
STRING2KEY *s2k;
DEK *dek;
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
set_next_passphrase( r->u.value );
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL );
set_next_passphrase( NULL );
assert( dek );
memset( r->u.value, 0, strlen(r->u.value) );
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
@@ -1294,7 +1746,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
r->u.expire = i * 86400L;
r->key = pKEYEXPIRE; /* change hat entry */
/* also set it for the subkey */
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = i * 86400L;
r->next = para;
@@ -1324,13 +1776,17 @@ read_parameter_file( const char *fname )
} keywords[] = {
{ "Key-Type", pKEYTYPE},
{ "Key-Length", pKEYLENGTH },
+ { "Key-Usage", pKEYUSAGE },
{ "Subkey-Type", pSUBKEYTYPE },
{ "Subkey-Length", pSUBKEYLENGTH },
+ { "Subkey-Usage", pSUBKEYUSAGE },
{ "Name-Real", pNAMEREAL },
{ "Name-Email", pNAMEEMAIL },
{ "Name-Comment", pNAMECOMMENT },
{ "Expire-Date", pEXPIREDATE },
{ "Passphrase", pPASSPHRASE },
+ { "Preferences", pPREFERENCES },
+ { "Revoker", pREVOKER },
{ NULL, 0 }
};
FILE *fp;
@@ -1366,45 +1822,45 @@ read_parameter_file( const char *fname )
err = "line too long";
break;
}
- for( p = line; isspace(*p); p++ )
+ for( p = line; isspace(*(byte*)p); p++ )
;
if( !*p || *p == '#' )
continue;
keyword = p;
if( *keyword == '%' ) {
- for( ; !isspace(*p); p++ )
+ for( ; !isspace(*(byte*)p); p++ )
;
if( *p )
*p++ = 0;
- for( ; isspace(*p); p++ )
+ for( ; isspace(*(byte*)p); p++ )
;
value = p;
trim_trailing_ws( value, strlen(value) );
- if( !stricmp( keyword, "%echo" ) )
+ if( !ascii_strcasecmp( keyword, "%echo" ) )
log_info("%s\n", value );
- else if( !stricmp( keyword, "%dry-run" ) )
+ else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
outctrl.dryrun = 1;
- else if( !stricmp( keyword, "%commit" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
outctrl.lnr = lnr;
proc_parameter_file( para, fname, &outctrl );
release_parameter_list( para );
para = NULL;
}
- else if( !stricmp( keyword, "%pubring" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%pubring" ) ) {
if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
; /* still the same file - ignore it */
else {
- gcry_free( outctrl.pub.newfname );
- outctrl.pub.newfname = gcry_xstrdup( value );
+ m_free( outctrl.pub.newfname );
+ outctrl.pub.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
- else if( !stricmp( keyword, "%secring" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%secring" ) ) {
if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
; /* still the same file - ignore it */
else {
- gcry_free( outctrl.sec.newfname );
- outctrl.sec.newfname = gcry_xstrdup( value );
+ m_free( outctrl.sec.newfname );
+ outctrl.sec.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
@@ -1422,7 +1878,7 @@ read_parameter_file( const char *fname )
}
if( *p )
*p++ = 0;
- for( ; isspace(*p); p++ )
+ for( ; isspace(*(byte*)p); p++ )
;
if( !*p ) {
err = "missing argument";
@@ -1432,7 +1888,7 @@ read_parameter_file( const char *fname )
trim_trailing_ws( value, strlen(value) );
for(i=0; keywords[i].name; i++ ) {
- if( !stricmp( keywords[i].name, keyword ) )
+ if( !ascii_strcasecmp( keywords[i].name, keyword ) )
break;
}
if( !keywords[i].name ) {
@@ -1460,7 +1916,7 @@ read_parameter_file( const char *fname )
break;
}
}
- r = gcry_xcalloc( 1, sizeof *r + strlen( value ) );
+ r = m_alloc_clear( sizeof *r + strlen( value ) );
r->lnr = lnr;
r->key = keywords[i].key;
strcpy( r->u.value, value );
@@ -1480,10 +1936,10 @@ read_parameter_file( const char *fname )
if( outctrl.use_files ) { /* close open streams */
iobuf_close( outctrl.pub.stream );
iobuf_close( outctrl.sec.stream );
- gcry_free( outctrl.pub.fname );
- gcry_free( outctrl.pub.newfname );
- gcry_free( outctrl.sec.fname );
- gcry_free( outctrl.sec.newfname );
+ m_free( outctrl.pub.fname );
+ m_free( outctrl.pub.newfname );
+ m_free( outctrl.sec.fname );
+ m_free( outctrl.sec.newfname );
}
release_parameter_list( para );
@@ -1504,6 +1960,7 @@ generate_keypair( const char *fname )
DEK *dek;
STRING2KEY *s2k;
int algo;
+ unsigned int use;
int both = 0;
u32 expire;
struct para_data_s *para = NULL;
@@ -1517,50 +1974,61 @@ generate_keypair( const char *fname )
return;
}
- algo = ask_algo( 0 );
+ algo = ask_algo( 0, &use );
if( !algo ) { /* default: DSA with ElG subkey of the specified size */
both = 1;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", GCRY_PK_DSA );
+ sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
r->next = para;
para = r;
tty_printf(_("DSA keypair will have 1024 bits.\n"));
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
strcpy( r->u.value, "1024" );
r->next = para;
para = r;
- algo = GCRY_PK_ELG_E;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ algo = PUBKEY_ALGO_ELGAMAL_E;
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
}
else {
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
+
+ if (use) {
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ sprintf( r->u.value, "%s%s",
+ (use & PUBKEY_USAGE_SIG)? "sign ":"",
+ (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+ r->next = para;
+ para = r;
+ }
+
}
nbits = ask_keysize( algo );
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
sprintf( r->u.value, "%u", nbits);
r->next = para;
para = r;
- expire = ask_expire_interval();
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ expire = ask_expire_interval(0);
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYEXPIRE;
r->u.expire = expire;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = expire;
r->next = para;
@@ -1572,7 +2040,7 @@ generate_keypair( const char *fname )
release_parameter_list( para );
return;
}
- r = gcry_xcalloc( 1, sizeof *r + strlen(uid) );
+ r = m_alloc_clear( sizeof *r + strlen(uid) );
r->key = pUSERID;
strcpy( r->u.value, uid );
r->next = para;
@@ -1580,12 +2048,12 @@ generate_keypair( const char *fname )
dek = ask_passphrase( &s2k );
if( dek ) {
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
@@ -1601,13 +2069,13 @@ static void
do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl )
{
- char *pub_fname = NULL;
- char *sec_fname = NULL;
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
PKT_secret_key *sk = NULL;
const char *s;
+ struct revocation_key *revkey;
int rc;
+ int did_sub = 0;
if( outctrl->dryrun ) {
log_info("dry-run mode - key generation skipped\n");
@@ -1619,7 +2087,7 @@ do_generate_keypair( struct para_data_s *para,
if( outctrl->pub.newfname ) {
iobuf_close(outctrl->pub.stream);
outctrl->pub.stream = NULL;
- gcry_free( outctrl->pub.fname );
+ m_free( outctrl->pub.fname );
outctrl->pub.fname = outctrl->pub.newfname;
outctrl->pub.newfname = NULL;
@@ -1638,7 +2106,7 @@ do_generate_keypair( struct para_data_s *para,
if( outctrl->sec.newfname ) {
iobuf_close(outctrl->sec.stream);
outctrl->sec.stream = NULL;
- gcry_free( outctrl->sec.fname );
+ m_free( outctrl->sec.fname );
outctrl->sec.fname = outctrl->sec.newfname;
outctrl->sec.newfname = NULL;
@@ -1654,20 +2122,14 @@ do_generate_keypair( struct para_data_s *para,
&outctrl->sec.afx );
}
}
- pub_fname = outctrl->pub.fname; /* only for info output */
- sec_fname = outctrl->sec.fname; /* only for info output */
assert( outctrl->pub.stream );
assert( outctrl->sec.stream );
- }
- else {
- pub_fname = get_writable_keyblock_file( 0 );
- sec_fname = get_writable_keyblock_file( 1 );
+ if( opt.verbose ) {
+ log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
+ log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
+ }
}
- if( opt.verbose ) {
- log_info(_("writing public key to `%s'\n"), pub_fname );
- log_info(_("writing secret key to `%s'\n"), sec_fname );
- }
/* we create the packets as a tree of kbnodes. Because the structure
* we create is known in advance we simply generate a linked list
@@ -1684,14 +2146,24 @@ do_generate_keypair( struct para_data_s *para,
get_parameter_s2k( para, pPASSPHRASE_S2K ),
&sk,
get_parameter_u32( para, pKEYEXPIRE ) );
+
+ if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
+ {
+ rc=write_direct_sig(pub_root,pub_root,sk,revkey);
+ if(!rc)
+ write_direct_sig(sec_root,pub_root,sk,revkey);
+ }
+
if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
write_uid(pub_root, s );
if( !rc )
write_uid(sec_root, s );
if( !rc )
- rc = write_selfsig(pub_root, pub_root, sk);
+ rc = write_selfsig(pub_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
if( !rc )
- rc = write_selfsig(sec_root, pub_root, sk);
+ rc = write_selfsig(sec_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
}
if( get_parameter( para, pSUBKEYTYPE ) ) {
@@ -1703,64 +2175,90 @@ do_generate_keypair( struct para_data_s *para,
NULL,
get_parameter_u32( para, pSUBKEYEXPIRE ) );
if( !rc )
- rc = write_keybinding(pub_root, pub_root, sk);
+ rc = write_keybinding(pub_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
if( !rc )
- rc = write_keybinding(sec_root, pub_root, sk);
+ rc = write_keybinding(sec_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
+ did_sub = 1;
}
if( !rc && outctrl->use_files ) { /* direct write to specified files */
rc = write_keyblock( outctrl->pub.stream, pub_root );
if( rc )
- log_error("can't write public key: %s\n", gpg_errstr(rc) );
+ log_error("can't write public key: %s\n", g10_errstr(rc) );
if( !rc ) {
rc = write_keyblock( outctrl->sec.stream, sec_root );
if( rc )
- log_error("can't write secret key: %s\n", gpg_errstr(rc) );
+ log_error("can't write secret key: %s\n", g10_errstr(rc) );
}
}
else if( !rc ) { /* write to the standard keyrings */
- KBPOS pub_kbpos;
- KBPOS sec_kbpos;
- int rc1 = -1;
- int rc2 = -1;
-
- /* we can now write the certificates */
- if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- if( add_keyblock_resource( pub_fname, 1, 0 ) ) {
- log_error("can add keyblock file `%s'\n", pub_fname );
- rc = GPGERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", pub_fname );
- rc = GPGERR_CREATE_FILE;
- }
- }
- if( rc )
- ;
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- if( add_keyblock_resource( sec_fname, 1, 1 ) ) {
- log_error("can add keyblock file `%s'\n", sec_fname );
- rc = GPGERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", sec_fname );
- rc = GPGERR_CREATE_FILE;
- }
- }
+ KEYDB_HANDLE pub_hd = keydb_new (0);
+ KEYDB_HANDLE sec_hd = keydb_new (1);
+
+ /* FIXME: we may have to create the keyring first */
+ rc = keydb_locate_writable (pub_hd, NULL);
+ if (rc)
+ log_error (_("no writable public keyring found: %s\n"),
+ g10_errstr (rc));
+
+ if (!rc) {
+ rc = keydb_locate_writable (sec_hd, NULL);
+ if (rc)
+ log_error (_("no writable secret keyring found: %s\n"),
+ g10_errstr (rc));
+ }
+
+ if (!rc && opt.verbose) {
+ log_info(_("writing public key to `%s'\n"),
+ keydb_get_resource_name (pub_hd));
+ log_info(_("writing secret key to `%s'\n"),
+ keydb_get_resource_name (sec_hd));
+ }
+
+ if (!rc) {
+ rc = keydb_insert_keyblock (pub_hd, pub_root);
+ if (rc)
+ log_error (_("error writing public keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), g10_errstr(rc));
+ }
+
+ if (!rc) {
+ rc = keydb_insert_keyblock (sec_hd, sec_root);
+ if (rc)
+ log_error (_("error writing secret keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), g10_errstr(rc));
+ }
+
+ keydb_release (pub_hd);
+ keydb_release (sec_hd);
+
+ if (!rc) {
+ int no_enc_rsa =
+ get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
+ && get_parameter_uint( para, pKEYUSAGE )
+ && !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
+ PKT_public_key *pk = find_kbnode (pub_root,
+ PKT_PUBLIC_KEY)->pkt->pkt.public_key;
+
+ update_ownertrust (pk,
+ ((get_ownertrust (pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE ));
+
+ if (!opt.batch) {
+ tty_printf(_("public and secret key created and signed.\n") );
+ tty_printf(_("key marked as ultimately trusted.\n") );
+ tty_printf("\n");
+ list_keyblock(pub_root,0,1,NULL);
+ }
+
- if( rc )
- ;
- else if( (rc=insert_keyblock( pub_root )) )
- log_error("can't write public key: %s\n", gpg_errstr(rc) );
- else if( (rc=insert_keyblock( sec_root )) )
- log_error("can't write secret key: %s\n", gpg_errstr(rc) );
- else {
- if( !opt.batch )
- tty_printf(_("public and secret key created and signed.\n") );
if( !opt.batch
- && get_parameter_algo( para, pKEYTYPE ) == GCRY_PK_DSA
+ && ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
+ || no_enc_rsa )
&& !get_parameter( para, pSUBKEYTYPE ) )
{
tty_printf(_("Note that this key cannot be used for "
@@ -1769,23 +2267,21 @@ do_generate_keypair( struct para_data_s *para,
"secondary key for this purpose.\n") );
}
}
-
}
if( rc ) {
if( opt.batch )
- log_error("key generation failed: %s\n", gpg_errstr(rc) );
+ log_error("key generation failed: %s\n", g10_errstr(rc) );
else
- tty_printf(_("Key generation failed: %s\n"), gpg_errstr(rc) );
+ tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
+ }
+ else {
+ write_status_text (STATUS_KEY_CREATED, did_sub? "B":"P");
}
release_kbnode( pub_root );
release_kbnode( sec_root );
if( sk ) /* the unprotected secret key */
free_secret_key(sk);
- if( !outctrl->use_files ) {
- gcry_free(pub_fname);
- gcry_free(sec_fname);
- }
}
@@ -1800,6 +2296,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
int algo;
+ unsigned int use;
u32 expire;
unsigned nbits;
char *passphrase = NULL;
@@ -1825,16 +2322,21 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
: _("key has been created %lu seconds "
"in future (time warp or clock problem)\n"), d );
if( !opt.ignore_time_conflict ) {
- rc = GPGERR_TIME_CONFLICT;
+ rc = G10ERR_TIME_CONFLICT;
goto leave;
}
}
+ if (sk->version < 4) {
+ log_info (_("NOTE: creating subkeys for v3 keys "
+ "is not OpenPGP compliant\n"));
+ goto leave;
+ }
/* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) {
case -1:
- rc = GPGERR_PUBKEY_ALGO;
+ rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf("This key is not protected.\n");
@@ -1850,37 +2352,39 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
goto leave;
- algo = ask_algo( 1 );
+ algo = ask_algo( 1, &use );
assert(algo);
nbits = ask_keysize( algo );
- expire = ask_expire_interval();
+ expire = ask_expire_interval(0);
if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
_("Really create? ") ) )
goto leave;
if( passphrase ) {
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
set_next_passphrase( passphrase );
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL );
}
rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
dek, s2k, NULL, expire );
if( !rc )
- rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
- if( !rc )
- rc = write_keybinding(sec_keyblock, pub_keyblock, sk);
+ rc = write_keybinding(pub_keyblock, pub_keyblock, sk, use);
if( !rc )
+ rc = write_keybinding(sec_keyblock, pub_keyblock, sk, use);
+ if( !rc ) {
okay = 1;
+ write_status_text (STATUS_KEY_CREATED, "S");
+ }
leave:
if( rc )
- log_error(_("Key generation failed: %s\n"), gpg_errstr(rc) );
- gcry_free( passphrase );
- gcry_free( dek );
- gcry_free( s2k );
+ log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
+ m_free( passphrase );
+ m_free( dek );
+ m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk);
set_next_passphrase( NULL );
@@ -1897,10 +2401,9 @@ write_keyblock( IOBUF out, KBNODE node )
int rc = build_packet( out, node->pkt );
if( rc ) {
log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- return GPGERR_WRITE_FILE;
+ node->pkt->pkttype, g10_errstr(rc) );
+ return G10ERR_WRITE_FILE;
}
}
return 0;
}
-
diff --git a/g10/keyid.c b/g10/keyid.c
index 0269a6bb0..43e531e3e 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -1,5 +1,5 @@
-/* keyid.c - jeyid and fingerprint handling
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* keyid.c - key ID and fingerprint handling
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,12 +25,11 @@
#include <errno.h>
#include <time.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
#include "main.h"
#include "packet.h"
#include "options.h"
+#include "mpi.h"
#include "keydb.h"
#include "i18n.h"
@@ -39,58 +38,48 @@ int
pubkey_letter( int algo )
{
switch( algo ) {
- case GCRY_PK_RSA: return 'R' ;
- case GCRY_PK_RSA_E: return 'r' ;
- case GCRY_PK_RSA_S: return 's' ;
- case GCRY_PK_ELG_E: return 'g';
- case GCRY_PK_ELG: return 'G' ;
- case GCRY_PK_DSA: return 'D' ;
+ case PUBKEY_ALGO_RSA: return 'R' ;
+ case PUBKEY_ALGO_RSA_E: return 'r' ;
+ case PUBKEY_ALGO_RSA_S: return 's' ;
+ case PUBKEY_ALGO_ELGAMAL_E: return 'g';
+ case PUBKEY_ALGO_ELGAMAL: return 'G' ;
+ case PUBKEY_ALGO_DSA: return 'D' ;
default: return '?';
}
}
-
-static GCRY_MD_HD
+static MD_HANDLE
do_fingerprint_md( PKT_public_key *pk )
{
- GCRY_MD_HD md;
- unsigned int n;
- unsigned int nn[GNUPG_MAX_NPKEY];
- byte *pp[GNUPG_MAX_NPKEY];
+ MD_HANDLE md;
+ unsigned n;
+ unsigned nb[PUBKEY_MAX_NPKEY];
+ unsigned nn[PUBKEY_MAX_NPKEY];
+ byte *pp[PUBKEY_MAX_NPKEY];
int i;
int npkey = pubkey_get_npkey( pk->pubkey_algo );
- md = gcry_md_open( pk->version < 4 ? GCRY_MD_RMD160 : GCRY_MD_SHA1, 0);
- if( !md )
- BUG();
+ md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
n = pk->version < 4 ? 8 : 6;
for(i=0; i < npkey; i++ ) {
- int rc;
- size_t nbytes;
-
- rc = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, &nbytes, pk->pkey[i] );
- assert( !rc );
- /* fixme: we should try to allocate a buffer on the stack */
- pp[i] = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_PGP, pp[i], &nbytes, pk->pkey[i] );
- assert( !rc );
- nn[i] = nbytes;
- n += nn[i];
+ nb[i] = mpi_get_nbits(pk->pkey[i]);
+ pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
+ n += 2 + nn[i];
}
- gcry_md_putc( md, 0x99 ); /* ctb */
- gcry_md_putc( md, n >> 8 ); /* 2 byte length header */
- gcry_md_putc( md, n );
+ md_putc( md, 0x99 ); /* ctb */
+ md_putc( md, n >> 8 ); /* 2 byte length header */
+ md_putc( md, n );
if( pk->version < 4 )
- gcry_md_putc( md, 3 );
+ md_putc( md, 3 );
else
- gcry_md_putc( md, 4 );
+ md_putc( md, 4 );
{ u32 a = pk->timestamp;
- gcry_md_putc( md, a >> 24 );
- gcry_md_putc( md, a >> 16 );
- gcry_md_putc( md, a >> 8 );
- gcry_md_putc( md, a );
+ md_putc( md, a >> 24 );
+ md_putc( md, a >> 16 );
+ md_putc( md, a >> 8 );
+ md_putc( md, a );
}
if( pk->version < 4 ) {
u16 a;
@@ -99,20 +88,22 @@ do_fingerprint_md( PKT_public_key *pk )
a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
else
a = 0;
- gcry_md_putc( md, a >> 8 );
- gcry_md_putc( md, a );
+ md_putc( md, a >> 8 );
+ md_putc( md, a );
}
- gcry_md_putc( md, pk->pubkey_algo );
+ md_putc( md, pk->pubkey_algo );
for(i=0; i < npkey; i++ ) {
- gcry_md_write( md, pp[i], nn[i] );
- gcry_free(pp[i]);
+ md_putc( md, nb[i]>>8);
+ md_putc( md, nb[i] );
+ md_write( md, pp[i], nn[i] );
+ m_free(pp[i]);
}
- gcry_md_final( md );
+ md_final( md );
return md;
}
-static GCRY_MD_HD
+static MD_HANDLE
do_fingerprint_md_sk( PKT_secret_key *sk )
{
PKT_public_key pk;
@@ -130,30 +121,6 @@ do_fingerprint_md_sk( PKT_secret_key *sk )
}
-static void
-v3_keyid( MPI a, u32 *ki )
-{
- int rc;
- byte *buffer;
- size_t nbytes;
-
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, a );
- assert( !rc );
- /* fixme: allocate it on the stack */
- buffer = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, buffer, &nbytes, a );
- assert( !rc );
- if( nbytes < 8 ) { /* oops */
- ki[0] = ki[1] = 0;
- }
- else {
- memcpy( ki+0, buffer+nbytes-8, 4);
- memcpy( ki+1, buffer+nbytes-4, 4);
- }
- gcry_free( buffer );
-}
-
-
/****************
* Get the keyid from the secret key and put it into keyid
* if this is not NULL. Return the 32 low bits of the keyid.
@@ -161,36 +128,28 @@ v3_keyid( MPI a, u32 *ki )
u32
keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
{
+ u32 lowbits;
u32 dummy_keyid[2];
if( !keyid )
keyid = dummy_keyid;
- if( sk->keyid[0] || sk->keyid[1] ) {
- keyid[0] = sk->keyid[0];
- keyid[1] = sk->keyid[1];
- }
- else if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
- if( pubkey_get_npkey(sk->pubkey_algo) )
- v3_keyid( sk->skey[0], keyid ); /* take n */
- else
- keyid[0] = keyid[1] = 0;
- sk->keyid[0] = keyid[0];
- sk->keyid[1] = keyid[1];
+ if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
+ lowbits = pubkey_get_npkey(sk->pubkey_algo) ?
+ mpi_get_keyid( sk->skey[0], keyid ) : 0; /* take n */
}
else {
const byte *dp;
- GCRY_MD_HD md;
+ MD_HANDLE md;
md = do_fingerprint_md_sk(sk);
- dp = gcry_md_read( md, 0 );
+ dp = md_read( md, 0 );
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
- gcry_md_close(md);
- sk->keyid[0] = keyid[0];
- sk->keyid[1] = keyid[1];
+ lowbits = keyid[1];
+ md_close(md);
}
- return keyid[1];
+ return lowbits;
}
@@ -201,6 +160,7 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
u32
keyid_from_pk( PKT_public_key *pk, u32 *keyid )
{
+ u32 lowbits;
u32 dummy_keyid[2];
if( !keyid )
@@ -209,28 +169,28 @@ keyid_from_pk( PKT_public_key *pk, u32 *keyid )
if( pk->keyid[0] || pk->keyid[1] ) {
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
+ lowbits = keyid[1];
}
else if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
- if( pubkey_get_npkey(pk->pubkey_algo) )
- v3_keyid( pk->pkey[0], keyid ); /* from n */
- else
- keyid[0] = keyid[1] = 0;
+ lowbits = pubkey_get_npkey(pk->pubkey_algo) ?
+ mpi_get_keyid( pk->pkey[0], keyid ) : 0 ; /* from n */
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
else {
const byte *dp;
- GCRY_MD_HD md;
+ MD_HANDLE md;
md = do_fingerprint_md(pk);
- dp = gcry_md_read( md, 0 );
+ dp = md_read( md, 0 );
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
- gcry_md_close(md);
+ lowbits = keyid[1];
+ md_close(md);
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
- return keyid[1];
+ return lowbits;
}
@@ -299,6 +259,21 @@ nbits_from_sk( PKT_secret_key *sk )
return pubkey_nbits( sk->pubkey_algo, sk->skey );
}
+static const char *
+mk_datestr (char *buffer, time_t atime)
+{
+ struct tm *tp;
+
+ if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */
+ strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */
+ else {
+ tp = gmtime (&atime);
+ sprintf (buffer,"%04d-%02d-%02d",
+ 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
+ }
+ return buffer;
+}
+
/****************
* return a string with the creation date of the pk
* Note: this is alloced in a static buffer.
@@ -308,67 +283,122 @@ const char *
datestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
- struct tm *tp;
time_t atime = pk->timestamp;
- tp = gmtime( &atime );
- sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
- return buffer;
+ return mk_datestr (buffer, atime);
}
const char *
datestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
- struct tm *tp;
time_t atime = sk->timestamp;
- tp = gmtime( &atime );
- sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
- return buffer;
+ return mk_datestr (buffer, atime);
}
const char *
datestr_from_sig( PKT_signature *sig )
{
static char buffer[11+5];
- struct tm *tp;
time_t atime = sig->timestamp;
- tp = gmtime( &atime );
- sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
- return buffer;
+ return mk_datestr (buffer, atime);
}
-
const char *
expirestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
- struct tm *tp;
time_t atime;
if( !pk->expiredate )
return _("never ");
atime = pk->expiredate;
- tp = gmtime( &atime );
- sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
- return buffer;
+ return mk_datestr (buffer, atime);
}
const char *
expirestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
- struct tm *tp;
time_t atime;
if( !sk->expiredate )
return _("never ");
atime = sk->expiredate;
- tp = gmtime( &atime );
- sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
- return buffer;
+ return mk_datestr (buffer, atime);
+}
+
+const char *
+expirestr_from_sig( PKT_signature *sig )
+{
+ static char buffer[11+5];
+ time_t atime;
+
+ if(!sig->expiredate)
+ return _("never ");
+ atime=sig->expiredate;
+ return mk_datestr (buffer, atime);
+}
+
+const char *
+colon_strtime (u32 t)
+{
+ if (!t)
+ return "";
+ if (opt.fixed_list_mode) {
+ static char buf[15];
+ sprintf (buf, "%lu", (ulong)t);
+ return buf;
+ }
+ return strtimestamp(t);
+}
+
+const char *
+colon_datestr_from_pk (PKT_public_key *pk)
+{
+ if (opt.fixed_list_mode) {
+ static char buf[15];
+ sprintf (buf, "%lu", (ulong)pk->timestamp);
+ return buf;
+ }
+ return datestr_from_pk (pk);
+}
+
+const char *
+colon_datestr_from_sk (PKT_secret_key *sk)
+{
+ if (opt.fixed_list_mode) {
+ static char buf[15];
+ sprintf (buf, "%lu", (ulong)sk->timestamp);
+ return buf;
+ }
+ return datestr_from_sk (sk);
+}
+
+const char *
+colon_datestr_from_sig (PKT_signature *sig)
+{
+ if (opt.fixed_list_mode) {
+ static char buf[15];
+ sprintf (buf, "%lu", (ulong)sig->timestamp);
+ return buf;
+ }
+ return datestr_from_sig (sig);
+}
+
+const char *
+colon_expirestr_from_sig (PKT_signature *sig)
+{
+ if(!sig->expiredate)
+ return "";
+ if (opt.fixed_list_mode) {
+ static char buf[15];
+ sprintf (buf, "%lu", (ulong)sig->expiredate);
+ return buf;
+ }
+ return expirestr_from_sig (sig);
}
@@ -381,184 +411,92 @@ expirestr_from_sk( PKT_secret_key *sk )
byte *
fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
{
- byte *buf;
- const char *dp;
+ byte *p, *buf;
+ const byte *dp;
size_t len;
+ unsigned int n;
if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
/* RSA in version 3 packets is special */
- GCRY_MD_HD md;
+ MD_HANDLE md;
- md = gcry_md_open( GCRY_MD_MD5, 0);
- if( !md )
- BUG();
+ md = md_open( DIGEST_ALGO_MD5, 0);
if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) {
- int rc;
- size_t nbytes;
-
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, pk->pkey[0] );
- assert( !rc );
- /* fixme: allocate it on the stack */
- buf = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, buf, &nbytes, pk->pkey[0] );
- assert( !rc );
- gcry_md_write( md, buf, nbytes );
- gcry_free(buf);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, pk->pkey[1] );
- assert( !rc );
- /* fixme: allocate it on the stack */
- buf = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, buf, &nbytes, pk->pkey[1] );
- assert( !rc );
- gcry_md_write( md, buf, nbytes );
- gcry_free(buf);
+ p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL );
+ md_write( md, p, n );
+ m_free(buf);
+ p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL );
+ md_write( md, p, n );
+ m_free(buf);
}
- gcry_md_final(md);
+ md_final(md);
if( !array )
- array = gcry_xmalloc( 16 );
+ array = m_alloc( 16 );
len = 16;
- memcpy(array, gcry_md_read(md, GCRY_MD_MD5), 16 );
- gcry_md_close(md);
+ memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
+ md_close(md);
}
else {
- GCRY_MD_HD md;
+ MD_HANDLE md;
md = do_fingerprint_md(pk);
- dp = gcry_md_read( md, 0 );
- len = gcry_md_get_algo_dlen( gcry_md_get_algo( md ) );
+ dp = md_read( md, 0 );
+ len = md_digest_length( md_get_algo( md ) );
assert( len <= MAX_FINGERPRINT_LEN );
if( !array )
- array = gcry_xmalloc( len );
+ array = m_alloc( len );
memcpy(array, dp, len );
- gcry_md_close(md);
+ pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
+ pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
+ md_close(md);
}
*ret_len = len;
return array;
}
-
-/* Create a unified fingerprint, that is a printable fingerprint along
- * wth some other information suitable to passto get_pubkye_byname.
- * Pass NULL for buffer to let this function allocate the buffer.
- * This function will truncate the buffer in a way that a valid C string
- * is returnd (unless bufsize is 0)
- * Returns: Supplied buffer or newly allocated buffer
- */
-char *
-unified_fingerprint_from_pk( PKT_public_key *pk,
- char *buffer, size_t bufsize )
-{
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
- int i;
-
- fingerprint_from_pk( pk, fpr, &fprlen );
- if ( !buffer ) {
- bufsize = 1+fprlen*2+1+4+1+1;
- buffer = gcry_xmalloc( bufsize );
- }
- if ( bufsize < 1+fprlen*2+1+4+1+1 ) {
- /* Hmmm, that should be sufficiend also not very nice */
- if ( bufsize )
- *buffer = 0;
- return buffer;
- }
- *buffer = ':';
- for (i=0; i < fprlen; i++ )
- sprintf( buffer+1+i*2, "%02X", fpr[i] );
- sprintf( buffer+1+i*2, ":%d:", (pk->pubkey_algo & 0xff) );
- return buffer;
-}
-
byte *
fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len )
{
- byte *buf;
+ byte *p, *buf;
const char *dp;
size_t len;
+ unsigned n;
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
/* RSA in version 3 packets is special */
- GCRY_MD_HD md;
+ MD_HANDLE md;
- md = gcry_md_open( GCRY_MD_MD5, 0);
- if( !md )
- BUG();
+ md = md_open( DIGEST_ALGO_MD5, 0);
if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) {
- int rc;
- size_t nbytes;
-
- /* FIXME: Why is the hash sequence for secret keys different */
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, sk->skey[1] );
- assert( !rc );
- /* fixme: allocate it on the stack */
- buf = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, buf, &nbytes, sk->skey[1] );
- assert( !rc );
- gcry_md_write( md, buf, nbytes );
- gcry_free(buf);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, NULL, &nbytes, sk->skey[0] );
- assert( !rc );
- /* fixme: allocate it on the stack */
- buf = gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_USG, buf, &nbytes, sk->skey[0] );
- assert( !rc );
- gcry_md_write( md, buf, nbytes );
- gcry_free(buf);
+ p = buf = mpi_get_buffer( sk->skey[0], &n, NULL );
+ md_write( md, p, n );
+ m_free(buf);
+ p = buf = mpi_get_buffer( sk->skey[1], &n, NULL );
+ md_write( md, p, n );
+ m_free(buf);
}
- gcry_md_final(md);
+ md_final(md);
if( !array )
- array = gcry_xmalloc( 16 );
+ array = m_alloc( 16 );
len = 16;
- memcpy(array, gcry_md_read(md, GCRY_MD_MD5), 16 );
- gcry_md_close(md);
+ memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
+ md_close(md);
}
else {
- GCRY_MD_HD md;
+ MD_HANDLE md;
md = do_fingerprint_md_sk(sk);
- dp = gcry_md_read( md, 0 );
- len = gcry_md_get_algo_dlen( gcry_md_get_algo( md ) );
+ dp = md_read( md, 0 );
+ len = md_digest_length( md_get_algo( md ) );
assert( len <= MAX_FINGERPRINT_LEN );
if( !array )
- array = gcry_xmalloc( len );
+ array = m_alloc( len );
memcpy(array, dp, len );
- gcry_md_close(md);
+ md_close(md);
}
*ret_len = len;
return array;
}
-char *
-unified_fingerprint_from_sk( PKT_secret_key *sk,
- char *buffer, size_t bufsize )
-{
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
- int i;
-
- fingerprint_from_sk( sk, fpr, &fprlen );
- if ( !buffer ) {
- bufsize = 1+fprlen*2+1+4+1+1;
- buffer = gcry_xmalloc( bufsize );
- }
- if ( bufsize < 1+fprlen*2+1+4+1+1 ) {
- /* Hmmm, that should be sufficiend also not very nice */
- if ( bufsize )
- *buffer = 0;
- return buffer;
- }
- *buffer = ':';
- for (i=0; i < fprlen; i++ )
- sprintf( buffer+1+i*2, "%02X", fpr[i] );
- sprintf( buffer+1+i*2, ":%d:", (sk->pubkey_algo & 0xff) );
- return buffer;
-}
-
-
-
-
-
-
diff --git a/g10/keylist.c b/g10/keylist.c
index 89691873a..e226ee071 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -1,5 +1,5 @@
/* keylist.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,17 +29,26 @@
#include "packet.h"
#include "errors.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
+#include "photoid.h"
#include "util.h"
+#include "ttyio.h"
#include "trustdb.h"
#include "main.h"
#include "i18n.h"
+#include "status.h"
static void list_all(int);
static void list_one( STRLIST names, int secret);
-static void list_keyblock( KBNODE keyblock, int secret );
-static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk );
+struct sig_stats
+{
+ int inv_sigs;
+ int no_key;
+ int oth_err;
+};
+
+static FILE *attrib_fp=NULL;
/****************
* List the keys
@@ -63,123 +72,146 @@ secret_key_list( STRLIST list )
list_one( list, 1 );
}
+void
+show_policy_url(PKT_signature *sig,int indent)
+{
+ const byte *p;
+ size_t len;
+ int seq=0,crit;
+
+ while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&len,&seq,&crit)))
+ {
+ int i;
+
+ for(i=0;i<indent;i++)
+ putchar(' ');
+
+ /* This isn't UTF8 as it is a URL(?) */
+ if(crit)
+ printf(_("Critical signature policy: "));
+ else
+ printf(_("Signature policy: "));
+ print_string(stdout,p,len,0);
+ printf("\n");
+ }
+}
+
+void
+show_notation(PKT_signature *sig,int indent)
+{
+ const byte *p;
+ size_t len;
+ int seq=0,crit;
+
+ /* There may be multiple notations in the same sig. */
+
+ while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
+ if(len>=8)
+ {
+ int n1,n2,i;
+
+ n1=(p[4]<<8)|p[5];
+ n2=(p[6]<<8)|p[7];
+
+ if(8+n1+n2!=len)
+ {
+ log_info(_("WARNING: invalid notation data found\n"));
+ return;
+ }
+
+ for(i=0;i<indent;i++)
+ putchar(' ');
+
+ /* This is UTF8 */
+ if(crit)
+ printf(_("Critical signature notation: "));
+ else
+ printf(_("Signature notation: "));
+ print_utf8_string(stdout,p+8,n1);
+ printf("=");
+
+ if(*p&0x80)
+ print_utf8_string(stdout,p+8+n1,n2);
+ else
+ printf("[ %s ]",_("not human readable"));
+
+ printf("\n");
+ }
+ else
+ log_info(_("WARNING: invalid notation data found\n"));
+}
+
+static void
+print_signature_stats(struct sig_stats *s)
+{
+ if( s->inv_sigs == 1 )
+ tty_printf(_("1 bad signature\n") );
+ else if( s->inv_sigs )
+ tty_printf(_("%d bad signatures\n"), s->inv_sigs );
+ if( s->no_key == 1 )
+ tty_printf(_("1 signature not checked due to a missing key\n") );
+ else if( s->no_key )
+ tty_printf(_("%d signatures not checked due to missing keys\n"),s->no_key);
+ if( s->oth_err == 1 )
+ tty_printf(_("1 signature not checked due to an error\n") );
+ else if( s->oth_err )
+ tty_printf(_("%d signatures not checked due to errors\n"), s->oth_err );
+}
static void
list_all( int secret )
{
- KBPOS kbpos;
+ KEYDB_HANDLE hd;
KBNODE keyblock = NULL;
int rc=0;
- int lastresno;
+ const char *lastresname, *resname;
+ struct sig_stats stats;
+
+ memset(&stats,0,sizeof(stats));
- rc = enum_keyblocks_begin( &kbpos, secret );
+ hd = keydb_new (secret);
+ if (!hd)
+ rc = G10ERR_GENERAL;
+ else
+ rc = keydb_search_first (hd);
if( rc ) {
if( rc != -1 )
- log_error("enum_keyblocks(open) failed: %s\n", gpg_errstr(rc) );
+ log_error("keydb_search_first failed: %s\n", g10_errstr(rc) );
goto leave;
}
- lastresno = -1;
- while( !(rc = enum_keyblocks_next( kbpos, 1, &keyblock )) ) {
- if( 1 /*lastresno != kbpos.resno FIXME!!! */ ) {
- const char *s = "foo" /*keyblock_resource_name( &kbpos ) */;
+ lastresname = NULL;
+ do {
+ rc = keydb_get_keyblock (hd, &keyblock);
+ if (rc) {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ resname = keydb_get_resource_name (hd);
+ if (lastresname != resname ) {
int i;
- /* FIXME lastresno = kbpos.resno*/
- printf("%s\n", s );
- for(i=strlen(s); i; i-- )
+ printf("%s\n", resname );
+ for(i=strlen(resname); i; i-- )
putchar('-');
putchar('\n');
+ lastresname = resname;
}
- merge_keys_and_selfsig( keyblock );
- list_keyblock( keyblock, secret );
- release_kbnode( keyblock ); keyblock = NULL;
- }
-
+ merge_keys_and_selfsig( keyblock );
+ list_keyblock( keyblock, secret, opt.fingerprint,
+ opt.check_sigs?&stats:NULL);
+ release_kbnode( keyblock );
+ keyblock = NULL;
+ } while (!(rc = keydb_search_next (hd)));
if( rc && rc != -1 )
- log_error("enum_keyblocks(read) failed: %s\n", gpg_errstr(rc));
+ log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
- leave:
- enum_keyblocks_end( kbpos );
- release_kbnode( keyblock );
-}
+ if(opt.check_sigs && !opt.with_colons)
+ print_signature_stats(&stats);
-
-/****************
- * Check whether the user ID at NODE is valid; that is it has a
- * valid self-signature but no later valid revocation.
- * Caller has to pass the keyID of the primary in mainkey.
- * Returns: NULL = valid
- * string with the reason why it is invalid
- */
-static const char *
-is_uid_valid ( KBNODE keyblock, KBNODE uidnode, u32 *mainkid )
-{
- KBNODE node;
- PKT_signature *selfsig = NULL; /* the latest valid self signature */
-
- /* The key signature verify function can's handle secret keys yet and
- * becuase we are not sure whether the duplication of user IDs and
- * self-signatures should be kept on secret keys we are not going to fix
- * it there. */
- if ( keyblock->pkt->pkttype == PKT_SECRET_KEY )
- return NULL;
-
- assert ( uidnode->pkt->pkttype == PKT_USER_ID
- || uidnode->pkt->pkttype == PKT_PHOTO_ID );
-
- /* first find out about the latest valid self-signature */
- for ( node = uidnode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if ( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PHOTO_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
- || node->pkt->pkttype == PKT_SECRET_SUBKEY )
- break;
- if ( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
- sig = node->pkt->pkt.signature;
- if ( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if ( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
- if ( !check_key_signature( keyblock, node, NULL ) ) {
- if ( !selfsig )
- selfsig = sig; /* use the first valid sig */
- else if ( sig->timestamp > selfsig->timestamp
- && sig->sig_class >= selfsig->sig_class )
- selfsig = sig; /* but this one is newer */
- }
- }
- }
-
- if ( !selfsig )
- return _("invalid"); /* no valid self signature */
-
- /* watch out for a newer revocation */
- for ( node = uidnode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if ( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PHOTO_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
- || node->pkt->pkttype == PKT_SECRET_SUBKEY )
- break;
- if ( node->pkt->pkttype != PKT_SIGNATURE )
- continue;
- sig = node->pkt->pkt.signature;
- if ( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if ( sig->sig_class == 0x30
- && sig->timestamp >= selfsig->timestamp ) {
- if ( !check_key_signature( keyblock, node, NULL ) )
- return _("revoked");
- }
- }
-
- return NULL; /* UID is valid */
+ leave:
+ release_kbnode (keyblock);
+ keydb_release (hd);
}
@@ -189,17 +221,38 @@ list_one( STRLIST names, int secret )
int rc = 0;
KBNODE keyblock = NULL;
GETKEY_CTX ctx;
+ const char *resname;
+ char *keyring_str = N_("Keyring");
+ int i;
+ struct sig_stats stats;
+ memset(&stats,0,sizeof(stats));
+
+ /* fixme: using the bynames function has the disadvantage that we
+ * don't know wether one of the names given was not found. OTOH,
+ * this function has the advantage to list the names in the
+ * sequence as defined by the keyDB and does not duplicate
+ * outputs. A solution could be do test whether all given have
+ * been listed (this needs a way to use the keyDB search
+ * functions) or to have the search function return indicators for
+ * found names. Yet another way is to use the keydb search
+ * facilities directly. */
if( secret ) {
rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
if( rc ) {
- log_error("error reading key: %s\n", gpg_errstr(rc) );
+ log_error("error reading key: %s\n", g10_errstr(rc) );
get_seckey_end( ctx );
return;
}
do {
- merge_keys_and_selfsig( keyblock );
- list_keyblock( keyblock, 1 );
+ if (opt.show_keyring) {
+ resname = keydb_get_resource_name (get_ctx_handle(ctx));
+ printf("%s: %s\n", keyring_str, resname);
+ for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
+ putchar('-');
+ putchar('\n');
+ }
+ list_keyblock( keyblock, 1, opt.fingerprint, &stats );
release_kbnode( keyblock );
} while( !get_seckey_next( ctx, NULL, &keyblock ) );
get_seckey_end( ctx );
@@ -207,17 +260,27 @@ list_one( STRLIST names, int secret )
else {
rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
if( rc ) {
- log_error("error reading key: %s\n", gpg_errstr(rc) );
+ log_error("error reading key: %s\n", g10_errstr(rc) );
get_pubkey_end( ctx );
return;
}
do {
- merge_keys_and_selfsig( keyblock );
- list_keyblock( keyblock, 0 );
+ if (opt.show_keyring) {
+ resname = keydb_get_resource_name (get_ctx_handle(ctx));
+ printf("%s: %s\n", keyring_str, resname);
+ for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
+ putchar('-');
+ putchar('\n');
+ }
+ list_keyblock( keyblock, 0, opt.fingerprint,
+ opt.check_sigs?&stats:NULL );
release_kbnode( keyblock );
} while( !get_pubkey_next( ctx, NULL, &keyblock ) );
get_pubkey_end( ctx );
}
+
+ if(opt.check_sigs && !opt.with_colons)
+ print_signature_stats(&stats);
}
static void
@@ -227,16 +290,103 @@ print_key_data( PKT_public_key *pk, u32 *keyid )
int i;
for(i=0; i < n; i++ ) {
- printf("pkd:%d:%u:", i, gcry_mpi_get_nbits( pk->pkey[i] ) );
+ printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
mpi_print(stdout, pk->pkey[i], 1 );
putchar(':');
putchar('\n');
}
}
+static void
+print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
+{
+ unsigned int use = pk? pk->pubkey_usage : sk->pubkey_usage;
+
+ if ( use & PUBKEY_USAGE_ENC ) {
+ putchar ('e');
+ }
+ if ( use & PUBKEY_USAGE_SIG ) {
+ putchar ('s');
+ putchar ('c');
+ }
+ if ( keyblock ) { /* figure our the usable capabilities */
+ KBNODE k;
+ int enc=0, sign=0, cert=0;
+
+ for (k=keyblock; k; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ pk = k->pkt->pkt.public_key;
+ if ( pk->is_valid && !pk->is_revoked && !pk->has_expired ) {
+ if ( pk->pubkey_usage & PUBKEY_USAGE_ENC )
+ enc = 1;
+ if ( pk->pubkey_usage & PUBKEY_USAGE_SIG )
+ sign = cert = 1;
+ }
+ }
+ else if ( k->pkt->pkttype == PKT_SECRET_KEY
+ || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ sk = k->pkt->pkt.secret_key;
+ if ( sk->is_valid && !sk->is_revoked && !sk->has_expired ) {
+ if ( sk->pubkey_usage & PUBKEY_USAGE_ENC )
+ enc = 1;
+ if ( sk->pubkey_usage & PUBKEY_USAGE_SIG )
+ sign = cert = 1;
+ }
+ }
+ }
+ if (enc)
+ putchar ('E');
+ if (sign)
+ putchar ('S');
+ if (cert)
+ putchar ('C');
+ }
+ putchar(':');
+}
+
+static void dump_attribs(const PKT_user_id *uid,
+ PKT_public_key *pk,PKT_secret_key *sk)
+{
+ int i;
+
+ if(!attrib_fp)
+ BUG();
+
+ for(i=0;i<uid->numattribs;i++)
+ {
+ if(is_status_enabled())
+ {
+ byte array[MAX_FINGERPRINT_LEN], *p;
+ char buf[(MAX_FINGERPRINT_LEN*2)+90];
+ size_t j,n;
+
+ if(pk)
+ fingerprint_from_pk( pk, array, &n );
+ else if(sk)
+ fingerprint_from_sk( sk, array, &n );
+ else
+ BUG();
+
+ p = array;
+ for(j=0; j < n ; j++, p++ )
+ sprintf(buf+2*j, "%02X", *p );
+
+ sprintf(buf+strlen(buf)," %lu %u %u %u %lu %lu %u",
+ uid->attribs[i].len,uid->attribs[i].type,i+1,
+ uid->numattribs,(ulong)uid->created,(ulong)uid->expiredate,
+ ((uid->is_primary?0x01:0)|
+ (uid->is_revoked?0x02:0)|
+ (uid->is_expired?0x04:0)));
+ write_status_text(STATUS_ATTRIBUTE,buf);
+ }
+
+ fwrite(uid->attribs[i].data,uid->attribs[i].len,1,attrib_fp);
+ }
+}
static void
-list_keyblock( KBNODE keyblock, int secret )
+list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
{
int rc = 0;
KBNODE kbctx;
@@ -245,8 +395,7 @@ list_keyblock( KBNODE keyblock, int secret )
PKT_secret_key *sk;
u32 keyid[2];
int any=0;
- int trustletter = 0;
- int ulti_hack = 0;
+ struct sig_stats *stats=opaque;
/* get the keyid from the keyblock */
node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
@@ -260,16 +409,7 @@ list_keyblock( KBNODE keyblock, int secret )
pk = NULL;
sk = node->pkt->pkt.secret_key;
keyid_from_sk( sk, keyid );
- if( opt.with_colons )
- printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::",
- nbits_from_sk( sk ),
- sk->pubkey_algo,
- (ulong)keyid[0],(ulong)keyid[1],
- datestr_from_sk( sk ),
- sk->expiredate? strtimestamp(sk->expiredate):""
- /* fixme: add LID here */ );
- else
- printf("sec %4u%c/%08lX %s ", nbits_from_sk( sk ),
+ printf("sec %4u%c/%08lX %s ", nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
(ulong)keyid[1],
datestr_from_sk( sk ) );
@@ -278,80 +418,309 @@ list_keyblock( KBNODE keyblock, int secret )
pk = node->pkt->pkt.public_key;
sk = NULL;
keyid_from_pk( pk, keyid );
- if( opt.with_colons ) {
- if ( opt.fast_list_mode ) {
- fputs( "pub::", stdout );
- trustletter = 0;
+ printf("pub %4u%c/%08lX %s ", nbits_from_pk( pk ),
+ pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1],
+ datestr_from_pk( pk ) );
+ }
+
+ for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
+ if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
+ if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
+ dump_attribs(node->pkt->pkt.user_id,pk,sk);
+ /* don't list revoked UIDS unless we are in verbose mode and
+ * signature listing has not been requested */
+ if ( !opt.verbose && !opt.list_sigs
+ && node->pkt->pkt.user_id->is_revoked )
+ continue;
+
+ if( any )
+ printf("uid%*s", 28, "");
+
+ if ( node->pkt->pkt.user_id->is_revoked )
+ fputs ("[revoked] ", stdout);
+ if ( node->pkt->pkt.user_id->is_expired )
+ fputs ("[expired] ", stdout);
+ print_utf8_string( stdout, node->pkt->pkt.user_id->name,
+ node->pkt->pkt.user_id->len );
+ putchar('\n');
+ if( !any ) {
+ if( fpr )
+ print_fingerprint( pk, sk, 0 );
+ if( opt.with_key_data )
+ print_key_data( pk, keyid );
+ any = 1;
+ }
+
+ if(opt.show_photos && node->pkt->pkt.user_id->attribs!=NULL)
+ show_photos(node->pkt->pkt.user_id->attribs,
+ node->pkt->pkt.user_id->numattribs,pk,sk);
+ }
+ else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ u32 keyid2[2];
+ PKT_public_key *pk2 = node->pkt->pkt.public_key;
+
+ if( !any ) {
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 ); /* of the main key */
+ any = 1;
+ }
+
+ keyid_from_pk( pk2, keyid2 );
+ printf("sub %4u%c/%08lX %s", nbits_from_pk( pk2 ),
+ pubkey_letter( pk2->pubkey_algo ),
+ (ulong)keyid2[1],
+ datestr_from_pk( pk2 ) );
+ if( pk2->expiredate ) {
+ printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
+ }
+ putchar('\n');
+ if( fpr > 1 )
+ print_fingerprint( pk2, NULL, 0 );
+ if( opt.with_key_data )
+ print_key_data( pk2, keyid2 );
+ }
+ else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ u32 keyid2[2];
+ PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
+
+ if( !any ) {
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 ); /* of the main key */
+ any = 1;
+ }
+
+ keyid_from_sk( sk2, keyid2 );
+ printf("ssb %4u%c/%08lX %s\n", nbits_from_sk( sk2 ),
+ pubkey_letter( sk2->pubkey_algo ),
+ (ulong)keyid2[1],
+ datestr_from_sk( sk2 ) );
+ if( fpr > 1 )
+ print_fingerprint( NULL, sk2, 0 );
+ }
+ else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
+ PKT_signature *sig = node->pkt->pkt.signature;
+ int sigrc;
+ char *sigstr;
+
+ if( stats ) {
+ /*fflush(stdout);*/
+ rc = check_key_signature( keyblock, node, NULL );
+ switch( rc ) {
+ case 0: sigrc = '!'; break;
+ case G10ERR_BAD_SIGN: stats->inv_sigs++; sigrc = '-'; break;
+ case G10ERR_NO_PUBKEY:
+ case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
+ default: stats->oth_err++; sigrc = '%'; break;
+ }
}
else {
- trustletter = query_trust_info( pk, NULL );
- if( trustletter == 'u' )
- ulti_hack = 1;
- printf("pub:%c:", trustletter );
+ rc = 0;
+ sigrc = ' ';
}
- printf("%u:%d:%08lX%08lX:%s:%s:",
+
+ if( !any ) { /* no user id, (maybe a revocation follows)*/
+ /* Check if the pk is really revoked - there could be a
+ 0x20 sig packet there even if we are not revoked
+ (say, if a revocation key issued the packet, but the
+ revocation key isn't present to verify it.) */
+ if( sig->sig_class == 0x20 && pk->is_revoked )
+ puts("[revoked]");
+ else if( sig->sig_class == 0x18 )
+ puts("[key binding]");
+ else if( sig->sig_class == 0x28 )
+ puts("[subkey revoked]");
+ else
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 );
+ any=1;
+ }
+
+ if( sig->sig_class == 0x20 || sig->sig_class == 0x28
+ || sig->sig_class == 0x30 )
+ sigstr = "rev";
+ else if( (sig->sig_class&~3) == 0x10 )
+ sigstr = "sig";
+ else if( sig->sig_class == 0x18 )
+ sigstr = "sig";
+ else if( sig->sig_class == 0x1F )
+ sigstr = "sig";
+ else {
+ printf("sig "
+ "[unexpected signature class 0x%02x]\n",sig->sig_class );
+ continue;
+ }
+
+ fputs( sigstr, stdout );
+ printf("%c%c %c%c%c%c%c %08lX %s ",
+ sigrc,(sig->sig_class-0x10>0 &&
+ sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
+ sig->flags.exportable?' ':'L',
+ sig->flags.revocable?' ':'R',
+ sig->flags.policy_url?'P':' ',
+ sig->flags.notation?'N':' ',
+ sig->flags.expired?'X':' ',
+ (ulong)sig->keyid[1], datestr_from_sig(sig));
+ if( sigrc == '%' )
+ printf("[%s] ", g10_errstr(rc) );
+ else if( sigrc == '?' )
+ ;
+ else if ( !opt.fast_list_mode ) {
+ size_t n;
+ char *p = get_user_id( sig->keyid, &n );
+ print_utf8_string( stdout, p, n );
+ m_free(p);
+ }
+ putchar('\n');
+
+ if(sig->flags.policy_url && opt.show_policy_url)
+ show_policy_url(sig,3);
+
+ if(sig->flags.notation && opt.show_notation)
+ show_notation(sig,3);
+
+ /* fixme: check or list other sigs here */
+ }
+ }
+ putchar('\n');
+}
+
+
+static void
+list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
+{
+ int rc = 0;
+ KBNODE kbctx;
+ KBNODE node;
+ PKT_public_key *pk;
+ PKT_secret_key *sk;
+ u32 keyid[2];
+ int any=0;
+ int trustletter = 0;
+ int ulti_hack = 0;
+
+ /* get the keyid from the keyblock */
+ node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
+ if( !node ) {
+ log_error("Oops; key lost!\n");
+ dump_kbnode( keyblock );
+ return;
+ }
+
+ if( secret ) {
+ pk = NULL;
+ sk = node->pkt->pkt.secret_key;
+ keyid_from_sk( sk, keyid );
+ printf("sec:u:%u:%d:%08lX%08lX:%s:%s:::",
+ nbits_from_sk( sk ),
+ sk->pubkey_algo,
+ (ulong)keyid[0],(ulong)keyid[1],
+ colon_datestr_from_sk( sk ),
+ colon_strtime (sk->expiredate)
+ /* fixme: add LID here */ );
+ }
+ else {
+ pk = node->pkt->pkt.public_key;
+ sk = NULL;
+ keyid_from_pk( pk, keyid );
+ fputs( "pub:", stdout );
+ trustletter = 0;
+ if ( !pk->is_valid )
+ putchar ('i');
+ else if ( pk->is_revoked )
+ putchar ('r');
+ else if ( pk->has_expired )
+ putchar ('e');
+ else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
+ ;
+ else {
+ trustletter = get_validity_info ( pk, NULL );
+ if( trustletter == 'u' )
+ ulti_hack = 1;
+ putchar(trustletter);
+ }
+ printf(":%u:%d:%08lX%08lX:%s:%s:",
nbits_from_pk( pk ),
pk->pubkey_algo,
(ulong)keyid[0],(ulong)keyid[1],
- datestr_from_pk( pk ),
- pk->expiredate? strtimestamp(pk->expiredate):"" );
- if( pk->local_id )
- printf("%lu", pk->local_id );
+ colon_datestr_from_pk( pk ),
+ colon_strtime (pk->expiredate) );
+ if( pk->local_id )
+ printf("%lu", pk->local_id );
+ putchar(':');
+ if( !opt.fast_list_mode && !opt.no_expensive_trust_checks )
+ putchar( get_ownertrust_info(pk) );
putchar(':');
- if( pk->local_id && !opt.fast_list_mode )
- putchar( get_ownertrust_info( pk->local_id ) );
- putchar(':');
- }
- else
- printf("pub %4u%c/%08lX %s ", nbits_from_pk( pk ),
- pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1],
- datestr_from_pk( pk ) );
+ }
+
+ if (opt.fixed_list_mode) {
+ /* do not merge the first uid with the primary key */
+ putchar(':');
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 );
+ if( opt.with_key_data )
+ print_key_data( pk, keyid );
+ any = 1;
}
+
for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
+ if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
+ dump_attribs(node->pkt->pkt.user_id,pk,sk);
+ /*
+ * Fixme: We need a is_valid flag here too
+ */
if( any ) {
- if ( opt.with_colons ) {
+ char *str=node->pkt->pkt.user_id->attrib_data?"uat":"uid";
+ if ( node->pkt->pkt.user_id->is_revoked )
+ printf("%s:r::::::::",str);
+ else if ( node->pkt->pkt.user_id->is_expired )
+ printf("%s:e::::::::",str);
+ else if ( opt.no_expensive_trust_checks ) {
+ printf("%s:::::::::",str);
+ }
+ else {
byte namehash[20];
if( pk && !ulti_hack ) {
- if( node->pkt->pkt.user_id->photo ) {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+ if( node->pkt->pkt.user_id->attrib_data )
+ rmd160_hash_buffer( namehash,
+ node->pkt->pkt.user_id->attrib_data,
+ node->pkt->pkt.user_id->attrib_len);
+ else
+ rmd160_hash_buffer( namehash,
node->pkt->pkt.user_id->name,
node->pkt->pkt.user_id->len );
- }
- else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
- node->pkt->pkt.user_id->name,
- node->pkt->pkt.user_id->len );
- }
- trustletter = query_trust_info( pk, namehash );
+ trustletter = get_validity_info( pk, namehash );
}
else
trustletter = 'u';
- printf("uid:%c::::::::", trustletter);
- }
- else
- printf("uid%*s", 28, "");
- }
- if( opt.with_colons ) {
- print_string( stdout, node->pkt->pkt.user_id->name,
- node->pkt->pkt.user_id->len, ':' );
- putchar(':');
+ printf("%s:%c::::::::",str,trustletter);
+ }
}
- else {
- const char *s = is_uid_valid ( keyblock, node, keyid );
- if ( s )
- printf ("[%s] ", s );
- print_utf8_string( stdout, node->pkt->pkt.user_id->name,
- node->pkt->pkt.user_id->len );
- }
-
- putchar('\n');
- if( !any ) {
- if( opt.fingerprint )
- fingerprint( pk, sk );
+ if(node->pkt->pkt.user_id->attrib_data)
+ printf("%u %lu",
+ node->pkt->pkt.user_id->numattribs,
+ node->pkt->pkt.user_id->attrib_len);
+ else
+ print_string( stdout, node->pkt->pkt.user_id->name,
+ node->pkt->pkt.user_id->len, ':' );
+ putchar(':');
+ if (any)
+ putchar('\n');
+ else {
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 );
if( opt.with_key_data )
print_key_data( pk, keyid );
any = 1;
@@ -362,48 +731,46 @@ list_keyblock( KBNODE keyblock, int secret )
PKT_public_key *pk2 = node->pkt->pkt.public_key;
if( !any ) {
- putchar('\n');
- if( opt.fingerprint )
- fingerprint( pk, sk ); /* of the main key */
+ putchar(':');
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 ); /* of the main key */
any = 1;
}
-
-
keyid_from_pk( pk2, keyid2 );
- if( opt.with_colons ) {
- if ( opt.fast_list_mode ) {
- fputs( "sub::", stdout );
- }
- else {
- printf("sub:%c:", trustletter );
- }
- printf("%u:%d:%08lX%08lX:%s:%s:",
+ fputs ("sub:", stdout );
+ if ( !pk2->is_valid )
+ putchar ('i');
+ else if ( pk2->is_revoked )
+ putchar ('r');
+ else if ( pk2->has_expired )
+ putchar ('e');
+ else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
+ ;
+ else {
+ printf("%c", trustletter );
+ }
+ printf(":%u:%d:%08lX%08lX:%s:%s:",
nbits_from_pk( pk2 ),
pk2->pubkey_algo,
(ulong)keyid2[0],(ulong)keyid2[1],
- datestr_from_pk( pk2 ),
- pk2->expiredate? strtimestamp(pk2->expiredate):""
+ colon_datestr_from_pk( pk2 ),
+ colon_strtime (pk2->expiredate)
/* fixme: add LID and ownertrust here */
);
- if( pk->local_id ) /* use the local_id of the main key??? */
- printf("%lu", pk->local_id );
- putchar(':');
- putchar(':');
- putchar('\n');
- }
- else {
- printf("sub %4u%c/%08lX %s", nbits_from_pk( pk2 ),
- pubkey_letter( pk2->pubkey_algo ),
- (ulong)keyid2[1],
- datestr_from_pk( pk2 ) );
- if( pk2->expiredate ) {
- printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
- }
- putchar('\n');
- }
- if( opt.fingerprint > 1 )
- fingerprint( pk2, NULL );
+ if( pk->local_id ) /* use the local_id of the main key??? */
+ printf("%lu", pk->local_id );
+ putchar(':');
+ putchar(':');
+ putchar(':');
+ putchar(':');
+ print_capabilities (pk2, NULL, NULL);
+ putchar('\n');
+ if( fpr > 1 )
+ print_fingerprint( pk2, NULL, 0 );
if( opt.with_key_data )
print_key_data( pk2, keyid2 );
}
@@ -412,47 +779,47 @@ list_keyblock( KBNODE keyblock, int secret )
PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
if( !any ) {
+ putchar(':');
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
putchar('\n');
- if( opt.fingerprint )
- fingerprint( pk, sk ); /* of the main key */
+ if( fpr )
+ print_fingerprint( pk, sk, 0 ); /* of the main key */
any = 1;
}
keyid_from_sk( sk2, keyid2 );
- if( opt.with_colons )
- printf("ssb::%u:%d:%08lX%08lX:%s:%s:::\n",
+ printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
nbits_from_sk( sk2 ),
sk2->pubkey_algo,
(ulong)keyid2[0],(ulong)keyid2[1],
- datestr_from_sk( sk2 ),
- sk2->expiredate? strtimestamp(sk2->expiredate):""
- /* fixme: add LID */
- );
- else
- printf("ssb %4u%c/%08lX %s\n", nbits_from_sk( sk2 ),
- pubkey_letter( sk2->pubkey_algo ),
- (ulong)keyid2[1],
- datestr_from_sk( sk2 ) );
- if( opt.fingerprint > 1 )
- fingerprint( NULL, sk2 );
-
+ colon_datestr_from_sk( sk2 ),
+ colon_strtime (sk2->expiredate)
+ /* fixme: add LID */ );
+ print_capabilities (NULL, sk2, NULL);
+ putchar ('\n');
+ if( fpr > 1 )
+ print_fingerprint( NULL, sk2, 0 );
}
else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;
int sigrc;
- char *sigstr;
+ char *sigstr;
if( !any ) { /* no user id, (maybe a revocation follows)*/
if( sig->sig_class == 0x20 )
- puts("[revoked]");
+ fputs("[revoked]:", stdout);
else if( sig->sig_class == 0x18 )
- puts("[key binding]");
+ fputs("[key binding]:", stdout);
else if( sig->sig_class == 0x28 )
- puts("[subkey revoked]");
- else
- putchar('\n');
- if( opt.fingerprint )
- fingerprint( pk, sk );
+ fputs("[subkey revoked]:", stdout);
+ else
+ putchar (':');
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
+ putchar('\n');
+ if( fpr )
+ print_fingerprint( pk, sk, 0 );
any=1;
}
@@ -464,11 +831,8 @@ list_keyblock( KBNODE keyblock, int secret )
else if( sig->sig_class == 0x18 )
sigstr = "sig";
else {
- if( opt.with_colons )
- printf("sig::::::::::%02x:\n",sig->sig_class );
- else
- printf("sig "
- "[unexpected signature class 0x%02x]\n",sig->sig_class );
+ printf ("sig::::::::::%02x%c:\n",
+ sig->sig_class, sig->flags.exportable?'x':'l');
continue;
}
if( opt.check_sigs ) {
@@ -476,8 +840,9 @@ list_keyblock( KBNODE keyblock, int secret )
rc = check_key_signature( keyblock, node, NULL );
switch( rc ) {
case 0: sigrc = '!'; break;
- case GPGERR_BAD_SIGN: sigrc = '-'; break;
- case GPGERR_NO_PUBKEY: sigrc = '?'; break;
+ case G10ERR_BAD_SIGN: sigrc = '-'; break;
+ case G10ERR_NO_PUBKEY:
+ case G10ERR_UNU_PUBKEY: sigrc = '?'; break;
default: sigrc = '%'; break;
}
}
@@ -485,80 +850,191 @@ list_keyblock( KBNODE keyblock, int secret )
rc = 0;
sigrc = ' ';
}
- fputs( sigstr, stdout );
- if( opt.with_colons ) {
- putchar(':');
- if( sigrc != ' ' )
- putchar(sigrc);
- printf("::%d:%08lX%08lX:%s::::", sig->pubkey_algo,
+ fputs( sigstr, stdout );
+ putchar(':');
+ if( sigrc != ' ' )
+ putchar(sigrc);
+ printf("::%d:%08lX%08lX:%s:%s:::", sig->pubkey_algo,
(ulong)sig->keyid[0],
- (ulong)sig->keyid[1], datestr_from_sig(sig));
- }
- else
- printf("%c %08lX %s ",
- sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
+ (ulong)sig->keyid[1], colon_datestr_from_sig(sig),
+ colon_expirestr_from_sig(sig));
if( sigrc == '%' )
- printf("[%s] ", gpg_errstr(rc) );
+ printf("[%s] ", g10_errstr(rc) );
else if( sigrc == '?' )
;
else if ( !opt.fast_list_mode ) {
size_t n;
char *p = get_user_id( sig->keyid, &n );
- if( opt.with_colons )
- print_string( stdout, p, n, ':' );
- else
- print_utf8_string( stdout, p, n );
- gcry_free(p);
+ print_string( stdout, p, n, ':' );
+ m_free(p);
}
- if( opt.with_colons )
- printf(":%02x:", sig->sig_class );
- putchar('\n');
- /* FIXME: check or list other sigs here (subpkt PRIV_ADD_SIG)*/
+ printf(":%02x%c:\n", sig->sig_class,sig->flags.exportable?'x':'l');
+ /* fixme: check or list other sigs here */
}
}
if( !any ) {/* oops, no user id */
- if( opt.with_colons )
- putchar(':');
+ putchar(':');
+ putchar(':');
+ print_capabilities (pk, sk, keyblock);
putchar('\n');
}
- else if( !opt.with_colons )
- putchar('\n'); /* separator line */
}
+/*
+ * Reorder the keyblock so that the primary user ID (and not attribute
+ * packet) comes first. Fixme: Replace this by a generic sort
+ * function. */
+static void
+reorder_keyblock (KBNODE keyblock)
+{
+ KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
+ KBNODE last, node;
+
+ for (node=keyblock; node; primary0=node, node = node->next) {
+ if( node->pkt->pkttype == PKT_USER_ID &&
+ !node->pkt->pkt.user_id->attrib_data &&
+ node->pkt->pkt.user_id->is_primary ) {
+ primary = primary2 = node;
+ for (node=node->next; node; primary2=node, node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if ( !primary )
+ return; /* no primary key flag found (should not happen) */
+ for (last=NULL, node=keyblock; node; last = node, node = node->next) {
+ if( node->pkt->pkttype == PKT_USER_ID )
+ break;
+ }
+ assert (node);
+ assert (last); /* the user ID is never the first packet */
+ assert (primary0); /* ditto (this is the node before primary) */
+ if ( node == primary )
+ return; /* already the first one */
-static void
-fingerprint( PKT_public_key *pk, PKT_secret_key *sk )
+ last->next = primary;
+ primary0->next = primary2->next;
+ primary2->next = node;
+}
+
+void
+list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
{
- byte *array, *p;
+ reorder_keyblock (keyblock);
+ if (opt.with_colons)
+ list_keyblock_colon (keyblock, secret, fpr );
+ else
+ list_keyblock_print (keyblock, secret, fpr, opaque );
+}
+
+/*
+ * standard function to print the finperprint.
+ * mode 0: as used in key listings, opt.with_colons is honored
+ * 1: print using log_info ()
+ * 2: direct use of tty
+ */
+void
+print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
+{
+ byte array[MAX_FINGERPRINT_LEN], *p;
size_t i, n;
+ FILE *fp;
+ const char *text;
- p = array = pk? fingerprint_from_pk( pk, NULL, &n )
- : fingerprint_from_sk( sk, NULL, &n );
- if( opt.with_colons ) {
- printf("fpr:::::::::");
- for(i=0; i < n ; i++, p++ )
- printf("%02X", *p );
- putchar(':');
+ if (mode == 1) {
+ fp = log_stream ();
+ text = _("Fingerprint:");
+ }
+ else if (mode == 2) {
+ fp = NULL; /* use tty */
+ /* Translators: this should fit into 24 bytes to that the fingerprint
+ * data is properly aligned with the user ID */
+ text = _(" Fingerprint:");
}
else {
- printf(" Key fingerprint =");
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- putchar(' ');
- printf(" %02X%02X", *p, p[1] );
+ fp = stdout;
+ text = _(" Key fingerprint =");
+ }
+
+ if (sk)
+ fingerprint_from_sk (sk, array, &n);
+ else
+ fingerprint_from_pk (pk, array, &n);
+ p = array;
+ if (opt.with_colons && !mode) {
+ fprintf (fp, "fpr:::::::::");
+ for (i=0; i < n ; i++, p++ )
+ fprintf (fp, "%02X", *p );
+ putc(':', fp);
+ }
+ else {
+ if (fp)
+ fputs (text, fp);
+ else
+ tty_printf ("%s", text);
+ if (n == 20) {
+ for (i=0; i < n ; i++, i++, p += 2 ) {
+ if (fp) {
+ if (i == 10 )
+ putc(' ', fp);
+ fprintf (fp, " %02X%02X", *p, p[1] );
+ }
+ else {
+ if (i == 10 )
+ tty_printf (" ");
+ tty_printf (" %02X%02X", *p, p[1]);
+ }
}
}
else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- putchar(' ');
- printf(" %02X", *p );
+ for (i=0; i < n ; i++, p++ ) {
+ if (fp) {
+ if (i && !(i%8) )
+ putc (' ', fp);
+ fprintf (fp, " %02X", *p );
+ }
+ else {
+ if (i && !(i%8) )
+ tty_printf (" ");
+ tty_printf (" %02X", *p );
+ }
}
}
}
- putchar('\n');
- gcry_free(array);
+ if (fp)
+ putc ('\n', fp);
+ else
+ tty_printf ("\n");
}
+void set_attrib_fd(int fd)
+{
+ static int last_fd=-1;
+
+ if ( fd != -1 && last_fd == fd )
+ return;
+
+ if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
+ fclose (attrib_fp);
+ attrib_fp = NULL;
+ if ( fd == -1 )
+ return;
+
+ if( fd == 1 )
+ attrib_fp = stdout;
+ else if( fd == 2 )
+ attrib_fp = stderr;
+ else
+ attrib_fp = fdopen( fd, "w" );
+ if( !attrib_fp ) {
+ log_fatal("can't open fd %d for attribute output: %s\n",
+ fd, strerror(errno));
+ }
+ last_fd = fd;
+}
diff --git a/g10/keyring.c b/g10/keyring.c
new file mode 100644
index 000000000..f75a79dfe
--- /dev/null
+++ b/g10/keyring.c
@@ -0,0 +1,1550 @@
+/* keyring.c - keyring file handling
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "keyring.h"
+#include "packet.h"
+#include "keydb.h"
+#include "options.h"
+#include "main.h" /*for check_key_signature()*/
+#include "i18n.h"
+
+/* off_item is a funny named for an object used to keep track of known
+ * keys. The idea was to use the offset to seek to the known keyblock, but
+ * this is not possible if more than one process is using the keyring.
+ */
+struct off_item {
+ struct off_item *next;
+ u32 kid[2];
+ /*off_t off;*/
+};
+
+typedef struct off_item **OffsetHashTable;
+
+
+typedef struct keyring_name *KR_NAME;
+struct keyring_name {
+ struct keyring_name *next;
+ int secret;
+ DOTLOCK lockhd;
+ int is_locked;
+ int did_full_scan;
+ char fname[1];
+};
+typedef struct keyring_name const * CONST_KR_NAME;
+
+static KR_NAME kr_names;
+static int active_handles;
+
+static OffsetHashTable kr_offtbl;
+static int kr_offtbl_ready;
+
+
+struct keyring_handle {
+ CONST_KR_NAME resource;
+ int secret; /* this is for a secret keyring */
+ struct {
+ CONST_KR_NAME kr;
+ IOBUF iobuf;
+ int eof;
+ int error;
+ } current;
+ struct {
+ CONST_KR_NAME kr;
+ off_t offset;
+ size_t pk_no;
+ size_t uid_no;
+ unsigned int n_packets; /*used for delete and update*/
+ } found;
+ struct {
+ char *name;
+ char *pattern;
+ } word_match;
+};
+
+
+
+static int do_copy (int mode, const char *fname, KBNODE root, int secret,
+ off_t start_offset, unsigned int n_packets );
+
+
+
+static struct off_item *
+new_offset_item (void)
+{
+ struct off_item *k;
+
+ k = m_alloc_clear (sizeof *k);
+ return k;
+}
+
+#if 0
+static void
+release_offset_items (struct off_item *k)
+{
+ struct off_item *k2;
+
+ for (; k; k = k2)
+ {
+ k2 = k->next;
+ m_free (k);
+ }
+}
+#endif
+
+static OffsetHashTable
+new_offset_hash_table (void)
+{
+ struct off_item **tbl;
+
+ tbl = m_alloc_clear (2048 * sizeof *tbl);
+ return tbl;
+}
+
+#if 0
+static void
+release_offset_hash_table (OffsetHashTable tbl)
+{
+ int i;
+
+ if (!tbl)
+ return;
+ for (i=0; i < 2048; i++)
+ release_offset_items (tbl[i]);
+ m_free (tbl);
+}
+#endif
+
+static struct off_item *
+lookup_offset_hash_table (OffsetHashTable tbl, u32 *kid)
+{
+ struct off_item *k;
+
+ for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ return k;
+ return NULL;
+}
+
+static void
+update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
+{
+ struct off_item *k;
+
+ for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
+ {
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ {
+ /*k->off = off;*/
+ return;
+ }
+ }
+
+ k = new_offset_item ();
+ k->kid[0] = kid[0];
+ k->kid[1] = kid[1];
+ /*k->off = off;*/
+ k->next = tbl[(kid[1] & 0x07ff)];
+ tbl[(kid[1] & 0x07ff)] = k;
+}
+
+static void
+update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
+{
+ for (; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ u32 aki[2];
+ keyid_from_pk (node->pkt->pkt.public_key, aki);
+ update_offset_hash_table (tbl, aki, off);
+ }
+ }
+}
+
+
+
+
+/*
+ * Register a filename for plain keyring files. Returns a pointer to
+ * be used to create a handles etc or NULL to indicate that it has
+ * already been registered */
+void *
+keyring_register_filename (const char *fname, int secret)
+{
+ KR_NAME kr;
+
+ if (active_handles)
+ BUG (); /* We don't allow that */
+
+ for (kr=kr_names; kr; kr = kr->next) {
+ if ( !compare_filenames (kr->fname, fname) )
+ return NULL; /* already registered */
+ }
+
+ kr = m_alloc (sizeof *kr + strlen (fname));
+ strcpy (kr->fname, fname);
+ kr->secret = !!secret;
+ kr->lockhd = NULL;
+ kr->is_locked = 0;
+ kr->did_full_scan = 0;
+ /* keep a list of all issued pointers */
+ kr->next = kr_names;
+ kr_names = kr;
+
+ /* create the offset table the first time a function here is used */
+ if (!kr_offtbl)
+ kr_offtbl = new_offset_hash_table ();
+
+ return kr;
+}
+
+int
+keyring_is_writable (void *token)
+{
+ KR_NAME r = token;
+
+ return r? !access (r->fname, W_OK) : 0;
+}
+
+
+
+/* Create a new handle for the resource associated with TOKEN. SECRET
+ is just just as a cross-check.
+
+ The returned handle must be released using keyring_release (). */
+KEYRING_HANDLE
+keyring_new (void *token, int secret)
+{
+ KEYRING_HANDLE hd;
+ KR_NAME resource = token;
+
+ assert (resource && !resource->secret == !secret);
+
+ hd = m_alloc_clear (sizeof *hd);
+ hd->resource = resource;
+ hd->secret = !!secret;
+ active_handles++;
+ return hd;
+}
+
+void
+keyring_release (KEYRING_HANDLE hd)
+{
+ if (!hd)
+ return;
+ assert (active_handles > 0);
+ active_handles--;
+ m_free (hd->word_match.name);
+ m_free (hd->word_match.pattern);
+ iobuf_close (hd->current.iobuf);
+ m_free (hd);
+}
+
+
+const char *
+keyring_get_resource_name (KEYRING_HANDLE hd)
+{
+ if (!hd || !hd->resource)
+ return NULL;
+ return hd->resource->fname;
+}
+
+
+/*
+ * Lock the keyring with the given handle, or unlok if yes is false.
+ * We ignore the handle and lock all registered files.
+ */
+int
+keyring_lock (KEYRING_HANDLE hd, int yes)
+{
+ KR_NAME kr;
+ int rc = 0;
+
+ if (yes) {
+ /* first make sure the lock handles are created */
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (!keyring_is_writable(kr))
+ continue;
+ if (!kr->lockhd) {
+ kr->lockhd = create_dotlock( kr->fname );
+ if (!kr->lockhd) {
+ log_info ("can't allocate lock for `%s'\n", kr->fname );
+ rc = G10ERR_GENERAL;
+ }
+ }
+ }
+ if (rc)
+ return rc;
+
+ /* and now set the locks */
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (!keyring_is_writable(kr))
+ continue;
+ if (kr->is_locked)
+ ;
+ else if (make_dotlock (kr->lockhd, -1) ) {
+ log_info ("can't lock `%s'\n", kr->fname );
+ rc = G10ERR_GENERAL;
+ }
+ else
+ kr->is_locked = 1;
+ }
+ }
+
+ if (rc || !yes) {
+ for (kr=kr_names; kr; kr = kr->next) {
+ if (!keyring_is_writable(kr))
+ continue;
+ if (!kr->is_locked)
+ ;
+ else if (release_dotlock (kr->lockhd))
+ log_info ("can't unlock `%s'\n", kr->fname );
+ else
+ kr->is_locked = 0;
+ }
+ }
+
+ return rc;
+}
+
+
+
+/*
+ * Return the last found keyring. Caller must free it.
+ * The returned keyblock has the kbode flag bit 0 set for the node with
+ * the public key used to locate the keyblock or flag bit 1 set for
+ * the user ID node.
+ */
+int
+keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
+{
+ PACKET *pkt;
+ int rc;
+ KBNODE keyblock = NULL, node, lastnode;
+ IOBUF a;
+ int in_cert = 0;
+ int pk_no = 0;
+ int uid_no = 0;
+ int save_mode;
+
+ if (ret_kb)
+ *ret_kb = NULL;
+
+ if (!hd->found.kr)
+ return -1; /* no successful search */
+
+ a = iobuf_open (hd->found.kr->fname);
+ if (!a) {
+ log_error ("can't open `%s'\n", hd->found.kr->fname);
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ if (iobuf_seek (a, hd->found.offset) ) {
+ log_error ("can't seek `%s'\n", hd->found.kr->fname);
+ iobuf_close(a);
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ pkt = m_alloc (sizeof *pkt);
+ init_packet (pkt);
+ hd->found.n_packets = 0;;
+ lastnode = NULL;
+ save_mode = set_packet_list_mode(0);
+ while ((rc=parse_packet (a, pkt)) != -1) {
+ hd->found.n_packets++;
+ if (rc == G10ERR_UNKNOWN_PACKET) {
+ free_packet (pkt);
+ init_packet (pkt);
+ continue;
+ }
+ if (rc) {
+ log_error ("keyring_get_keyblock: read error: %s\n",
+ g10_errstr(rc) );
+ rc = G10ERR_INV_KEYRING;
+ break;
+ }
+ if (pkt->pkttype == PKT_COMPRESSED) {
+ log_error ("skipped compressed packet in keyring\n");
+ free_packet(pkt);
+ init_packet(pkt);
+ continue;
+ }
+
+ if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
+ || pkt->pkttype == PKT_SECRET_KEY)) {
+ hd->found.n_packets--; /* fix counter */
+ break; /* ready */
+ }
+
+ in_cert = 1;
+ if (pkt->pkttype == PKT_RING_TRUST) {
+ /*(this code is duplicated after the loop)*/
+ if ( lastnode
+ && lastnode->pkt->pkttype == PKT_SIGNATURE
+ && (pkt->pkt.ring_trust->sigcache & 1) ) {
+ /* this is a ring trust packet with a checked signature
+ * status cache following directly a signature paket.
+ * Set the cache status into that signature packet */
+ PKT_signature *sig = lastnode->pkt->pkt.signature;
+
+ sig->flags.checked = 1;
+ sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+ }
+ /* reset lastnode, so that we set the cache status only from
+ * the ring trust packet immediately folling a signature */
+ lastnode = NULL;
+ }
+ else {
+ node = lastnode = new_kbnode (pkt);
+ if (!keyblock)
+ keyblock = node;
+ else
+ add_kbnode (keyblock, node);
+
+ if ( pkt->pkttype == PKT_PUBLIC_KEY
+ || pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || pkt->pkttype == PKT_SECRET_KEY
+ || pkt->pkttype == PKT_SECRET_SUBKEY) {
+ if (++pk_no == hd->found.pk_no)
+ node->flag |= 1;
+ }
+ else if ( pkt->pkttype == PKT_USER_ID) {
+ if (++uid_no == hd->found.uid_no)
+ node->flag |= 2;
+ }
+ }
+
+ pkt = m_alloc (sizeof *pkt);
+ init_packet(pkt);
+ }
+ set_packet_list_mode(save_mode);
+
+ if (rc == -1 && keyblock)
+ rc = 0; /* got the entire keyblock */
+
+ if (rc || !ret_kb)
+ release_kbnode (keyblock);
+ else {
+ /*(duplicated form the loop body)*/
+ if ( pkt && pkt->pkttype == PKT_RING_TRUST
+ && lastnode
+ && lastnode->pkt->pkttype == PKT_SIGNATURE
+ && (pkt->pkt.ring_trust->sigcache & 1) ) {
+ PKT_signature *sig = lastnode->pkt->pkt.signature;
+ sig->flags.checked = 1;
+ sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+ }
+ *ret_kb = keyblock;
+ }
+ free_packet (pkt);
+ m_free (pkt);
+ iobuf_close(a);
+
+ /* Make sure that future search operations fail immediately when
+ * we know that we are working on a invalid keyring
+ */
+ if (rc == G10ERR_INV_KEYRING)
+ hd->current.error = rc;
+
+ return rc;
+}
+
+int
+keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
+{
+ int rc;
+
+ if (!hd->found.kr)
+ return -1; /* no successful prior search */
+
+ if (!hd->found.n_packets) {
+ /* need to know the number of packets - do a dummy get_keyblock*/
+ rc = keyring_get_keyblock (hd, NULL);
+ if (rc) {
+ log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+ return rc;
+ }
+ if (!hd->found.n_packets)
+ BUG ();
+ }
+
+ /* The open iobuf isn't needed anymore and in fact is a problem when
+ it comes to renaming the keyring files on some operating systems,
+ so close it here */
+ iobuf_close(hd->current.iobuf);
+ hd->current.iobuf = NULL;
+
+ /* do the update */
+ rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
+ hd->found.offset, hd->found.n_packets );
+ if (!rc) {
+ if (!hd->secret && kr_offtbl)
+ {
+ update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
+ }
+ /* better reset the found info */
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ }
+ return rc;
+}
+
+int
+keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
+{
+ int rc;
+ const char *fname;
+
+ if (!hd)
+ fname = NULL;
+ else if (hd->found.kr)
+ fname = hd->found.kr->fname;
+ else if (hd->current.kr)
+ fname = hd->current.kr->fname;
+ else
+ fname = hd->resource? hd->resource->fname:NULL;
+
+ if (!fname)
+ return G10ERR_GENERAL;
+
+ /* close this one otherwise we will lose the position for
+ * a next search. Fixme: it would be better to adjust the position
+ * after the write opertions.
+ */
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+
+ /* do the insert */
+ rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
+ if (!rc && !hd->secret && kr_offtbl)
+ {
+ update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
+ }
+
+ return rc;
+}
+
+
+int
+keyring_delete_keyblock (KEYRING_HANDLE hd)
+{
+ int rc;
+
+ if (!hd->found.kr)
+ return -1; /* no successful prior search */
+
+ if (!hd->found.n_packets) {
+ /* need to know the number of packets - do a dummy get_keyblock*/
+ rc = keyring_get_keyblock (hd, NULL);
+ if (rc) {
+ log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
+ return rc;
+ }
+ if (!hd->found.n_packets)
+ BUG ();
+ }
+
+ /* close this one otherwise we will lose the position for
+ * a next search. Fixme: it would be better to adjust the position
+ * after the write opertions.
+ */
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+
+ /* do the delete */
+ rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
+ hd->found.offset, hd->found.n_packets );
+ if (!rc) {
+ /* better reset the found info */
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ /* Delete is a rare operations, so we don't remove the keys
+ * from the offset table */
+ }
+ return rc;
+}
+
+
+
+/*
+ * Start the next search on this handle right at the beginning
+ */
+int
+keyring_search_reset (KEYRING_HANDLE hd)
+{
+ assert (hd);
+
+ hd->current.kr = NULL;
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+ hd->current.eof = 0;
+ hd->current.error = 0;
+
+ hd->found.kr = NULL;
+ hd->found.offset = 0;
+ return 0;
+}
+
+
+static int
+prepare_search (KEYRING_HANDLE hd)
+{
+ if (hd->current.error)
+ return hd->current.error; /* still in error state */
+
+ if (hd->current.kr && !hd->current.eof) {
+ if ( !hd->current.iobuf )
+ return G10ERR_GENERAL; /* position invalid after a modify */
+ return 0; /* okay */
+ }
+
+ if (!hd->current.kr && hd->current.eof)
+ return -1; /* still EOF */
+
+ if (!hd->current.kr) { /* start search with first keyring */
+ hd->current.kr = hd->resource;
+ if (!hd->current.kr) {
+ hd->current.eof = 1;
+ return -1; /* keyring not available */
+ }
+ assert (!hd->current.iobuf);
+ }
+ else { /* EOF */
+ iobuf_close (hd->current.iobuf);
+ hd->current.iobuf = NULL;
+ hd->current.kr = NULL;
+ hd->current.eof = 1;
+ return -1;
+ }
+
+ hd->current.eof = 0;
+ hd->current.iobuf = iobuf_open (hd->current.kr->fname);
+ if (!hd->current.iobuf) {
+ log_error ("can't open `%s'\n", hd->current.kr->fname );
+ return (hd->current.error = G10ERR_OPEN_FILE);
+ }
+
+ return 0;
+}
+
+
+/* A map of the all characters valid used for word_match()
+ * Valid characters are in in this table converted to uppercase.
+ * because the upper 128 bytes have special meaning, we assume
+ * that they are all valid.
+ * Note: We must use numerical values here in case that this program
+ * will be converted to those little blue HAL9000s with their strange
+ * EBCDIC character set (user ids are UTF-8).
+ * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
+ * we can run gpg now on a S/390 running GNU/Linux, where the code
+ * translation is done by the device drivers?
+ */
+static const byte word_match_chars[256] = {
+ /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 40 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ /* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ /* 58 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 60 */ 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ /* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ /* 78 */ 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /* 88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ /* 90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ /* 98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ /* a0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ /* a8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ /* b0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ /* b8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ /* c0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ /* c8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ /* d0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ /* d8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ /* e0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ /* e8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ /* f0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ /* f8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+/****************
+ * Do a word match (original user id starts with a '+').
+ * The pattern is already tokenized to a more suitable format:
+ * There are only the real words in it delimited by one space
+ * and all converted to uppercase.
+ *
+ * Returns: 0 if all words match.
+ *
+ * Note: This algorithm is a straightforward one and not very
+ * fast. It works for UTF-8 strings. The uidlen should
+ * be removed but due to the fact that old versions of
+ * pgp don't use UTF-8 we still use the length; this should
+ * be fixed in parse-packet (and replace \0 by some special
+ * UTF-8 encoding)
+ */
+static int
+word_match( const byte *uid, size_t uidlen, const byte *pattern )
+{
+ size_t wlen, n;
+ const byte *p;
+ const byte *s;
+
+ for( s=pattern; *s; ) {
+ do {
+ /* skip leading delimiters */
+ while( uidlen && !word_match_chars[*uid] )
+ uid++, uidlen--;
+ /* get length of the word */
+ n = uidlen; p = uid;
+ while( n && word_match_chars[*p] )
+ p++, n--;
+ wlen = p - uid;
+ /* and compare against the current word from pattern */
+ for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
+ if( word_match_chars[*p] != s[n] )
+ break;
+ }
+ if( n == wlen && (s[n] == ' ' || !s[n]) )
+ break; /* found */
+ uid += wlen;
+ uidlen -= wlen;
+ } while( uidlen );
+ if( !uidlen )
+ return -1; /* not found */
+
+ /* advance to next word in pattern */
+ for(; *s != ' ' && *s ; s++ )
+ ;
+ if( *s )
+ s++ ;
+ }
+ return 0; /* found */
+}
+
+/****************
+ * prepare word word_match; that is parse the name and
+ * build the pattern.
+ * caller has to free the returned pattern
+ */
+static char*
+prepare_word_match (const byte *name)
+{
+ byte *pattern, *p;
+ int c;
+
+ /* the original length is always enough for the pattern */
+ p = pattern = m_alloc(strlen(name)+1);
+ do {
+ /* skip leading delimiters */
+ while( *name && !word_match_chars[*name] )
+ name++;
+ /* copy as long as we don't have a delimiter and convert
+ * to uppercase.
+ * fixme: how can we handle utf8 uppercasing */
+ for( ; *name && (c=word_match_chars[*name]); name++ )
+ *p++ = c;
+ *p++ = ' '; /* append pattern delimiter */
+ } while( *name );
+ p[-1] = 0; /* replace last pattern delimiter by EOS */
+
+ return pattern;
+}
+
+
+
+
+static int
+compare_name (int mode, const char *name, const char *uid, size_t uidlen)
+{
+ int i;
+ const char *s, *se;
+
+ if (mode == KEYDB_SEARCH_MODE_EXACT) {
+ for (i=0; name[i] && uidlen; i++, uidlen--)
+ if (uid[i] != name[i])
+ break;
+ if (!uidlen && !name[i])
+ return 0; /* found */
+ }
+ else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
+ if (ascii_memistr( uid, uidlen, name ))
+ return 0;
+ }
+ else if ( mode == KEYDB_SEARCH_MODE_MAIL
+ || mode == KEYDB_SEARCH_MODE_MAILSUB
+ || mode == KEYDB_SEARCH_MODE_MAILEND) {
+ for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
+ ;
+ if (i < uidlen) {
+ /* skip opening delim and one char and look for the closing one*/
+ s++; i++;
+ for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
+ ;
+ if (i < uidlen) {
+ i = se - s;
+ if (mode == KEYDB_SEARCH_MODE_MAIL) {
+ if( strlen(name)-2 == i
+ && !ascii_memcasecmp( s, name+1, i) )
+ return 0;
+ }
+ else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
+ if( ascii_memistr( s, i, name ) )
+ return 0;
+ }
+ else { /* email from end */
+ /* nyi */
+ }
+ }
+ }
+ }
+ else if (mode == KEYDB_SEARCH_MODE_WORDS)
+ return word_match (uid, uidlen, name);
+ else
+ BUG();
+
+ return -1; /* not found */
+}
+
+
+/*
+ * Search through the keyring(s), starting at the current position,
+ * for a keyblock which contains one of the keys described in the DESC array.
+ */
+int
+keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+{
+ int rc;
+ PACKET pkt;
+ int save_mode;
+ off_t offset, main_offset;
+ size_t n;
+ int need_uid, need_words, need_keyid, need_fpr, any_skip;
+ int pk_no, uid_no;
+ int initial_skip;
+ int use_offtbl;
+ PKT_user_id *uid = NULL;
+ PKT_public_key *pk = NULL;
+ PKT_secret_key *sk = NULL;
+
+ /* figure out what information we need */
+ need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
+ for (n=0; n < ndesc; n++)
+ {
+ switch (desc[n].mode)
+ {
+ case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_SUBSTR:
+ case KEYDB_SEARCH_MODE_MAIL:
+ case KEYDB_SEARCH_MODE_MAILSUB:
+ case KEYDB_SEARCH_MODE_MAILEND:
+ need_uid = 1;
+ break;
+ case KEYDB_SEARCH_MODE_WORDS:
+ need_uid = 1;
+ need_words = 1;
+ break;
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ need_keyid = 1;
+ break;
+ case KEYDB_SEARCH_MODE_FPR16:
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ need_fpr = 1;
+ break;
+ case KEYDB_SEARCH_MODE_FIRST:
+ /* always restart the search in this mode */
+ keyring_search_reset (hd);
+ break;
+ default: break;
+ }
+ if (desc[n].skipfnc)
+ {
+ any_skip = 1;
+ need_keyid = 1;
+ }
+ }
+
+ rc = prepare_search (hd);
+ if (rc)
+ return rc;
+
+ use_offtbl = !hd->secret && kr_offtbl;
+ if (!use_offtbl)
+ ;
+ else if (!kr_offtbl_ready)
+ need_keyid = 1;
+ else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
+ {
+ struct off_item *oi;
+
+ oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
+ if (!oi)
+ { /* We know that we don't have this key */
+ hd->found.kr = NULL;
+ hd->current.eof = 1;
+ return -1;
+ }
+ /* We could now create a positive search status and return.
+ * However the problem is that another instance of gpg may
+ * have changed the keyring so that the offsets are not valid
+ * anymore - therefore we don't do it
+ */
+ }
+
+ if (need_words)
+ {
+ const char *name = NULL;
+
+ log_debug ("word search mode does not yet work\n");
+ /* FIXME: here is a long standing bug in our function and in addition we
+ just use the first search description */
+ for (n=0; n < ndesc && !name; n++)
+ {
+ if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
+ name = desc[n].u.name;
+ }
+ assert (name);
+ if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
+ {
+ /* name changed */
+ m_free (hd->word_match.name);
+ m_free (hd->word_match.pattern);
+ hd->word_match.name = m_strdup (name);
+ hd->word_match.pattern = prepare_word_match (name);
+ }
+ name = hd->word_match.pattern;
+ }
+
+ init_packet(&pkt);
+ save_mode = set_packet_list_mode(0);
+
+ hd->found.kr = NULL;
+ main_offset = 0;
+ pk_no = uid_no = 0;
+ initial_skip = 1; /* skip until we see the start of a keyblock */
+ while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid)))
+ {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+ u32 aki[2];
+
+ if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY)
+ {
+ main_offset = offset;
+ pk_no = uid_no = 0;
+ initial_skip = 0;
+ }
+ if (initial_skip)
+ {
+ free_packet (&pkt);
+ continue;
+ }
+
+ pk = NULL;
+ sk = NULL;
+ uid = NULL;
+ if ( pkt.pkttype == PKT_PUBLIC_KEY
+ || pkt.pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ pk = pkt.pkt.public_key;
+ ++pk_no;
+
+ if (need_fpr) {
+ fingerprint_from_pk (pk, afp, &an);
+ while (an < 20) /* fill up to 20 bytes */
+ afp[an++] = 0;
+ }
+ if (need_keyid)
+ keyid_from_pk (pk, aki);
+
+ if (use_offtbl && !kr_offtbl_ready)
+ update_offset_hash_table (kr_offtbl, aki, main_offset);
+ }
+ else if (pkt.pkttype == PKT_USER_ID)
+ {
+ uid = pkt.pkt.user_id;
+ ++uid_no;
+ }
+ else if ( pkt.pkttype == PKT_SECRET_KEY
+ || pkt.pkttype == PKT_SECRET_SUBKEY)
+ {
+ sk = pkt.pkt.secret_key;
+ ++pk_no;
+
+ if (need_fpr) {
+ fingerprint_from_sk (sk, afp, &an);
+ while (an < 20) /* fill up to 20 bytes */
+ afp[an++] = 0;
+ }
+ if (need_keyid)
+ keyid_from_sk (sk, aki);
+
+ }
+
+ for (n=0; n < ndesc; n++)
+ {
+ switch (desc[n].mode) {
+ case KEYDB_SEARCH_MODE_NONE:
+ BUG ();
+ break;
+ case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_SUBSTR:
+ case KEYDB_SEARCH_MODE_MAIL:
+ case KEYDB_SEARCH_MODE_MAILSUB:
+ case KEYDB_SEARCH_MODE_MAILEND:
+ case KEYDB_SEARCH_MODE_WORDS:
+ if ( uid && !compare_name (desc[n].mode,
+ desc[n].u.name,
+ uid->name, uid->len))
+ goto found;
+ break;
+
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ if ((pk||sk) && desc[n].u.kid[1] == aki[1])
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ if ((pk||sk) && desc[n].u.kid[0] == aki[0]
+ && desc[n].u.kid[1] == aki[1])
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FPR16:
+ if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16))
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_FIRST:
+ if (pk||sk)
+ goto found;
+ break;
+ case KEYDB_SEARCH_MODE_NEXT:
+ if (pk||sk)
+ goto found;
+ break;
+ default:
+ rc = G10ERR_INV_ARG;
+ goto found;
+ }
+ }
+ free_packet (&pkt);
+ continue;
+ found:
+ for (n=any_skip?0:ndesc; n < ndesc; n++)
+ {
+ if (desc[n].skipfnc
+ && desc[n].skipfnc (desc[n].skipfncvalue, aki))
+ break;
+ }
+ if (n == ndesc)
+ goto real_found;
+ free_packet (&pkt);
+ }
+ real_found:
+ if (!rc)
+ {
+ hd->found.offset = main_offset;
+ hd->found.kr = hd->current.kr;
+ hd->found.pk_no = (pk||sk)? pk_no : 0;
+ hd->found.uid_no = uid? uid_no : 0;
+ }
+ else if (rc == -1)
+ {
+ hd->current.eof = 1;
+ /* if we scanned all keyrings, we are sure that
+ * all known key IDs are in our offtbl, mark that. */
+ if (use_offtbl && !kr_offtbl_ready)
+ {
+ KR_NAME kr;
+
+ /* First set the did_full_scan flag for this keyring (ignore
+ secret keyrings) */
+ for (kr=kr_names; kr; kr = kr->next)
+ {
+ if (!kr->secret && hd->resource == kr)
+ {
+ kr->did_full_scan = 1;
+ break;
+ }
+ }
+ /* Then check whether all flags are set and if so, mark the
+ offtbl ready */
+ for (kr=kr_names; kr; kr = kr->next)
+ {
+ if (!kr->secret && !kr->did_full_scan)
+ break;
+ }
+ if (!kr)
+ kr_offtbl_ready = 1;
+ }
+ }
+ else
+ hd->current.error = rc;
+
+ free_packet(&pkt);
+ set_packet_list_mode(save_mode);
+ return rc;
+}
+
+
+static int
+create_tmp_file (const char *template,
+ char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
+{
+ char *bakfname, *tmpfname;
+
+ *r_bakfname = NULL;
+ *r_tmpfname = NULL;
+
+# ifdef USE_ONLY_8DOT3
+ /* Here is another Windoze bug?:
+ * you cant rename("pubring.gpg.tmp", "pubring.gpg");
+ * but rename("pubring.gpg.tmp", "pubring.aaa");
+ * works. So we replace .gpg by .bak or .tmp
+ */
+ if (strlen (template) > 4
+ && !strcmp (template+strlen(template)-4, EXTSEP_S "gpg") )
+ {
+ bakfname = m_alloc (strlen (template) + 1);
+ strcpy (bakfname, template);
+ strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
+
+ tmpfname = m_alloc (strlen( template ) + 1 );
+ strcpy (tmpfname,template);
+ strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
+ }
+ else
+ { /* file does not end with gpg; hmmm */
+ bakfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
+
+ tmpfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(tmpfname, template), EXTSEP_S "tmp");
+ }
+# else /* Posix file names */
+ bakfname = m_alloc (strlen( template ) + 2);
+ strcpy (stpcpy (bakfname,template),"~");
+
+ tmpfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
+# endif /* Posix filename */
+
+ *r_fp = iobuf_create (tmpfname);
+ if (!*r_fp) {
+ log_error ("can't create `%s': %s\n", tmpfname, strerror(errno) );
+ m_free (tmpfname);
+ m_free (bakfname);
+ return G10ERR_OPEN_FILE;
+ }
+
+ *r_bakfname = bakfname;
+ *r_tmpfname = tmpfname;
+ return 0;
+}
+
+
+static int
+rename_tmp_file (const char *bakfname, const char *tmpfname,
+ const char *fname, int secret )
+{
+ int rc=0;
+
+ /* restrict the permissions for secret keyrings */
+#ifndef HAVE_DOSISH_SYSTEM
+ if (secret && !opt.preserve_permissions)
+ {
+ if (chmod (tmpfname, S_IRUSR | S_IWUSR) )
+ {
+ log_error ("chmod of `%s' failed: %s\n",
+ tmpfname, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ }
+#endif
+
+ /* invalidate close caches*/
+ iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
+ iobuf_ioctl (NULL, 2, 0, (char*)bakfname );
+ iobuf_ioctl (NULL, 2, 0, (char*)fname );
+
+ /* first make a backup file except for secret keyrings */
+ if (!secret)
+ {
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove (bakfname);
+#endif
+ if (rename (fname, bakfname) )
+ {
+ log_error ("renaming `%s' to `%s' failed: %s\n",
+ fname, bakfname, strerror(errno) );
+ return G10ERR_RENAME_FILE;
+ }
+ }
+
+ /* then rename the file */
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove( fname );
+#endif
+ if (rename (tmpfname, fname) )
+ {
+ log_error ("renaming `%s' to `%s' failed: %s\n",
+ tmpfname, fname, strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ if (secret)
+ {
+ log_info(_("WARNING: 2 files with confidential"
+ " information exists.\n"));
+ log_info(_("%s is the unchanged one\n"), fname );
+ log_info(_("%s is the new one\n"), tmpfname );
+ log_info(_("Please fix this possible security flaw\n"));
+ }
+ return rc;
+ }
+
+ return 0;
+}
+
+
+static int
+write_keyblock (IOBUF fp, KBNODE keyblock)
+{
+ KBNODE kbctx = NULL, node;
+ int rc;
+
+ while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
+ {
+ if (node->pkt->pkttype == PKT_RING_TRUST)
+ continue; /* we write it later on our own */
+
+ if ( (rc = build_packet (fp, node->pkt) ))
+ {
+ log_error ("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ return rc;
+ }
+ if (node->pkt->pkttype == PKT_SIGNATURE)
+ { /* always write a signature cache packet */
+ PKT_signature *sig = node->pkt->pkt.signature;
+ unsigned int cacheval = 0;
+
+ if (sig->flags.checked)
+ {
+ cacheval |= 1;
+ if (sig->flags.valid)
+ cacheval |= 2;
+ }
+ iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
+ iobuf_put (fp, 2); /* 2 bytes */
+ iobuf_put (fp, 0); /* unused */
+ if (iobuf_put (fp, cacheval)) {
+ log_error ("writing sigcache packet failed\n");
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Walk over all public keyrings, check the signatures and replace the
+ * keyring with a new one where the signature cache is then updated.
+ * This is only done for the public keyrings.
+ */
+int
+keyring_rebuild_cache (void *token)
+{
+ KEYRING_HANDLE hd;
+ KEYDB_SEARCH_DESC desc;
+ KBNODE keyblock = NULL, node;
+ const char *lastresname = NULL, *resname;
+ IOBUF tmpfp = NULL;
+ char *tmpfilename = NULL;
+ char *bakfilename = NULL;
+ int rc;
+ ulong count = 0, sigcount = 0;
+
+ hd = keyring_new (token, 0);
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+
+ while ( !(rc = keyring_search (hd, &desc, 1)) )
+ {
+ desc.mode = KEYDB_SEARCH_MODE_NEXT;
+ resname = keyring_get_resource_name (hd);
+ if (lastresname != resname )
+ { /* we have switched to a new keyring - commit changes */
+ if (tmpfp)
+ {
+ if (iobuf_close (tmpfp))
+ {
+ log_error ("error closing `%s': %s\n",
+ tmpfilename, strerror (errno));
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* because we have switched resources, we can be sure that
+ * the original file is closed */
+ tmpfp = NULL;
+ }
+ rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
+ lastresname, 0) : 0;
+ m_free (tmpfilename); tmpfilename = NULL;
+ m_free (bakfilename); bakfilename = NULL;
+ if (rc)
+ goto leave;
+ lastresname = resname;
+ if (!opt.quiet)
+ log_info (_("checking keyring `%s'\n"), resname);
+ rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
+ if (rc)
+ goto leave;
+ }
+
+ release_kbnode (keyblock);
+ rc = keyring_get_keyblock (hd, &keyblock);
+ if (rc)
+ {
+ log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+
+ /* check all signature to set the signature's cache flags */
+ for (node=keyblock; node; node=node->next)
+ {
+ if (node->pkt->pkttype == PKT_SIGNATURE)
+ {
+ check_key_signature (keyblock, node, NULL);
+ sigcount++;
+ }
+ }
+
+ /* write the keyblock to the temporary file */
+ rc = write_keyblock (tmpfp, keyblock);
+ if (rc)
+ goto leave;
+
+ if ( !(++count % 50) && !opt.quiet)
+ log_info(_("%lu keys so far checked (%lu signatures)\n"),
+ count, sigcount );
+
+ } /* end main loop */
+ if (rc == -1)
+ rc = 0;
+ if (rc)
+ {
+ log_error ("keyring_search failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ log_info(_("%lu keys checked (%lu signatures)\n"), count, sigcount );
+ if (tmpfp)
+ {
+ if (iobuf_close (tmpfp))
+ {
+ log_error ("error closing `%s': %s\n",
+ tmpfilename, strerror (errno));
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* because we have switched resources, we can be sure that
+ * the original file is closed */
+ tmpfp = NULL;
+ }
+ rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
+ lastresname, 0) : 0;
+ m_free (tmpfilename); tmpfilename = NULL;
+ m_free (bakfilename); bakfilename = NULL;
+
+ leave:
+ if (tmpfp)
+ iobuf_cancel (tmpfp);
+ m_free (tmpfilename);
+ m_free (bakfilename);
+ release_kbnode (keyblock);
+ keyring_release (hd);
+ return rc;
+}
+
+
+/****************
+ * Perform insert/delete/update operation.
+ * mode 1 = insert
+ * 2 = delete
+ * 3 = update
+ */
+static int
+do_copy (int mode, const char *fname, KBNODE root, int secret,
+ off_t start_offset, unsigned int n_packets )
+{
+ IOBUF fp, newfp;
+ int rc=0;
+ char *bakfname = NULL;
+ char *tmpfname = NULL;
+
+ /* Open the source file. Because we do a rname, we have to check the
+ permissions of the file */
+ if (access (fname, W_OK))
+ return G10ERR_WRITE_FILE;
+
+ fp = iobuf_open (fname);
+ if (mode == 1 && !fp && errno == ENOENT) {
+ /* insert mode but file does not exist: create a new file */
+ KBNODE kbctx, node;
+
+ newfp = iobuf_create (fname);
+ if( !newfp ) {
+ log_error (_("%s: can't create: %s\n"),
+ fname, strerror(errno));
+ return G10ERR_OPEN_FILE;
+ }
+ if( !opt.quiet )
+ log_info(_("%s: keyring created\n"), fname );
+
+ kbctx=NULL;
+ while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
+ if( (rc = build_packet( newfp, node->pkt )) ) {
+ log_error("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ iobuf_cancel(newfp);
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ if( iobuf_close(newfp) ) {
+ log_error ("%s: close failed: %s\n", fname, strerror(errno));
+ return G10ERR_CLOSE_FILE;
+ }
+ if (chmod( fname, S_IRUSR | S_IWUSR )) {
+ log_error("%s: chmod failed: %s\n", fname, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ return 0; /* ready */
+ }
+
+ if( !fp ) {
+ log_error ("%s: can't open: %s\n", fname, strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ /* create the new file */
+ rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
+ if (rc) {
+ iobuf_close(fp);
+ goto leave;
+ }
+ if( mode == 1 ) { /* insert */
+ /* copy everything to the new file */
+ rc = copy_all_packets (fp, newfp);
+ if( rc != -1 ) {
+ log_error("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ rc = 0;
+ }
+
+ if( mode == 2 || mode == 3 ) { /* delete or update */
+ /* copy first part to the new file */
+ rc = copy_some_packets( fp, newfp, start_offset );
+ if( rc ) { /* should never get EOF here */
+ log_error ("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ /* skip this keyblock */
+ assert( n_packets );
+ rc = skip_some_packets( fp, n_packets );
+ if( rc ) {
+ log_error("%s: skipping %u packets failed: %s\n",
+ fname, n_packets, g10_errstr(rc));
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ }
+
+ if( mode == 1 || mode == 3 ) { /* insert or update */
+ rc = write_keyblock (newfp, root);
+ if (rc) {
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ }
+
+ if( mode == 2 || mode == 3 ) { /* delete or update */
+ /* copy the rest */
+ rc = copy_all_packets( fp, newfp );
+ if( rc != -1 ) {
+ log_error("%s: copy to `%s' failed: %s\n",
+ fname, tmpfname, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ rc = 0;
+ }
+
+ /* close both files */
+ if( iobuf_close(fp) ) {
+ log_error("%s: close failed: %s\n", fname, strerror(errno) );
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ if( iobuf_close(newfp) ) {
+ log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+
+ rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
+
+ leave:
+ m_free(bakfname);
+ m_free(tmpfname);
+ return rc;
+}
diff --git a/g10/keyring.h b/g10/keyring.h
new file mode 100644
index 000000000..cb8e404a4
--- /dev/null
+++ b/g10/keyring.h
@@ -0,0 +1,45 @@
+/* keyring.h - Keyring operations
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef GPG_KEYRING_H
+#define GPG_KEYRING_H 1
+
+#include "global.h"
+
+
+typedef struct keyring_handle *KEYRING_HANDLE;
+
+void *keyring_register_filename (const char *fname, int secret);
+int keyring_is_writable (void *token);
+
+KEYRING_HANDLE keyring_new (void *token, int secret);
+void keyring_release (KEYRING_HANDLE hd);
+const char *keyring_get_resource_name (KEYRING_HANDLE hd);
+int keyring_lock (KEYRING_HANDLE hd, int yes);
+int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
+int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
+int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
+int keyring_locate_writable (KEYRING_HANDLE hd);
+int keyring_delete_keyblock (KEYRING_HANDLE hd);
+int keyring_search_reset (KEYRING_HANDLE hd);
+int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
+int keyring_rebuild_cache (void *);
+
+#endif /*GPG_KEYRING_H*/
diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h
new file mode 100644
index 000000000..9f0d2e8c0
--- /dev/null
+++ b/g10/keyserver-internal.h
@@ -0,0 +1,22 @@
+/* Keyserver internals */
+
+#ifndef _KEYSERVER_INTERNAL_H_
+#define _KEYSERVER_INTERNAL_H_
+
+#include <time.h>
+#include "keyserver.h"
+#include "iobuf.h"
+#include "types.h"
+
+void parse_keyserver_options(char *options);
+int parse_keyserver_uri(char *uri,
+ const char *configname,unsigned int configlineno);
+int keyserver_export(STRLIST users);
+int keyserver_import(STRLIST users);
+int keyserver_import_fprint(const byte *fprint,size_t fprint_len);
+int keyserver_import_keyid(u32 *keyid);
+int keyserver_refresh(STRLIST users);
+int keyserver_search(STRLIST tokens);
+void keyserver_search_prompt(IOBUF buffer,int count,const char *searchstr);
+
+#endif /* !_KEYSERVER_INTERNAL_H_ */
diff --git a/g10/keyserver.c b/g10/keyserver.c
new file mode 100644
index 000000000..9338bfbb7
--- /dev/null
+++ b/g10/keyserver.c
@@ -0,0 +1,1033 @@
+/* keyserver.c - generic keyserver code
+ * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "filter.h"
+#include "keydb.h"
+#include "status.h"
+#include "exec.h"
+#include "main.h"
+#include "i18n.h"
+#include "hkp.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "options.h"
+#include "packet.h"
+#include "keyserver-internal.h"
+#include "util.h"
+
+#define KEYSERVER_PROTO_VERSION 0
+
+#define GET 0
+#define SEND 1
+#define SEARCH 2
+
+struct kopts
+{
+ char *name;
+ int tell; /* tell remote process about this one */
+ int *flag;
+} keyserver_opts[]=
+{
+ {"include-revoked",1,&opt.keyserver_options.include_revoked},
+ {"include-disabled",1,&opt.keyserver_options.include_disabled},
+ {"include-subkeys",1,&opt.keyserver_options.include_subkeys},
+ {"keep-temp-files",0,&opt.keyserver_options.keep_temp_files},
+ {"honor-http-proxy",1,&opt.keyserver_options.honor_http_proxy},
+ {"broken-http-proxy",1,&opt.keyserver_options.broken_http_proxy},
+ {"refresh-add-fake-v3-keyids",0,&opt.keyserver_options.fake_v3_keyids},
+ {"auto-key-retrieve",0,&opt.keyserver_options.auto_key_retrieve},
+ {NULL}
+};
+
+void
+parse_keyserver_options(char *options)
+{
+ char *tok="";
+
+ do
+ {
+ struct kopts *kopts=keyserver_opts;
+ int i,hit=0;
+
+ for(i=0,kopts=keyserver_opts;kopts[i].name;i++)
+ {
+ if(ascii_strcasecmp(tok,kopts[i].name)==0)
+ {
+ *(kopts[i].flag)=1;
+ hit=1;
+ break;
+ }
+ else if(ascii_memcasecmp("no-",tok,3)==0 && strlen(tok)>3 &&
+ ascii_strcasecmp(&tok[3],kopts[i].name)==0)
+ {
+ *(kopts[i].flag)=0;
+ hit=1;
+ break;
+ }
+ }
+
+ /* These options need more than just a flag */
+ if(!hit)
+ {
+ if(ascii_strcasecmp(tok,"verbose")==0)
+ opt.keyserver_options.verbose++;
+ else if(ascii_strcasecmp(tok,"no-verbose")==0)
+ opt.keyserver_options.verbose--;
+#ifdef EXEC_TEMPFILE_ONLY
+ else if(ascii_strcasecmp(tok,"use-temp-files")==0 ||
+ ascii_strcasecmp(tok,"no-use-temp-files")==0)
+ log_info(_("Warning: keyserver option \"%s\" is not used "
+ "on this platform\n"),tok);
+#else
+ else if(ascii_strcasecmp(tok,"use-temp-files")==0)
+ opt.keyserver_options.use_temp_files=1;
+ else if(ascii_strcasecmp(tok,"no-use-temp-files")==0)
+ opt.keyserver_options.use_temp_files=0;
+#endif
+ else if(strlen(tok)>0)
+ add_to_strlist(&opt.keyserver_options.other,tok);
+ }
+
+ tok=strsep(&options," ,");
+ }
+ while(tok!=NULL);
+}
+
+int
+parse_keyserver_uri(char *uri,const char *configname,unsigned int configlineno)
+{
+ /* Get the scheme */
+
+ opt.keyserver_scheme=strsep(&uri,":");
+ if(uri==NULL)
+ {
+ uri=opt.keyserver_scheme;
+ opt.keyserver_scheme="hkp";
+ }
+
+ if(ascii_strcasecmp(opt.keyserver_scheme,"x-broken-hkp")==0)
+ {
+ deprecated_warning(configname,configlineno,"x-broken-hkp",
+ "--keyserver-options ","broken-http-proxy");
+ opt.keyserver_scheme="hkp";
+ opt.keyserver_options.broken_http_proxy=1;
+ }
+ else if(ascii_strcasecmp(opt.keyserver_scheme,"x-hkp")==0)
+ {
+ /* Canonicalize this to "hkp" so it works with both the internal
+ and external keyserver interface. */
+ opt.keyserver_scheme="hkp";
+ }
+
+ /* Skip the "//", if any */
+ if(strlen(uri)>2 && uri[0]=='/' && uri[1]=='/')
+ uri+=2;
+
+ /* Get the host */
+ opt.keyserver_host=strsep(&uri,":/");
+ if(uri==NULL)
+ opt.keyserver_port="0";
+ else
+ {
+ char *ch;
+
+ /* Get the port */
+ opt.keyserver_port=strsep(&uri,"/");
+
+ /* Ports are digits only */
+ ch=opt.keyserver_port;
+ while(*ch!='\0')
+ {
+ if(!isdigit(*ch))
+ return G10ERR_BAD_URI;
+
+ ch++;
+ }
+
+ if(strlen(opt.keyserver_port)==0 ||
+ atoi(opt.keyserver_port)<1 || atoi(opt.keyserver_port)>65535)
+ return G10ERR_BAD_URI;
+ }
+
+ /* (any path part of the URI is discarded for now as no keyserver
+ uses it) */
+
+ if(opt.keyserver_scheme[0]=='\0' || opt.keyserver_host[0]=='\0')
+ return G10ERR_BAD_URI;
+
+ return 0;
+}
+
+/* Unquote only the delimiter character and backslashes (\x5C) */
+static void
+printunquoted(char *string,char delim)
+{
+ char *ch=string;
+
+ while(*ch)
+ {
+ if(*ch=='\\')
+ {
+ int c;
+
+ sscanf(ch,"\\x%02x",&c);
+ if(c==delim)
+ {
+ printf("%c",c);
+ ch+=3;
+ }
+ else if(c=='\\')
+ {
+ fputc('\\',stdout);
+ ch+=3;
+ }
+ else
+ fputc(*ch,stdout);
+ }
+ else
+ fputc(*ch,stdout);
+
+ ch++;
+ }
+}
+
+static int
+print_keyinfo(int count,char *keystring,KEYDB_SEARCH_DESC *desc)
+{
+ char *certid,*userid,*keytype,*tok;
+ int flags,keysize=0;
+ time_t createtime=0,expiretime=0,modifytime=0;
+
+ if((certid=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ classify_user_id (certid, desc);
+ if(desc->mode!=KEYDB_SEARCH_MODE_SHORT_KID &&
+ desc->mode!=KEYDB_SEARCH_MODE_LONG_KID &&
+ desc->mode!=KEYDB_SEARCH_MODE_FPR16 &&
+ desc->mode!=KEYDB_SEARCH_MODE_FPR20)
+ return -1;
+
+ if((tok=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ userid=utf8_to_native(tok,strlen(tok),0);
+
+ if((tok=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ flags=atoi(tok);
+
+ if((tok=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ createtime=atoi(tok);
+
+ if((tok=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ expiretime=atoi(tok);
+
+ if((tok=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ modifytime=atoi(tok);
+
+ if((keytype=strsep(&keystring,":"))==NULL)
+ return -1;
+
+ /* The last one */
+ if(keystring!=NULL)
+ keysize=atoi(keystring);
+
+ printf("(%d)\t",count);
+
+ /* No need to check for control characters, as utf8_to_native does
+ this for us. */
+ printunquoted(userid,':');
+
+ if(flags&1)
+ printf(" (revoked)");
+ if(flags&2)
+ printf(" (disabled)");
+
+ if(keytype[0])
+ printf(" %s",keytype);
+
+ if(keysize>0)
+ printf(" %d",keysize);
+
+ printf("\n\t created %s,",strtimestamp(createtime));
+
+ if(expiretime>0)
+ printf(" expires %s,",strtimestamp(expiretime));
+
+ printf(" key %s\n",certid);
+
+ return 0;
+}
+
+#define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\""
+#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
+
+static int
+keyserver_spawn(int action,STRLIST list,
+ KEYDB_SEARCH_DESC *desc,int count,int *prog)
+{
+ int ret=0,i,gotversion=0,outofband=0;
+ STRLIST temp;
+ unsigned int maxlen=256,buflen;
+ char *command=NULL,*searchstr=NULL;
+ byte *line=NULL;
+ struct kopts *kopts;
+ struct exec_info *spawn;
+
+#ifdef EXEC_TEMPFILE_ONLY
+ opt.keyserver_options.use_temp_files=1;
+#endif
+
+ /* Build the filename for the helper to execute */
+
+ command=m_alloc(strlen("gpgkeys_")+strlen(opt.keyserver_scheme)+1);
+ strcpy(command,"gpgkeys_");
+ strcat(command,opt.keyserver_scheme);
+
+ if(opt.keyserver_options.use_temp_files)
+ {
+ if(opt.keyserver_options.keep_temp_files)
+ {
+ command=m_realloc(command,strlen(command)+
+ strlen(KEYSERVER_ARGS_KEEP)+1);
+ strcat(command,KEYSERVER_ARGS_KEEP);
+ }
+ else
+ {
+ command=m_realloc(command,strlen(command)+
+ strlen(KEYSERVER_ARGS_NOKEEP)+1);
+ strcat(command,KEYSERVER_ARGS_NOKEEP);
+ }
+
+ ret=exec_write(&spawn,NULL,command,NULL,0,0);
+ }
+ else
+ ret=exec_write(&spawn,command,NULL,NULL,0,0);
+
+ if(ret)
+ return ret;
+
+ fprintf(spawn->tochild,"# This is a gpg keyserver communications file\n");
+ fprintf(spawn->tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
+ fprintf(spawn->tochild,"PROGRAM %s\n",VERSION);
+ fprintf(spawn->tochild,"HOST %s\n",opt.keyserver_host);
+
+ if(atoi(opt.keyserver_port)>0)
+ fprintf(spawn->tochild,"PORT %s\n",opt.keyserver_port);
+
+ /* Write options */
+
+ for(i=0,kopts=keyserver_opts;kopts[i].name;i++)
+ if(*(kopts[i].flag) && kopts[i].tell)
+ fprintf(spawn->tochild,"OPTION %s\n",kopts[i].name);
+
+ for(i=0;i<opt.keyserver_options.verbose;i++)
+ fprintf(spawn->tochild,"OPTION verbose\n");
+
+ temp=opt.keyserver_options.other;
+
+ for(;temp;temp=temp->next)
+ fprintf(spawn->tochild,"OPTION %s\n",temp->d);
+
+ switch(action)
+ {
+ case GET:
+ {
+ fprintf(spawn->tochild,"COMMAND GET\n\n");
+
+ /* Which keys do we want? */
+
+ for(i=0;i<count;i++)
+ {
+ if(desc[i].mode==KEYDB_SEARCH_MODE_FPR20)
+ {
+ int f;
+
+ fprintf(spawn->tochild,"0x");
+
+ for(f=0;f<MAX_FINGERPRINT_LEN;f++)
+ fprintf(spawn->tochild,"%02X",(byte)desc[i].u.fpr[f]);
+
+ fprintf(spawn->tochild,"\n");
+ }
+ else if(desc[i].mode==KEYDB_SEARCH_MODE_FPR16)
+ {
+ int f;
+
+ fprintf(spawn->tochild,"0x");
+
+ for(f=0;f<16;f++)
+ fprintf(spawn->tochild,"%02X",(byte)desc[i].u.fpr[f]);
+
+ fprintf(spawn->tochild,"\n");
+ }
+ else if(desc[i].mode==KEYDB_SEARCH_MODE_LONG_KID)
+ fprintf(spawn->tochild,"0x%08lX%08lX\n",
+ (ulong)desc[i].u.kid[0],
+ (ulong)desc[i].u.kid[1]);
+ else
+ fprintf(spawn->tochild,"0x%08lX\n",
+ (ulong)desc[i].u.kid[1]);
+ }
+
+ fprintf(spawn->tochild,"\n");
+
+ break;
+ }
+
+ case SEND:
+ {
+ STRLIST key;
+
+ /* Note the extra \n here to send an empty keylist block */
+ fprintf(spawn->tochild,"COMMAND SEND\n\n\n");
+
+ for(key=list;key!=NULL;key=key->next)
+ {
+ armor_filter_context_t afx;
+ IOBUF buffer=iobuf_temp();
+
+ temp=NULL;
+ add_to_strlist(&temp,key->d);
+
+ memset(&afx,0,sizeof(afx));
+ afx.what=1;
+ iobuf_push_filter(buffer,armor_filter,&afx);
+
+ if(export_pubkeys_stream(buffer,temp,1)==-1)
+ iobuf_close(buffer);
+ else
+ {
+ iobuf_flush_temp(buffer);
+
+ fprintf(spawn->tochild,"KEY %s BEGIN\n",key->d);
+ fwrite(iobuf_get_temp_buffer(buffer),
+ iobuf_get_temp_length(buffer),1,spawn->tochild);
+ fprintf(spawn->tochild,"KEY %s END\n",key->d);
+
+ iobuf_close(buffer);
+ }
+
+ free_strlist(temp);
+ }
+
+ break;
+ }
+
+ case SEARCH:
+ {
+ STRLIST key;
+
+ fprintf(spawn->tochild,"COMMAND SEARCH\n\n");
+
+ /* Which keys do we want? Remember that the gpgkeys_ program
+ is going to lump these together into a search string. */
+
+ for(key=list;key!=NULL;key=key->next)
+ {
+ fprintf(spawn->tochild,"%s\n",key->d);
+ if(key!=list)
+ {
+ searchstr=m_realloc(searchstr,
+ strlen(searchstr)+strlen(key->d)+2);
+ strcat(searchstr," ");
+ }
+ else
+ {
+ searchstr=m_alloc(strlen(key->d)+1);
+ searchstr[0]='\0';
+ }
+
+ strcat(searchstr,key->d);
+ }
+
+ fprintf(spawn->tochild,"\n");
+
+ break;
+ }
+
+ default:
+ log_fatal(_("no keyserver action!\n"));
+ break;
+ }
+
+ /* Done sending, so start reading. */
+ ret=exec_read(spawn);
+ if(ret)
+ goto fail;
+
+ /* Now handle the response */
+
+ for(;;)
+ {
+ char *ptr;
+
+ if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
+ {
+ ret=G10ERR_READ_FILE;
+ goto fail; /* i.e. EOF */
+ }
+
+ ptr=line;
+
+ if(*ptr=='\r')
+ ptr++;
+
+ if(*ptr=='\n')
+ ptr++;
+
+ if(*ptr=='\0')
+ break;
+
+ if(ascii_memcasecmp(ptr,"VERSION ",8)==0)
+ {
+ gotversion=1;
+
+ if(atoi(&ptr[8])!=KEYSERVER_PROTO_VERSION)
+ {
+ log_error(_("invalid keyserver protocol (us %d!=handler %d)\n"),
+ KEYSERVER_PROTO_VERSION,atoi(&ptr[8]));
+ goto fail;
+ }
+ }
+ else if(ascii_memcasecmp(ptr,"PROGRAM ",8)==0)
+ {
+ if(ascii_memcasecmp(&ptr[8],VERSION,strlen(VERSION))!=0)
+ log_info(_("Warning: keyserver handler from a different "
+ "version of GnuPG (%s)\n"),&ptr[8]);
+ }
+ else if(ascii_memcasecmp(ptr,"OPTION OUTOFBAND",16)==0)
+ outofband=1; /* Currently the only OPTION */
+ }
+
+ m_free(line);
+
+ if(!gotversion)
+ {
+ log_error(_("keyserver did not send VERSION\n"));
+ goto fail;
+ }
+
+ if(!outofband)
+ switch(action)
+ {
+ case GET:
+ {
+ void *stats_handle;
+
+ stats_handle=import_new_stats_handle();
+
+ /* Slurp up all the key data. In the future, it might be nice
+ to look for KEY foo OUTOFBAND and FAILED indicators. It's
+ harmless to ignore them, but ignoring them does make gpg
+ complain about "no valid OpenPGP data found". One way to
+ do this could be to continue parsing this line-by-line and
+ make a temp iobuf for each key. */
+
+ import_keys_stream(spawn->fromchild,0,stats_handle);
+
+ import_print_stats(stats_handle);
+ import_release_stats_handle(stats_handle);
+
+ break;
+ }
+
+ /* Nothing to do here */
+ case SEND:
+ break;
+
+ case SEARCH:
+ {
+ line=NULL;
+ buflen = 0;
+ maxlen = 80;
+ /* Look for the COUNT line */
+ do
+ {
+ if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
+ {
+ ret=G10ERR_READ_FILE;
+ goto fail; /* i.e. EOF */
+ }
+ }
+ while(sscanf(line,"COUNT %d\n",&i)!=1);
+
+ keyserver_search_prompt(spawn->fromchild,i,searchstr);
+
+ break;
+ }
+
+ default:
+ log_fatal(_("no keyserver action!\n"));
+ break;
+ }
+
+ fail:
+ *prog=exec_finish(spawn);
+
+ return ret;
+}
+
+static int
+keyserver_work(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,int count)
+{
+ int rc=0,ret=0;
+
+ if(opt.keyserver_scheme==NULL ||
+ opt.keyserver_host==NULL ||
+ opt.keyserver_port==NULL)
+ {
+ log_error(_("no keyserver known (use option --keyserver)\n"));
+ return G10ERR_BAD_URI;
+ }
+
+#ifndef USE_EXTERNAL_HKP
+ /* Use the internal HKP code */
+ if(ascii_strcasecmp(opt.keyserver_scheme,"hkp")==0)
+ {
+ void *stats_handle = import_new_stats_handle ();
+
+ switch(action)
+ {
+ case GET:
+ for(count--;count>=0;count--)
+ if(hkp_ask_import(&desc[count],stats_handle))
+ log_inc_errorcount();
+ break;
+ case SEND:
+ return hkp_export(list);
+ case SEARCH:
+ return hkp_search(list);
+ }
+
+ import_print_stats (stats_handle);
+ import_release_stats_handle (stats_handle);
+
+ return 0;
+ }
+#endif
+
+ /* It's not the internal HKP code, so try and spawn a handler for it */
+
+ rc=keyserver_spawn(action,list,desc,count,&ret);
+ if(ret)
+ {
+ switch(ret)
+ {
+ case KEYSERVER_SCHEME_NOT_FOUND:
+ log_error(_("no handler for keyserver scheme \"%s\"\n"),
+ opt.keyserver_scheme);
+ break;
+
+ case KEYSERVER_NOT_SUPPORTED:
+ log_error(_("action \"%s\" not supported with keyserver "
+ "scheme \"%s\"\n"),
+ action==GET?"get":action==SEND?"send":
+ action==SEARCH?"search":"unknown",
+ opt.keyserver_scheme);
+
+ case KEYSERVER_INTERNAL_ERROR:
+ default:
+ log_error(_("keyserver internal error\n"));
+ break;
+ }
+
+ return G10ERR_KEYSERVER;
+ }
+
+ if(rc)
+ {
+ log_error(_("keyserver communications error: %s\n"),g10_errstr(rc));
+
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+keyserver_export(STRLIST users)
+{
+ /* We better ask for confirmation when the user entered --send-keys
+ without arguments. Sending all keys might not be the thing he
+ intended to do */
+ if (users || opt.batch || opt.answer_yes)
+ ;
+ else if ( !cpr_get_answer_is_yes
+ ("keyserver_export.send_all",
+ _("Do you really want to send all your "
+ "public keys to the keyserver? (y/N) ")))
+ return -1;
+
+ return keyserver_work(SEND,users,NULL,0);
+}
+
+int
+keyserver_import(STRLIST users)
+{
+ KEYDB_SEARCH_DESC *desc;
+ int num=100,count=0;
+ int rc=0;
+
+ /* Build a list of key ids */
+ desc=m_alloc(sizeof(KEYDB_SEARCH_DESC)*num);
+
+ for(;users;users=users->next)
+ {
+ classify_user_id (users->d, &desc[count]);
+ if(desc[count].mode!=KEYDB_SEARCH_MODE_SHORT_KID &&
+ desc[count].mode!=KEYDB_SEARCH_MODE_LONG_KID &&
+ desc[count].mode!=KEYDB_SEARCH_MODE_FPR16 &&
+ desc[count].mode!=KEYDB_SEARCH_MODE_FPR20)
+ {
+ log_error(_("skipping invalid key ID \"%s\"\n"),users->d);
+ continue;
+ }
+
+ count++;
+ if(count==num)
+ {
+ num+=100;
+ desc=m_realloc(desc,sizeof(KEYDB_SEARCH_DESC)*num);
+ }
+ }
+
+ if(count>0)
+ rc=keyserver_work(GET,NULL,desc,count);
+
+ m_free(desc);
+
+ return rc;
+}
+
+int
+keyserver_import_fprint(const byte *fprint,size_t fprint_len)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset(&desc,0,sizeof(desc));
+
+ if(fprint_len==16)
+ desc.mode=KEYDB_SEARCH_MODE_FPR16;
+ else if(fprint_len==20)
+ desc.mode=KEYDB_SEARCH_MODE_FPR20;
+ else
+ return -1;
+
+ memcpy(desc.u.fpr,fprint,fprint_len);
+
+ return keyserver_work(GET,NULL,&desc,1);
+}
+
+int
+keyserver_import_keyid(u32 *keyid)
+{
+ KEYDB_SEARCH_DESC desc;
+
+ memset(&desc,0,sizeof(desc));
+
+ desc.mode=KEYDB_SEARCH_MODE_LONG_KID;
+ desc.u.kid[0]=keyid[0];
+ desc.u.kid[1]=keyid[1];
+
+ return keyserver_work(GET,NULL,&desc,1);
+}
+
+/* code mostly stolen from do_export_stream */
+static int
+keyidlist(STRLIST users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
+{
+ int rc=0,ndesc,num=100;
+ KBNODE keyblock=NULL,node;
+ KEYDB_HANDLE kdbhd;
+ KEYDB_SEARCH_DESC *desc;
+ STRLIST sl;
+
+ *count=0;
+
+ *klist=m_alloc(sizeof(KEYDB_SEARCH_DESC)*num);
+
+ kdbhd=keydb_new(0);
+
+ if(!users)
+ {
+ ndesc = 1;
+ desc = m_alloc_clear ( ndesc * sizeof *desc);
+ desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
+ }
+ else
+ {
+ for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
+ ;
+ desc = m_alloc ( ndesc * sizeof *desc);
+
+ for (ndesc=0, sl=users; sl; sl = sl->next)
+ {
+ if(classify_user_id (sl->d, desc+ndesc))
+ ndesc++;
+ else
+ log_error (_("key `%s' not found: %s\n"),
+ sl->d, g10_errstr (G10ERR_INV_USER_ID));
+ }
+ }
+
+ while (!(rc = keydb_search (kdbhd, desc, ndesc)))
+ {
+ if (!users)
+ desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
+
+ /* read the keyblock */
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
+ if( rc )
+ {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY)))
+ {
+ /* This is to work around a bug in some keyservers (pksd and
+ OKS) that calculate v4 RSA keyids as if they were v3 RSA.
+ The answer is to refresh both the correct v4 keyid
+ (e.g. 99242560) and the fake v3 keyid (e.g. 68FDDBC7).
+ This only happens for key refresh using the HKP scheme
+ and if the refresh-add-fake-v3-keyids keyserver option is
+ set. */
+ if(fakev3 && is_RSA(node->pkt->pkt.public_key->pubkey_algo) &&
+ node->pkt->pkt.public_key->version>=4)
+ {
+ (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
+ mpi_get_keyid(node->pkt->pkt.public_key->pkey[0],
+ (*klist)[*count].u.kid);
+ (*count)++;
+
+ if(*count==num)
+ {
+ num+=100;
+ *klist=m_realloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
+ }
+ }
+
+ /* v4 keys get full fingerprints. v3 keys get long keyids.
+ This is because it's easy to calculate any sort of key id
+ from a v4 fingerprint, but not a v3 fingerprint. */
+
+ if(node->pkt->pkt.public_key->version<4)
+ {
+ (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
+ keyid_from_pk(node->pkt->pkt.public_key,
+ (*klist)[*count].u.kid);
+ }
+ else
+ {
+ size_t dummy;
+
+ (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20;
+ fingerprint_from_pk(node->pkt->pkt.public_key,
+ (*klist)[*count].u.fpr,&dummy);
+ }
+
+ (*count)++;
+
+ if(*count==num)
+ {
+ num+=100;
+ *klist=m_realloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
+ }
+ }
+ }
+
+ if(rc==-1)
+ rc=0;
+
+ leave:
+ m_free(desc);
+ keydb_release(kdbhd);
+ release_kbnode(keyblock);
+
+ return rc;
+}
+
+/* Note this is different than the original HKP refresh. It allows
+ usernames to refresh only part of the keyring. */
+
+int
+keyserver_refresh(STRLIST users)
+{
+ int rc,count,fakev3=0;
+ KEYDB_SEARCH_DESC *desc;
+
+ /* We switch merge_only on during a refresh, as 'refresh' should
+ never import new keys, even if their keyids match. Is it worth
+ preserving the old merge_only value here? */
+ opt.merge_only=1;
+
+ /* If refresh_add_fake_v3_keyids is on and it's a HKP or MAILTO
+ scheme, then enable fake v3 keyid generation. */
+ if(opt.keyserver_options.fake_v3_keyids && opt.keyserver_scheme &&
+ (ascii_strcasecmp(opt.keyserver_scheme,"hkp")==0 ||
+ ascii_strcasecmp(opt.keyserver_scheme,"mailto")==0))
+ fakev3=1;
+
+ rc=keyidlist(users,&desc,&count,fakev3);
+ if(rc)
+ return rc;
+
+ if(count==1)
+ log_info(_("%d key to refresh\n"),count);
+ else
+ log_info(_("%d keys to refresh\n"),count);
+
+ if(count>0)
+ rc=keyserver_work(GET,NULL,desc,count);
+
+ m_free(desc);
+
+ return 0;
+}
+
+int
+keyserver_search(STRLIST tokens)
+{
+ if(tokens)
+ return keyserver_work(SEARCH,tokens,NULL,0);
+ else
+ return 0;
+}
+
+/* Count and searchstr are just for cosmetics. If the count is too
+ small, it will grow safely. If negative it disables the "Key x-y
+ of z" messages. */
+void
+keyserver_search_prompt(IOBUF buffer,int count,const char *searchstr)
+{
+ int i=0,validcount=1;
+ unsigned int maxlen=256,buflen=0;
+ KEYDB_SEARCH_DESC *desc;
+ byte *line=NULL;
+ char *answer;
+
+ if(count==0)
+ goto notfound;
+
+ if(count<0)
+ {
+ validcount=0;
+ count=10;
+ }
+
+ desc=m_alloc(count*sizeof(KEYDB_SEARCH_DESC));
+
+ /* Read each line and show it to the user */
+
+ for(;;)
+ {
+ int rl;
+
+ if(validcount && i%10==0)
+ {
+ printf("Keys %d-%d of %d",i+1,(i+10<count)?i+10:count,count);
+ if(searchstr)
+ printf(" for \"%s\"",searchstr);
+ printf("\n");
+ }
+
+ maxlen=1024;
+ rl=iobuf_read_line(buffer,&line,&buflen,&maxlen);
+ if(rl>0)
+ {
+ if(print_keyinfo(i+1,line,&desc[i])==0)
+ {
+ i++;
+
+ if(i==count)
+ {
+ count+=10;
+ desc=m_realloc(desc,count*sizeof(KEYDB_SEARCH_DESC));
+ validcount=0;
+ }
+ }
+ else
+ continue;
+ }
+
+ if(rl==0 && i==0)
+ {
+ count=0;
+ break;
+ }
+
+ if(i%10==0 || rl==0)
+ {
+ answer=cpr_get_no_help("keysearch.prompt",
+ _("Enter number(s), N)ext, or Q)uit > "));
+ /* control-d */
+ if(answer[0]=='\x04')
+ {
+ printf("Q\n");
+ answer[0]='q';
+ }
+
+ if(answer[0]=='q' || answer[0]=='Q')
+ {
+ m_free(answer);
+ break;
+ }
+ else if(atoi(answer)>=1 && atoi(answer)<=i)
+ {
+ char *split=answer,*num;
+
+ while((num=strsep(&split," ,"))!=NULL)
+ if(atoi(num)>=1 && atoi(num)<=i)
+ keyserver_work(GET,NULL,&desc[atoi(num)-1],1);
+
+ m_free(answer);
+ break;
+ }
+ }
+ }
+
+ m_free(desc);
+ m_free(line);
+
+ notfound:
+ if(count==0)
+ {
+ if(searchstr)
+ log_info(_("key \"%s\" not found on keyserver\n"),searchstr);
+ else
+ log_info(_("key not found on keyserver\n"));
+ return;
+ }
+}
diff --git a/g10/ks-proto.c b/g10/ks-proto.c
index 43abf468a..aa7dc56e0 100644
--- a/g10/ks-proto.c
+++ b/g10/ks-proto.c
@@ -1,5 +1,5 @@
/* ks-proto.c keyserver protocol handling
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
diff --git a/g10/ks-proto.h b/g10/ks-proto.h
index 6e8bbad0b..cd55b47e2 100644
--- a/g10/ks-proto.h
+++ b/g10/ks-proto.h
@@ -1,5 +1,5 @@
/* ks-proto.h
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_KS_PROTO_H
-#define GPG_KS_PROTO_H
+#ifndef G10_KS_PROTO_H
+#define G10_KS_PROTO_H
-#endif /*GPG_KS_PROTO_H*/
+#endif /*G10_KS_PROTO_H*/
diff --git a/g10/main.h b/g10/main.h
index d199c5484..e7153bd55 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -1,5 +1,5 @@
/* main.h
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -17,30 +17,39 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_MAIN_H
-#define GPG_MAIN_H
-
-#include <gcrypt.h>
-#include "basicdefs.h"
+#ifndef G10_MAIN_H
+#define G10_MAIN_H
+#include "types.h"
#include "iobuf.h"
+#include "mpi.h"
+#include "cipher.h"
#include "keydb.h"
-#define DEFAULT_CIPHER_ALGO GCRY_CIPHER_BLOWFISH
-#define DEFAULT_PUBKEY_ALGO GCRY_PUBKEY_ELGAMAL
-#define DEFAULT_DIGEST_ALGO GCRY_MD_RMD160
+#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5
+#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL
+#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1
+#define DEFAULT_COMPRESS_ALGO 1
-#define is_RSA(a) ((a)==GCRY_PK_RSA || (a)==GCRY_PK_RSA_E \
- || (a)==GCRY_PK_RSA_S )
-#define is_ELGAMAL(a) ((a)==GCRY_PK_ELG || (a)==GCRY_PK_ELG_E)
+typedef struct {
+ int header_okay;
+ PK_LIST pk_list;
+ cipher_filter_context_t cfx;
+} encrypt_filter_context_t;
+struct groupitem
+{
+ char *name;
+ STRLIST values;
+ struct groupitem *next;
+};
-/*-- gpg.c --*/
-extern int gpg_errors_seen;
+/*-- g10.c --*/
+extern int g10_errors_seen;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
- void gpg_exit(int rc) __attribute__ ((noreturn));
+ void g10_exit(int rc) __attribute__ ((noreturn));
#else
- void gpg_exit(int rc);
+ void g10_exit(int rc);
#endif
void print_pubkey_algo_note( int algo );
void print_cipher_algo_note( int algo );
@@ -55,24 +64,29 @@ int disable_core_dumps(void);
u16 checksum_u16( unsigned n );
u16 checksum( byte *p, unsigned n );
u16 checksum_mpi( MPI a );
+u16 checksum_mpi_counted_nbits( MPI a );
u32 buffer_to_u32( const byte *buffer );
-
-int mpi_write( IOBUF out, GCRY_MPI a );
-int mpi_write_opaque( IOBUF out, MPI a );
-GCRY_MPI mpi_read(IOBUF inp, unsigned int *ret_nread, int secure );
-GCRY_MPI mpi_read_opaque(IOBUF inp, unsigned int *ret_nread );
-int mpi_print( FILE *fp, MPI a, int mode );
-
+const byte *get_session_marker( size_t *rlen );
int openpgp_cipher_test_algo( int algo );
int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
int openpgp_pk_algo_usage ( int algo );
int openpgp_md_test_algo( int algo );
-
-int pubkey_get_npkey( int algo );
-int pubkey_get_nskey( int algo );
-int pubkey_get_nsig( int algo );
-int pubkey_get_nenc( int algo );
-unsigned int pubkey_nbits( int algo, MPI *pkey );
+int check_permissions(const char *path,int extension,int checkonly);
+void idea_cipher_warn( int show );
+
+struct expando_args
+{
+ PKT_public_key *pk;
+ PKT_secret_key *sk;
+ byte imagetype;
+};
+
+char *pct_expando(const char *string,struct expando_args *args);
+int hextobyte( const char *s );
+void deprecated_warning(const char *configname,unsigned int configlineno,
+ const char *option,const char *repl1,const char *repl2);
+const char *compress_algo_to_string(int algo);
+int check_compress_algo(int algo);
/*-- helptext.c --*/
void display_online_help( const char *keyword );
@@ -81,15 +95,17 @@ void display_online_help( const char *keyword );
int encode_symmetric( const char *filename );
int encode_store( const char *filename );
int encode_crypt( const char *filename, STRLIST remusr );
+void encode_crypt_files(int nfiles, char **files, STRLIST remusr);
int encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len);
/*-- sign.c --*/
-int complete_sig( PKT_signature *sig, PKT_secret_key *sk, GCRY_MD_HD md );
+int complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md );
int sign_file( STRLIST filenames, int detached, STRLIST locusr,
int do_encrypt, STRLIST remusr, const char *outfile );
int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
+int sign_symencrypt_file (const char *fname, STRLIST locusr);
/*-- sig-check.c --*/
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
@@ -97,17 +113,22 @@ int check_key_signature2( KBNODE root, KBNODE node,
int *is_selfsig, u32 *r_expiredate, int *r_expired );
/*-- delkey.c --*/
-int delete_key( const char *username, int secure );
+int delete_keys( STRLIST names, int secret, int allow_both );
/*-- keyedit.c --*/
void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds,
int sign_mode );
/*-- keygen.c --*/
+u32 ask_expire_interval(int object);
u32 ask_expiredate(void);
void generate_keypair( const char *fname );
+int keygen_set_std_prefs (const char *string,int personal);
+char *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
+int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
+int keygen_add_revkey(PKT_signature *sig, void *opaque);
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
/*-- openfile.c --*/
@@ -121,16 +142,20 @@ void try_make_homedir( const char *fname );
/*-- seskey.c --*/
void make_session_key( DEK *dek );
MPI encode_session_key( DEK *dek, unsigned nbits );
-MPI encode_md_value( int pubkey_algo, GCRY_MD_HD md,
+MPI encode_md_value( int pubkey_algo, MD_HANDLE md,
int hash_algo, unsigned nbits, int v3compathack );
/*-- comment.c --*/
-KBNODE make_comment_node_from_buffer( const char *s, size_t n );
KBNODE make_comment_node( const char *s );
+KBNODE make_mpi_comment_node( const char *s, MPI a );
/*-- import.c --*/
-void import_keys( char **fnames, int nnames, int fast );
-int import_keys_stream( IOBUF inp, int fast );
+void import_keys( char **fnames, int nnames, int fast, void *stats_hd );
+int import_keys_stream( IOBUF inp, int fast, void *stats_hd );
+void *import_new_stats_handle (void);
+void import_release_stats_handle (void *p);
+void import_print_stats (void *hd);
+
int collapse_uids( KBNODE *keyblock );
/*-- export.c --*/
@@ -146,6 +171,7 @@ int enarmor_file( const char *fname );
/*-- revoke.c --*/
struct revocation_reason_info;
int gen_revoke( const char *uname );
+int gen_desig_revoke( const char *uname );
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint );
@@ -154,22 +180,32 @@ void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
void public_key_list( STRLIST list );
void secret_key_list( STRLIST list );
+void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque );
+void print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode);
+void show_policy_url(PKT_signature *sig,int indent);
+void show_notation(PKT_signature *sig,int indent);
+void set_attrib_fd(int fd);
/*-- verify.c --*/
+void print_file_status( int status, const char *name, int what );
int verify_signatures( int nfiles, char **files );
int verify_files( int nfiles, char **files );
/*-- decrypt.c --*/
int decrypt_message( const char *filename );
+void decrypt_messages(int nfiles, char **files);
/*-- plaintext.c --*/
-int hash_datafiles( GCRY_MD_HD md, GCRY_MD_HD md2,
+int hash_datafiles( MD_HANDLE md, MD_HANDLE md2,
STRLIST files, const char *sigfilename, int textmode );
+/*-- pipemode.c --*/
+void run_in_pipemode (void);
+
/*-- signal.c --*/
void init_signals(void);
void pause_on_sigusr( int which );
void block_all_signals(void);
void unblock_all_signals(void);
-#endif /*GPG_MAIN_H*/
+#endif /*G10_MAIN_H*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 7b04b3e6f..bcd1c1c01 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -1,5 +1,5 @@
/* mainproc.c - handle packets
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,18 +25,19 @@
#include <assert.h>
#include <time.h>
-#include <gcrypt.h>
#include "packet.h"
#include "iobuf.h"
+#include "memory.h"
#include "options.h"
#include "util.h"
+#include "cipher.h"
#include "keydb.h"
#include "filter.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
#include "trustdb.h"
-#include "hkp.h"
+#include "keyserver-internal.h"
struct kidlist_item {
@@ -69,8 +70,11 @@ struct mainproc_context {
IOBUF iobuf; /* used to get the filename etc. */
int trustletter; /* temp usage in list_node */
ulong local_id; /* ditto */
- struct kidlist_item *failed_pkenc; /* list of packets for which
- we do not have a secret key */
+ struct kidlist_item *pkenc_list; /* list of encryption packets */
+ struct {
+ int op;
+ int stop_now;
+ } pipemode;
};
@@ -87,13 +91,18 @@ release_list( CTX c )
return;
proc_tree(c, c->list );
release_kbnode( c->list );
- while( c->failed_pkenc ) {
- struct kidlist_item *tmp = c->failed_pkenc->next;
- gcry_free( c->failed_pkenc );
- c->failed_pkenc = tmp;
+ while( c->pkenc_list ) {
+ struct kidlist_item *tmp = c->pkenc_list->next;
+ m_free( c->pkenc_list );
+ c->pkenc_list = tmp;
}
- c->failed_pkenc = NULL;
+ c->pkenc_list = NULL;
c->list = NULL;
+ c->have_data = 0;
+ c->last_was_session_key = 0;
+ c->pipemode.op = 0;
+ c->pipemode.stop_now = 0;
+ m_free(c->dek); c->dek = NULL;
}
@@ -103,8 +112,14 @@ add_onepass_sig( CTX c, PACKET *pkt )
KBNODE node;
if( c->list ) { /* add another packet */
- if( c->list->pkt->pkttype != PKT_ONEPASS_SIG ) {
- log_error("add_onepass_sig: another packet is in the way\n");
+ /* We can only append another onepass packet if the list
+ * does contain only onepass packets */
+ for( node=c->list; node && node->pkt->pkttype == PKT_ONEPASS_SIG;
+ node = node->next )
+ ;
+ if( node ) {
+ /* this is not the case, so we flush the current thing and
+ * allow this packet to start a new verification thing */
release_list( c );
c->list = new_kbnode( pkt );
}
@@ -118,6 +133,48 @@ add_onepass_sig( CTX c, PACKET *pkt )
}
+static int
+add_gpg_control( CTX c, PACKET *pkt )
+{
+ if ( pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) {
+ /* New clear text signature.
+ * Process the last one and reset everything */
+ release_list(c);
+ }
+ else if ( pkt->pkt.gpg_control->control == CTRLPKT_PIPEMODE ) {
+ /* Pipemode control packet */
+ if ( pkt->pkt.gpg_control->datalen < 2 )
+ log_fatal ("invalid pipemode control packet length\n");
+ if (pkt->pkt.gpg_control->data[0] == 1) {
+ /* start the whole thing */
+ assert ( !c->list ); /* we should be in a pretty virgin state */
+ assert ( !c->pipemode.op );
+ c->pipemode.op = pkt->pkt.gpg_control->data[1];
+ }
+ else if (pkt->pkt.gpg_control->data[0] == 2) {
+ /* the signed material follows in a plaintext packet */
+ assert ( c->pipemode.op == 'B' );
+ }
+ else if (pkt->pkt.gpg_control->data[0] == 3) {
+ assert ( c->pipemode.op == 'B' );
+ release_list (c);
+ /* and tell the outer loop to terminate */
+ c->pipemode.stop_now = 1;
+ }
+ else
+ log_fatal ("invalid pipemode control packet code\n");
+ return 0; /* no need to store the packet */
+ }
+
+ if( c->list ) /* add another packet */
+ add_kbnode( c->list, new_kbnode( pkt ));
+ else /* insert the first one */
+ c->list = new_kbnode( pkt );
+
+ return 1;
+}
+
+
static int
add_user_id( CTX c, PACKET *pkt )
@@ -180,6 +237,32 @@ add_signature( CTX c, PACKET *pkt )
return 1;
}
+static void
+symkey_decrypt_sesskey( DEK *dek, byte *sesskey, size_t slen )
+{
+ CIPHER_HANDLE hd;
+
+ if ( slen < 17 || slen > 33 ) {
+ log_error( "weird size for an encrypted session key (%d)\n", slen );
+ return;
+ }
+ hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
+ cipher_setkey( hd, dek->key, dek->keylen );
+ cipher_setiv( hd, NULL, 0 );
+ cipher_decrypt( hd, sesskey, sesskey, slen );
+ cipher_close( hd );
+ /* check first byte (the cipher algo) */
+ if ( sesskey[0] > 10 ) {
+ log_error( "invalid symkey algorithm detected (%d)\n", sesskey[0] );
+ return;
+ }
+ /* now we replace the dek components with the real session key
+ to decrypt the contents of the sequencing packet. */
+ dek->keylen = cipher_get_keylen( sesskey[0] ) / 8;
+ dek->algo = sesskey[0];
+ memcpy( dek->key, sesskey + 1, dek->keylen );
+ /*log_hexdump( "thekey", dek->key, dek->keylen );*/
+}
static void
proc_symkey_enc( CTX c, PACKET *pkt )
@@ -187,12 +270,28 @@ proc_symkey_enc( CTX c, PACKET *pkt )
PKT_symkey_enc *enc;
enc = pkt->pkt.symkey_enc;
- if( enc->seskeylen )
- log_error( "symkey_enc packet with session keys are not supported!\n");
+ if (!enc)
+ log_error ("invalid symkey encrypted packet\n");
else {
+ int algo = enc->cipher_algo;
+ const char *s;
+
+ s = cipher_algo_to_string (algo);
+ if( s )
+ log_info(_("%s encrypted data\n"), s );
+ else
+ log_info(_("encrypted with unknown algorithm %d\n"), algo );
+
c->last_was_session_key = 2;
- c->dek = passphrase_to_dek( NULL, 0, enc->cipher_algo, &enc->s2k, 0 );
+ if ( opt.list_only )
+ goto leave;
+ c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL );
+ if (c->dek)
+ c->dek->algo_info_printed = 1;
+ if ( c->dek && enc->seskeylen )
+ symkey_decrypt_sesskey( c->dek, enc->seskey, enc->seskeylen );
}
+leave:
free_packet(pkt);
}
@@ -218,42 +317,64 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
write_status_text( STATUS_ENC_TO, buf );
}
-
- if( is_ELGAMAL(enc->pubkey_algo)
- || enc->pubkey_algo == GCRY_PK_DSA
+ if( !opt.list_only && opt.override_session_key ) {
+ /* It does not make much sense to store the session key in
+ * secure memory because it has already been passed on the
+ * command line and the GCHQ knows about it */
+ c->dek = m_alloc_clear( sizeof *c->dek );
+ result = get_override_session_key ( c->dek, opt.override_session_key );
+ if ( result ) {
+ m_free(c->dek); c->dek = NULL;
+ }
+ }
+ else if( is_ELGAMAL(enc->pubkey_algo)
+ || enc->pubkey_algo == PUBKEY_ALGO_DSA
|| is_RSA(enc->pubkey_algo) ) {
if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1])
+ || opt.try_all_secrets
|| !seckey_available( enc->keyid )) ) {
if( opt.list_only )
result = -1;
else {
- c->dek = gcry_xmalloc_secure( sizeof *c->dek );
+ c->dek = m_alloc_secure_clear( sizeof *c->dek );
if( (result = get_session_key( enc, c->dek )) ) {
/* error: delete the DEK */
- gcry_free(c->dek); c->dek = NULL;
+ m_free(c->dek); c->dek = NULL;
}
}
}
else
- result = GPGERR_NO_SECKEY;
+ result = G10ERR_NO_SECKEY;
}
else
- result = GPGERR_PUBKEY_ALGO;
+ result = G10ERR_PUBKEY_ALGO;
if( result == -1 )
;
- else if( !result ) {
- if( opt.verbose > 1 )
- log_info( _("public key encrypted data: good DEK\n") );
- }
- else { /* store it for later display */
- struct kidlist_item *x = gcry_xmalloc( sizeof *x );
- x->kid[0] = enc->keyid[0];
- x->kid[1] = enc->keyid[1];
- x->pubkey_algo = enc->pubkey_algo;
- x->reason = result;
- x->next = c->failed_pkenc;
- c->failed_pkenc = x;
+ else {
+ if( !result ) {
+ if( opt.verbose > 1 )
+ log_info( _("public key encrypted data: good DEK\n") );
+ if ( opt.show_session_key ) {
+ int i;
+ char *buf = m_alloc ( c->dek->keylen*2 + 20 );
+ sprintf ( buf, "%d:", c->dek->algo );
+ for(i=0; i < c->dek->keylen; i++ )
+ sprintf(buf+strlen(buf), "%02X", c->dek->key[i] );
+ log_info( "session key: \"%s\"\n", buf );
+ write_status_text ( STATUS_SESSION_KEY, buf );
+ }
+ }
+ /* store it for later display */
+ {
+ struct kidlist_item *x = m_alloc( sizeof *x );
+ x->kid[0] = enc->keyid[0];
+ x->kid[1] = enc->keyid[1];
+ x->pubkey_algo = enc->pubkey_algo;
+ x->reason = result;
+ x->next = c->pkenc_list;
+ c->pkenc_list = x;
+ }
}
free_packet(pkt);
}
@@ -265,11 +386,19 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
* not decrypt.
*/
static void
-print_failed_pkenc( struct kidlist_item *list )
+print_pkenc_list( struct kidlist_item *list, int failed )
{
for( ; list; list = list->next ) {
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- const char *algstr = gcry_pk_algo_name( list->pubkey_algo );
+ PKT_public_key *pk;
+ const char *algstr;
+
+ if ( failed && !list->reason )
+ continue;
+ if ( !failed && list->reason )
+ continue;
+
+ algstr = pubkey_algo_to_string( list->pubkey_algo );
+ pk = m_alloc_clear( sizeof *pk );
if( !algstr )
algstr = "[?]";
@@ -282,8 +411,8 @@ print_failed_pkenc( struct kidlist_item *list )
strtimestamp(pk->timestamp) );
fputs(" \"", log_stream() );
p = get_user_id( list->kid, &n );
- print_string( log_stream(), p, n, '"' );
- gcry_free(p);
+ print_utf8_string2 ( log_stream(), p, n, '"' );
+ m_free(p);
fputs("\"\n", log_stream() );
}
else {
@@ -292,8 +421,7 @@ print_failed_pkenc( struct kidlist_item *list )
}
free_public_key( pk );
- if( list->reason == GPGERR_NO_SECKEY ) {
- log_info(_("no secret key for decryption available\n"));
+ if( list->reason == G10ERR_NO_SECKEY ) {
if( is_status_enabled() ) {
char buf[20];
sprintf(buf,"%08lX%08lX", (ulong)list->kid[0],
@@ -301,9 +429,9 @@ print_failed_pkenc( struct kidlist_item *list )
write_status_text( STATUS_NO_SECKEY, buf );
}
}
- else
+ else if (list->reason)
log_error(_("public key decryption failed: %s\n"),
- gpg_errstr(list->reason));
+ g10_errstr(list->reason));
}
}
@@ -313,7 +441,10 @@ proc_encrypted( CTX c, PACKET *pkt )
{
int result = 0;
- print_failed_pkenc( c->failed_pkenc );
+ if (!opt.quiet) {
+ print_pkenc_list ( c->pkenc_list, 1 );
+ print_pkenc_list ( c->pkenc_list, 0 );
+ }
write_status( STATUS_BEGIN_DECRYPTION );
@@ -321,19 +452,43 @@ proc_encrypted( CTX c, PACKET *pkt )
if( opt.list_only )
result = -1;
else if( !c->dek && !c->last_was_session_key ) {
- /* assume this is old conventional encrypted data
- * Actually we should use IDEA and MD5 in this case, but because
- * IDEA is patented we can't do so */
- c->dek = passphrase_to_dek( NULL, 0,
- opt.def_cipher_algo ? opt.def_cipher_algo
- : DEFAULT_CIPHER_ALGO, NULL, 0 );
+ int algo;
+ STRING2KEY s2kbuf, *s2k = NULL;
+
+ /* assume this is old style conventional encrypted data */
+ if ( (algo = opt.def_cipher_algo))
+ log_info (_("assuming %s encrypted data\n"),
+ cipher_algo_to_string(algo));
+ else if ( check_cipher_algo(CIPHER_ALGO_IDEA) ) {
+ algo = opt.def_cipher_algo;
+ if (!algo)
+ algo = opt.s2k_cipher_algo;
+ idea_cipher_warn(1);
+ log_info (_("IDEA cipher unavailable, "
+ "optimistically attempting to use %s instead\n"),
+ cipher_algo_to_string(algo));
+ }
+ else {
+ algo = CIPHER_ALGO_IDEA;
+ if (!opt.def_digest_algo) {
+ /* If no digest is given we assume MD5 */
+ s2kbuf.mode = 0;
+ s2kbuf.hash_algo = DIGEST_ALGO_MD5;
+ s2k = &s2kbuf;
+ }
+ log_info (_("assuming %s encrypted data\n"), "IDEA");
+ }
+
+ c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 0, NULL );
+ if (c->dek)
+ c->dek->algo_info_printed = 1;
}
else if( !c->dek )
- result = GPGERR_NO_SECKEY;
+ result = G10ERR_NO_SECKEY;
if( !result )
result = decrypt_data( c, pkt->pkt.encrypted, c->dek );
- gcry_free(c->dek); c->dek = NULL;
+ m_free(c->dek); c->dek = NULL;
if( result == -1 )
;
else if( !result ) {
@@ -343,13 +498,13 @@ proc_encrypted( CTX c, PACKET *pkt )
if( pkt->pkt.encrypted->mdc_method )
write_status( STATUS_GOODMDC );
}
- else if( result == GPGERR_BAD_SIGN ) {
+ else if( result == G10ERR_BAD_SIGN ) {
log_error(_("WARNING: encrypted message has been manipulated!\n"));
write_status( STATUS_BADMDC );
}
else {
write_status( STATUS_DECRYPTION_FAILED );
- log_error(_("decryption failed: %s\n"), gpg_errstr(result));
+ log_error(_("decryption failed: %s\n"), g10_errstr(result));
/* Hmmm: does this work when we have encrypted using multiple
* ways to specify the session key (symmmetric and PK)*/
}
@@ -372,9 +527,7 @@ proc_plaintext( CTX c, PACKET *pkt )
else if( opt.verbose )
log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name);
free_md_filter_context( &c->mfx );
- c->mfx.md = gcry_md_open( 0, 0);
- if( !c->mfx.md )
- BUG();
+ c->mfx.md = md_open( 0, 0);
/* fixme: we may need to push the textfilter if we have sigclass 1
* and no armoring - Not yet tested
* Hmmm, why don't we need it at all if we have sigclass 1
@@ -385,9 +538,9 @@ proc_plaintext( CTX c, PACKET *pkt )
for(n=c->list; n; n = n->next ) {
if( n->pkt->pkttype == PKT_ONEPASS_SIG ) {
if( n->pkt->pkt.onepass_sig->digest_algo ) {
- gcry_md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo );
+ md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo );
if( !any && n->pkt->pkt.onepass_sig->digest_algo
- == GCRY_MD_MD5 )
+ == DIGEST_ALGO_MD5 )
only_md5 = 1;
else
only_md5 = 0;
@@ -395,27 +548,31 @@ proc_plaintext( CTX c, PACKET *pkt )
}
if( n->pkt->pkt.onepass_sig->sig_class != 0x01 )
only_md5 = 0;
-
- /* Check whether this is a cleartext signature. We assume that
- * we have one if the sig_class is 1 and the keyid is 0, that
- * are the faked packets produced by armor.c. There is a
- * possibility that this fails, but there is no other easy way
- * to do it. (We could use a special packet type to indicate
- * this, but this may also be faked - it simply can't be verified
- * and is _no_ security issue)
- */
- if( n->pkt->pkt.onepass_sig->sig_class == 0x01
- && !n->pkt->pkt.onepass_sig->keyid[0]
- && !n->pkt->pkt.onepass_sig->keyid[1] )
- clearsig = 1;
}
+ else if( n->pkt->pkttype == PKT_GPG_CONTROL
+ && n->pkt->pkt.gpg_control->control
+ == CTRLPKT_CLEARSIGN_START ) {
+ size_t datalen = n->pkt->pkt.gpg_control->datalen;
+ const byte *data = n->pkt->pkt.gpg_control->data;
+
+ /* check that we have at least the sigclass and one hash */
+ if ( datalen < 2 )
+ log_fatal("invalid control packet CTRLPKT_CLEARSIGN_START\n");
+ /* Note that we don't set the clearsig flag for not-dash-escaped
+ * documents */
+ clearsig = (*data == 0x01);
+ for( data++, datalen--; datalen; datalen--, data++ )
+ md_enable( c->mfx.md, *data );
+ any = 1;
+ break; /* no pass signature pakets are expected */
+ }
}
if( !any && !opt.skip_verify ) {
/* no onepass sig packet: enable all standard algos */
- gcry_md_enable( c->mfx.md, GCRY_MD_RMD160 );
- gcry_md_enable( c->mfx.md, GCRY_MD_SHA1 );
- gcry_md_enable( c->mfx.md, GCRY_MD_MD5 );
+ md_enable( c->mfx.md, DIGEST_ALGO_RMD160 );
+ md_enable( c->mfx.md, DIGEST_ALGO_SHA1 );
+ md_enable( c->mfx.md, DIGEST_ALGO_MD5 );
}
if( opt.pgp2_workarounds && only_md5 && !opt.skip_verify ) {
/* This is a kludge to work around a bug in pgp2. It does only
@@ -423,25 +580,36 @@ proc_plaintext( CTX c, PACKET *pkt )
* pgp mails we could see whether there is the signature packet
* in front of the plaintext. If someone needs this, send me a patch.
*/
- c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0);
- if( !c->mfx.md2 )
- BUG();
+ c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0);
}
if ( DBG_HASHING ) {
- gcry_md_start_debug( c->mfx.md, "verify" );
+ md_start_debug( c->mfx.md, "verify" );
if ( c->mfx.md2 )
- gcry_md_start_debug( c->mfx.md2, "verify2" );
+ md_start_debug( c->mfx.md2, "verify2" );
}
- rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig );
- if( rc == GPGERR_CREATE_FILE && !c->sigs_only) {
- /* can't write output but we hash it anyway to
- * check the signature */
- rc = handle_plaintext( pt, &c->mfx, 1, clearsig );
+ if ( c->pipemode.op == 'B' )
+ rc = handle_plaintext( pt, &c->mfx, 1, 0 );
+ else {
+ rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig );
+ if( rc == G10ERR_CREATE_FILE && !c->sigs_only) {
+ /* can't write output but we hash it anyway to
+ * check the signature */
+ rc = handle_plaintext( pt, &c->mfx, 1, clearsig );
+ }
}
if( rc )
- log_error( "handle plaintext failed: %s\n", gpg_errstr(rc));
+ log_error( "handle plaintext failed: %s\n", g10_errstr(rc));
free_packet(pkt);
c->last_was_session_key = 0;
+
+ /* We add a marker control packet instead of the plaintext packet.
+ * This is so that we can later detect invalid packet sequences.
+ */
+ n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0));
+ if (c->list)
+ add_kbnode (c->list, n);
+ else
+ c->list = n;
}
@@ -472,7 +640,7 @@ proc_compressed( CTX c, PACKET *pkt )
else
rc = handle_compressed( c, zd, NULL, NULL );
if( rc )
- log_error("uncompressing failed: %s\n", gpg_errstr(rc));
+ log_error("uncompressing failed: %s\n", g10_errstr(rc));
free_packet(pkt);
c->last_was_session_key = 0;
}
@@ -482,11 +650,15 @@ proc_compressed( CTX c, PACKET *pkt )
* Returns: 0 = valid signature or an error code
*/
static int
-do_check_sig( CTX c, KBNODE node, int *is_selfsig )
+do_check_sig( CTX c, KBNODE node, int *is_selfsig, int *is_expkey )
{
PKT_signature *sig;
- GCRY_MD_HD md = NULL, md2 = NULL;
- int algo, rc;
+ MD_HANDLE md = NULL, md2 = NULL;
+ int algo, rc, dum2;
+ u32 dummy;
+
+ if(!is_expkey)
+ is_expkey=&dum2;
assert( node->pkt->pkttype == PKT_SIGNATURE );
if( is_selfsig )
@@ -494,42 +666,35 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig )
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
- if( (rc=openpgp_md_test_algo(algo)) )
+ if( (rc=check_digest_algo(algo)) )
return rc;
if( sig->sig_class == 0x00 ) {
if( c->mfx.md )
- md = gcry_md_copy( c->mfx.md );
+ md = md_copy( c->mfx.md );
else /* detached signature */
- md = gcry_md_open( 0, 0 ); /* signature_check() will enable the md*/
- if( !md )
- BUG();
+ md = md_open( 0, 0 ); /* signature_check() will enable the md*/
}
else if( sig->sig_class == 0x01 ) {
/* how do we know that we have to hash the (already hashed) text
* in canonical mode ??? (calculating both modes???) */
if( c->mfx.md ) {
- md = gcry_md_copy( c->mfx.md );
- if( !md )
- BUG();
- if( c->mfx.md2 ) {
- md2 = gcry_md_copy( c->mfx.md2 );
- if( !md2 )
- BUG();
- }
+ md = md_copy( c->mfx.md );
+ if( c->mfx.md2 )
+ md2 = md_copy( c->mfx.md2 );
}
else { /* detached signature */
- log_debug("Do we really need this here?");
- md = gcry_md_open( 0, 0 ); /* signature_check() will enable the md*/
- md2 = gcry_md_open( 0, 0 );
- if( !md || !md2 )
- BUG();
+ log_debug("Do we really need this here?");
+ md = md_open( 0, 0 ); /* signature_check() will enable the md*/
+ md2 = md_open( 0, 0 );
}
}
else if( (sig->sig_class&~3) == 0x10
|| sig->sig_class == 0x18
+ || sig->sig_class == 0x1f
|| sig->sig_class == 0x20
- || sig->sig_class == 0x30 ) { /* classes 0x10..0x17,0x20,0x30 */
+ || sig->sig_class == 0x28
+ || sig->sig_class == 0x30 ) {
if( c->list->pkt->pkttype == PKT_PUBLIC_KEY
|| c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
return check_key_signature( c->list, node, is_selfsig );
@@ -537,21 +702,21 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig )
else if( sig->sig_class == 0x20 ) {
log_info(_("standalone revocation - "
"use \"gpg --import\" to apply\n"));
- return GPGERR_NOT_PROCESSED;
+ return G10ERR_NOT_PROCESSED;
}
else {
log_error("invalid root packet for sigclass %02x\n",
sig->sig_class);
- return GPGERR_SIG_CLASS;
+ return G10ERR_SIG_CLASS;
}
}
else
- return GPGERR_SIG_CLASS;
- rc = signature_check( sig, md );
- if( rc == GPGERR_BAD_SIGN && md2 )
- rc = signature_check( sig, md2 );
- gcry_md_close(md);
- gcry_md_close(md2);
+ return G10ERR_SIG_CLASS;
+ rc = signature_check2( sig, md, &dummy, is_expkey );
+ if( rc == G10ERR_BAD_SIGN && md2 )
+ rc = signature_check2( sig, md2, &dummy, is_expkey );
+ md_close(md);
+ md_close(md2);
return rc;
}
@@ -567,8 +732,15 @@ print_userid( PACKET *pkt )
return;
}
if( opt.with_colons )
- print_string( stdout, pkt->pkt.user_id->name,
- pkt->pkt.user_id->len, ':');
+ {
+ if(pkt->pkt.user_id->attrib_data)
+ printf("%u %lu",
+ pkt->pkt.user_id->numattribs,
+ pkt->pkt.user_id->attrib_len);
+ else
+ print_string( stdout, pkt->pkt.user_id->name,
+ pkt->pkt.user_id->len, ':');
+ }
else
print_utf8_string( stdout, pkt->pkt.user_id->name,
pkt->pkt.user_id->len );
@@ -576,51 +748,13 @@ print_userid( PACKET *pkt )
static void
-print_fingerprint( PKT_public_key *pk, PKT_secret_key *sk )
-{
- byte array[MAX_FINGERPRINT_LEN], *p;
- size_t i, n;
-
- if( sk )
- fingerprint_from_sk( sk, array, &n );
- else
- fingerprint_from_pk( pk, array, &n );
- p = array;
- if( opt.with_colons ) {
- printf("fpr:::::::::");
- for(i=0; i < n ; i++, p++ )
- printf("%02X", *p );
- putchar(':');
- }
- else {
- printf(" Key fingerprint =");
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- putchar(' ');
- printf(" %02X%02X", *p, p[1] );
- }
- }
- else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- putchar(' ');
- printf(" %02X", *p );
- }
- }
- }
- putchar('\n');
-}
-
-static void
print_notation_data( PKT_signature *sig )
{
size_t n, n1, n2;
const byte *p;
int seq = 0;
- while( (p = enum_sig_subpkt( sig->hashed_data, SIGSUBPKT_NOTATION,
- &n, &seq )) ) {
+ while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&n,&seq,NULL))) {
if( n < 8 ) {
log_info(_("WARNING: invalid notation data found\n"));
return;
@@ -639,14 +773,20 @@ print_notation_data( PKT_signature *sig )
putc( '=', log_stream() );
print_string( log_stream(), p+n1, n2, 0 );
putc( '\n', log_stream() );
+ write_status_buffer ( STATUS_NOTATION_NAME, p , n1, 0 );
+ write_status_buffer ( STATUS_NOTATION_DATA, p+n1, n2, 50 );
}
- if( (p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_POLICY, &n ) )) {
+
+ seq=0;
+
+ while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&n,&seq,NULL))) {
log_info(_("Policy: ") );
print_string( log_stream(), p, n, 0 );
putc( '\n', log_stream() );
+ write_status_buffer ( STATUS_POLICY_URL, p, n, 0 );
}
- /* Now check wheter the key of this signature has some
+ /* Now check whether the key of this signature has some
* notation data */
/* TODO */
@@ -675,7 +815,7 @@ list_node( CTX c, KBNODE node )
if( mainkey ) {
c->local_id = pk->local_id;
c->trustletter = opt.fast_list_mode?
- 0 : query_trust_info( pk, NULL );
+ 0 : get_validity_info( pk, NULL );
}
printf("%s:", mainkey? "pub":"sub" );
if( c->trustletter )
@@ -684,18 +824,18 @@ list_node( CTX c, KBNODE node )
nbits_from_pk( pk ),
pk->pubkey_algo,
(ulong)keyid[0],(ulong)keyid[1],
- datestr_from_pk( pk ),
- pk->expiredate? strtimestamp(pk->expiredate):"" );
+ colon_datestr_from_pk( pk ),
+ colon_strtime (pk->expiredate) );
if( c->local_id )
printf("%lu", c->local_id );
putchar(':');
- if( c->local_id && !opt.fast_list_mode )
- putchar( get_ownertrust_info( c->local_id ) );
+ if( mainkey && !opt.fast_list_mode )
+ putchar( get_ownertrust_info (pk) );
putchar(':');
if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) {
putchar('\n'); any=1;
if( opt.fingerprint )
- print_fingerprint( pk, NULL );
+ print_fingerprint( pk, NULL, 0 );
printf("rtv:1:%u:\n",
node->next->pkt->pkt.ring_trust->trustval );
}
@@ -724,7 +864,8 @@ list_node( CTX c, KBNODE node )
else if( node->pkt->pkttype == PKT_USER_ID ) {
if( any ) {
if( opt.with_colons )
- printf("uid:::::::::");
+ printf("%s:::::::::",
+ node->pkt->pkt.user_id->attrib_data?"uat":"uid");
else
printf( "uid%*s", 28, "" );
}
@@ -733,7 +874,7 @@ list_node( CTX c, KBNODE node )
putchar(':');
putchar('\n');
if( opt.fingerprint && !any )
- print_fingerprint( pk, NULL );
+ print_fingerprint( pk, NULL, 0 );
if( node->next
&& node->next->pkt->pkttype == PKT_RING_TRUST ) {
printf("rtv:2:%u:\n",
@@ -757,7 +898,7 @@ list_node( CTX c, KBNODE node )
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
- print_fingerprint( pk, NULL );
+ print_fingerprint( pk, NULL, 0 );
}
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@@ -771,8 +912,8 @@ list_node( CTX c, KBNODE node )
nbits_from_sk( sk ),
sk->pubkey_algo,
(ulong)keyid[0],(ulong)keyid[1],
- datestr_from_sk( sk ),
- sk->expiredate? strtimestamp(sk->expiredate):""
+ colon_datestr_from_sk( sk ),
+ colon_strtime (sk->expiredate)
/* fixme: add LID */ );
}
else
@@ -798,7 +939,8 @@ list_node( CTX c, KBNODE node )
else if( node->pkt->pkttype == PKT_USER_ID ) {
if( any ) {
if( opt.with_colons )
- printf("uid:::::::::");
+ printf("%s:::::::::",
+ node->pkt->pkt.user_id->attrib_data?"uat":"uid");
else
printf( "uid%*s", 28, "" );
}
@@ -807,7 +949,7 @@ list_node( CTX c, KBNODE node )
putchar(':');
putchar('\n');
if( opt.fingerprint && !any )
- print_fingerprint( NULL, sk );
+ print_fingerprint( NULL, sk, 0 );
any=1;
}
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@@ -822,7 +964,7 @@ list_node( CTX c, KBNODE node )
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
- print_fingerprint( NULL, sk );
+ print_fingerprint( NULL, sk, 0 );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;
@@ -841,10 +983,11 @@ list_node( CTX c, KBNODE node )
fputs("sig", stdout);
if( opt.check_sigs ) {
fflush(stdout);
- switch( (rc2=do_check_sig( c, node, &is_selfsig )) ) {
+ switch( (rc2=do_check_sig( c, node, &is_selfsig, NULL )) ) {
case 0: sigrc = '!'; break;
- case GPGERR_BAD_SIGN: sigrc = '-'; break;
- case GPGERR_NO_PUBKEY: sigrc = '?'; break;
+ case G10ERR_BAD_SIGN: sigrc = '-'; break;
+ case G10ERR_NO_PUBKEY:
+ case G10ERR_UNU_PUBKEY: sigrc = '?'; break;
default: sigrc = '%'; break;
}
}
@@ -868,13 +1011,13 @@ list_node( CTX c, KBNODE node )
putchar(sigrc);
printf("::%d:%08lX%08lX:%s::::", sig->pubkey_algo,
(ulong)sig->keyid[0],
- (ulong)sig->keyid[1], datestr_from_sig(sig));
+ (ulong)sig->keyid[1], colon_datestr_from_sig(sig));
}
else
printf("%c %08lX %s ",
sigrc, (ulong)sig->keyid[1], datestr_from_sig(sig));
if( sigrc == '%' )
- printf("[%s] ", gpg_errstr(rc2) );
+ printf("[%s] ", g10_errstr(rc2) );
else if( sigrc == '?' )
;
else if( is_selfsig ) {
@@ -887,10 +1030,10 @@ list_node( CTX c, KBNODE node )
else if( !opt.fast_list_mode ) {
p = get_user_id( sig->keyid, &n );
print_string( stdout, p, n, opt.with_colons );
- gcry_free(p);
+ m_free(p);
}
if( opt.with_colons )
- printf(":%02x:", sig->sig_class );
+ printf(":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l');
putchar('\n');
}
else
@@ -903,11 +1046,11 @@ int
proc_packets( void *anchor, IOBUF a )
{
int rc;
- CTX c = gcry_xcalloc( 1, sizeof *c );
+ CTX c = m_alloc_clear( sizeof *c );
c->anchor = anchor;
rc = do_proc_packets( c, a );
- gcry_free( c );
+ m_free( c );
return rc;
}
@@ -917,7 +1060,7 @@ int
proc_signature_packets( void *anchor, IOBUF a,
STRLIST signedfiles, const char *sigfilename )
{
- CTX c = gcry_xcalloc( 1, sizeof *c );
+ CTX c = m_alloc_clear( sizeof *c );
int rc;
c->anchor = anchor;
@@ -925,20 +1068,20 @@ proc_signature_packets( void *anchor, IOBUF a,
c->signed_data = signedfiles;
c->sigfilename = sigfilename;
rc = do_proc_packets( c, a );
- gcry_free( c );
+ m_free( c );
return rc;
}
int
proc_encryption_packets( void *anchor, IOBUF a )
{
- CTX c = gcry_xcalloc( 1, sizeof *c );
+ CTX c = m_alloc_clear( sizeof *c );
int rc;
c->anchor = anchor;
c->encrypt_only = 1;
rc = do_proc_packets( c, a );
- gcry_free( c );
+ m_free( c );
return rc;
}
@@ -946,18 +1089,20 @@ proc_encryption_packets( void *anchor, IOBUF a )
int
do_proc_packets( CTX c, IOBUF a )
{
- PACKET *pkt = gcry_xmalloc( sizeof *pkt );
+ PACKET *pkt = m_alloc( sizeof *pkt );
int rc=0;
int any_data=0;
int newpkt;
c->iobuf = a;
init_packet(pkt);
- while( (rc=parse_packet(a, pkt, NULL)) != -1 ) {
+ while( (rc=parse_packet(a, pkt)) != -1 ) {
any_data = 1;
if( rc ) {
free_packet(pkt);
- if( rc == GPGERR_INVALID_PACKET )
+ /* stop processing hwne an invalid packet has been encountered
+ * but don't do so when we are doing a --list-packet. */
+ if( rc == G10ERR_INVALID_PACKET && opt.list_packets != 2 )
break;
continue;
}
@@ -981,12 +1126,14 @@ do_proc_packets( CTX c, IOBUF a )
case PKT_PUBKEY_ENC:
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC:
- rc = GPGERR_UNEXPECTED;
+ write_status_text( STATUS_UNEXPECTED, "0" );
+ rc = G10ERR_UNEXPECTED;
goto leave;
case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break;
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
+ case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
default: newpkt = 0; break;
}
}
@@ -995,7 +1142,8 @@ do_proc_packets( CTX c, IOBUF a )
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
case PKT_USER_ID:
- rc = GPGERR_UNEXPECTED;
+ write_status_text( STATUS_UNEXPECTED, "0" );
+ rc = G10ERR_UNEXPECTED;
goto leave;
case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break;
case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break;
@@ -1005,6 +1153,7 @@ do_proc_packets( CTX c, IOBUF a )
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
+ case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
default: newpkt = 0; break;
}
}
@@ -1029,23 +1178,38 @@ do_proc_packets( CTX c, IOBUF a )
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
+ case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break;
default: newpkt = 0; break;
}
}
- if( pkt->pkttype != PKT_SIGNATURE )
+ /* This is a very ugly construct and frankly, I don't remember why
+ * I used it. Adding the MDC check here is a hack.
+ * The right solution is to initiate another context for encrypted
+ * packet and not to reuse the current one ... It works right
+ * when there is a compression packet inbetween which adds just
+ * an extra layer.
+ * Hmmm: Rewrite this whole module here??
+ */
+ if( pkt->pkttype != PKT_SIGNATURE && pkt->pkttype != PKT_MDC )
c->have_data = pkt->pkttype == PKT_PLAINTEXT;
if( newpkt == -1 )
;
else if( newpkt ) {
- pkt = gcry_xmalloc( sizeof *pkt );
+ pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
}
else
free_packet(pkt);
+ if ( c->pipemode.stop_now ) {
+ /* we won't get an EOF in pipemode, so we have to
+ * break the loop here */
+ rc = -1;
+ break;
+ }
}
- if( rc == GPGERR_INVALID_PACKET )
+ if( rc == G10ERR_INVALID_PACKET )
write_status_text( STATUS_NODATA, "3" );
if( any_data )
rc = 0;
@@ -1055,9 +1219,9 @@ do_proc_packets( CTX c, IOBUF a )
leave:
release_list( c );
- gcry_free(c->dek);
+ m_free(c->dek);
free_packet( pkt );
- gcry_free( pkt );
+ m_free( pkt );
free_md_filter_context( &c->mfx );
return rc;
}
@@ -1068,76 +1232,190 @@ check_sig_and_print( CTX c, KBNODE node )
{
PKT_signature *sig = node->pkt->pkt.signature;
const char *astr, *tstr;
- int rc;
+ int rc, is_expkey=0;
if( opt.skip_verify ) {
log_info(_("signature verification suppressed\n"));
return 0;
}
+ /* It is not in all cases possible to check multiple signatures:
+ * PGP 2 (which is also allowed by OpenPGP), does use the packet
+ * sequence: sig+data, OpenPGP does use onepas+data=sig and GnuPG
+ * sometimes uses (because I did'nt read the specs right) data+sig.
+ * Because it is possible to create multiple signatures with
+ * different packet sequence (e.g. data+sig and sig+data) it might
+ * not be possible to get it right: let's say we have:
+ * data+sig, sig+data,sig+data and we have not yet encountered the last
+ * data, we could also see this a one data with 2 signatures and then
+ * data+sig.
+ * To protect against this we check that all signatures follow
+ * without any intermediate packets. Note, that we won't get this
+ * error when we use onepass packets or cleartext signatures because
+ * we reset the list every time
+ *
+ * FIXME: Now that we have these marker packets, we should create a
+ * real grammar and check against this.
+ */
+ {
+ KBNODE n;
+ int n_sig=0;
+
+ for (n=c->list; n; n=n->next ) {
+ if ( n->pkt->pkttype == PKT_SIGNATURE )
+ n_sig++;
+ }
+ if (n_sig > 1) { /* more than one signature - check sequence */
+ int tmp, onepass;
+
+ for (tmp=onepass=0,n=c->list; n; n=n->next ) {
+ if (n->pkt->pkttype == PKT_ONEPASS_SIG)
+ onepass++;
+ else if (n->pkt->pkttype == PKT_GPG_CONTROL
+ && n->pkt->pkt.gpg_control->control
+ == CTRLPKT_CLEARSIGN_START ) {
+ onepass++; /* handle the same way as a onepass */
+ }
+ else if ( (tmp && n->pkt->pkttype != PKT_SIGNATURE) ) {
+ log_error(_("can't handle these multiple signatures\n"));
+ return 0;
+ }
+ else if ( n->pkt->pkttype == PKT_SIGNATURE )
+ tmp = 1;
+ else if (!tmp && !onepass
+ && n->pkt->pkttype == PKT_GPG_CONTROL
+ && n->pkt->pkt.gpg_control->control
+ == CTRLPKT_PLAINTEXT_MARK ) {
+ /* plaintext before signatures but no one-pass packets*/
+ log_error(_("can't handle these multiple signatures\n"));
+ return 0;
+ }
+ }
+ }
+ }
+
+
+
tstr = asctimestamp(sig->timestamp);
- astr = gcry_pk_algo_name( sig->pubkey_algo );
+ astr = pubkey_algo_to_string( sig->pubkey_algo );
log_info(_("Signature made %.*s using %s key ID %08lX\n"),
(int)strlen(tstr), tstr, astr? astr: "?", (ulong)sig->keyid[1] );
- rc = do_check_sig(c, node, NULL );
- if( rc == GPGERR_NO_PUBKEY && opt.keyserver_name && opt.auto_key_retrieve) {
- if( !hkp_ask_import( sig->keyid ) )
- rc = do_check_sig(c, node, NULL );
+ rc = do_check_sig(c, node, NULL, &is_expkey );
+ if( rc == G10ERR_NO_PUBKEY && opt.keyserver_scheme && opt.keyserver_options.auto_key_retrieve) {
+ if( keyserver_import_keyid ( sig->keyid )==0 )
+ rc = do_check_sig(c, node, NULL, &is_expkey );
}
- if( !rc || rc == GPGERR_BAD_SIGN ) {
+ if( !rc || rc == G10ERR_BAD_SIGN ) {
KBNODE un, keyblock;
- char *us;
- int count=0;
+ int count=0, statno;
+ char keyid_str[50];
+
+ if(rc)
+ statno=STATUS_BADSIG;
+ else if(sig->flags.expired)
+ statno=STATUS_EXPSIG;
+ else if(is_expkey)
+ statno=STATUS_EXPKEYSIG;
+ else
+ statno=STATUS_GOODSIG;
keyblock = get_pubkeyblock( sig->keyid );
- us = get_long_user_id_string( sig->keyid );
- write_status_text( rc? STATUS_BADSIG : STATUS_GOODSIG, us );
- gcry_free(us);
+ sprintf (keyid_str, "%08lX%08lX [uncertain] ",
+ (ulong)sig->keyid[0], (ulong)sig->keyid[1]);
- /* fixme: list only user ids which are valid and add information
- * about the trustworthiness of each user id, sort them.
- * Integrate this with check_signatures_trust(). */
+ /* find and print the primary user ID */
for( un=keyblock; un; un = un->next ) {
if( un->pkt->pkttype != PKT_USER_ID )
continue;
- if( !count++ )
- log_info(rc? _("BAD signature from \"")
- : _("Good signature from \""));
- else
- log_info( _(" aka \""));
+ if ( !un->pkt->pkt.user_id->created )
+ continue;
+ if ( un->pkt->pkt.user_id->is_revoked )
+ continue;
+ if ( !un->pkt->pkt.user_id->is_primary )
+ continue;
+
+ keyid_str[17] = 0; /* cut off the "[uncertain]" part */
+ write_status_text_and_buffer (statno, keyid_str,
+ un->pkt->pkt.user_id->name,
+ un->pkt->pkt.user_id->len,
+ -1 );
+
+ log_info(rc? _("BAD signature from \"")
+ : sig->flags.expired ? _("Expired signature from \"")
+ : _("Good signature from \""));
print_utf8_string( log_stream(), un->pkt->pkt.user_id->name,
un->pkt->pkt.user_id->len );
fputs("\"\n", log_stream() );
- if( rc )
- break; /* print only one id in this case */
+ count++;
}
if( !count ) { /* just in case that we have no userid */
- log_info(rc? _("BAD signature from \"")
+ for( un=keyblock; un; un = un->next ) {
+ if( un->pkt->pkttype == PKT_USER_ID )
+ break;
+ }
+
+ if (opt.always_trust || !un)
+ keyid_str[17] = 0; /* cut off the "[uncertain]" part */
+
+ write_status_text_and_buffer (statno, keyid_str,
+ un? un->pkt->pkt.user_id->name:"[?]",
+ un? un->pkt->pkt.user_id->len:3,
+ -1 );
+
+ log_info(rc? _("BAD signature from \"")
+ : sig->flags.expired ? _("Expired signature from \"")
: _("Good signature from \""));
- fputs("[?]\"\n", log_stream() );
+ if (!opt.always_trust && un) {
+ fputs(_("[uncertain]"), log_stream() );
+ putc(' ', log_stream() );
+ }
+ print_utf8_string( log_stream(),
+ un? un->pkt->pkt.user_id->name:"[?]",
+ un? un->pkt->pkt.user_id->len:3 );
+ fputs("\"\n", log_stream() );
+ }
+
+ /* If we have a good signature and already printed
+ * the primary user ID, print all the other user IDs */
+ if ( count && !rc ) {
+ for( un=keyblock; un; un = un->next ) {
+ if( un->pkt->pkttype != PKT_USER_ID )
+ continue;
+ if ( un->pkt->pkt.user_id->is_revoked )
+ continue;
+ if ( un->pkt->pkt.user_id->is_primary )
+ continue;
+
+ log_info( _(" aka \""));
+ print_utf8_string( log_stream(), un->pkt->pkt.user_id->name,
+ un->pkt->pkt.user_id->len );
+ fputs("\"\n", log_stream() );
+ }
}
release_kbnode( keyblock );
+
if( !rc )
print_notation_data( sig );
if( !rc && is_status_enabled() ) {
/* print a status response with the fingerprint */
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( !get_pubkey( pk, sig->keyid ) ) {
byte array[MAX_FINGERPRINT_LEN], *p;
- char buf[MAX_FINGERPRINT_LEN*2+61];
+ char buf[MAX_FINGERPRINT_LEN*2+72];
size_t i, n;
fingerprint_from_pk( pk, array, &n );
p = array;
for(i=0; i < n ; i++, p++ )
sprintf(buf+2*i, "%02X", *p );
- sprintf(buf+strlen(buf), " %s %lu",
+ sprintf(buf+strlen(buf), " %s %lu %lu",
strtimestamp( sig->timestamp ),
- (ulong)sig->timestamp );
+ (ulong)sig->timestamp,
+ (ulong)sig->expiredate );
write_status_text( STATUS_VALIDSIG, buf );
}
free_public_key( pk );
@@ -1145,10 +1423,19 @@ check_sig_and_print( CTX c, KBNODE node )
if( !rc )
rc = check_signatures_trust( sig );
+
+ if(sig->flags.expired)
+ {
+ log_info("Signature expired %s\n",asctimestamp(sig->expiredate));
+ rc=G10ERR_GENERAL; /* need a better error here? */
+ }
+ else if(sig->expiredate)
+ log_info("Signature expires %s\n",asctimestamp(sig->expiredate));
+
if( rc )
- gpg_errors_seen = 1;
+ g10_errors_seen = 1;
if( opt.batch && rc )
- gpg_exit(1);
+ g10_exit(1);
}
else {
char buf[50];
@@ -1157,12 +1444,12 @@ check_sig_and_print( CTX c, KBNODE node )
sig->pubkey_algo, sig->digest_algo,
sig->sig_class, (ulong)sig->timestamp, rc );
write_status_text( STATUS_ERRSIG, buf );
- if( rc == GPGERR_NO_PUBKEY ) {
+ if( rc == G10ERR_NO_PUBKEY ) {
buf[16] = 0;
write_status_text( STATUS_NO_PUBKEY, buf );
}
- if( rc != GPGERR_NOT_PROCESSED )
- log_error(_("Can't check signature: %s\n"), gpg_errstr(rc) );
+ if( rc != G10ERR_NOT_PROCESSED )
+ log_error(_("Can't check signature: %s\n"), g10_errstr(rc) );
}
return rc;
}
@@ -1180,6 +1467,18 @@ proc_tree( CTX c, KBNODE node )
if( opt.list_packets || opt.list_only )
return;
+ /* we must skip our special plaintext marker packets here becuase
+ they may be the root packet. These packets are only used in
+ addionla checks and skipping them here doesn't matter */
+ while ( node
+ && node->pkt->pkttype == PKT_GPG_CONTROL
+ && node->pkt->pkt.gpg_control->control
+ == CTRLPKT_PLAINTEXT_MARK ) {
+ node = node->next;
+ }
+ if (!node)
+ return;
+
c->local_id = 0;
c->trustletter = ' ';
if( node->pkt->pkttype == PKT_PUBLIC_KEY
@@ -1196,12 +1495,11 @@ proc_tree( CTX c, KBNODE node )
if( !c->have_data ) {
free_md_filter_context( &c->mfx );
/* prepare to create all requested message digests */
- if ( !(c->mfx.md = gcry_md_open(0, 0)) )
- BUG();
+ c->mfx.md = md_open(0, 0);
/* fixme: why looking for the signature packet and not 1passpacket*/
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) {
- gcry_md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
+ md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
}
/* ask for file and hash it */
if( c->sigs_only ) {
@@ -1211,18 +1509,38 @@ proc_tree( CTX c, KBNODE node )
}
else {
rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2,
- iobuf_get_fname(c->iobuf),
+ iobuf_get_real_fname(c->iobuf),
n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 );
}
if( rc ) {
- log_error("can't hash datafile: %s\n", gpg_errstr(rc));
+ log_error("can't hash datafile: %s\n", g10_errstr(rc));
return;
}
}
+ else if ( c->signed_data ) {
+ log_error (_("not a detached signature\n") );
+ return;
+ }
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); )
check_sig_and_print( c, n1 );
}
+ else if( node->pkt->pkttype == PKT_GPG_CONTROL
+ && node->pkt->pkt.gpg_control->control
+ == CTRLPKT_CLEARSIGN_START ) {
+ /* clear text signed message */
+ if( !c->have_data ) {
+ log_error("cleartext signature without data\n" );
+ return;
+ }
+ else if ( c->signed_data ) {
+ log_error (_("not a detached signature\n") );
+ return;
+ }
+
+ for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); )
+ check_sig_and_print( c, n1 );
+ }
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;
@@ -1232,26 +1550,20 @@ proc_tree( CTX c, KBNODE node )
else if( !c->have_data ) {
/* detached signature */
free_md_filter_context( &c->mfx );
- c->mfx.md = gcry_md_open(sig->digest_algo, 0);
- if ( !c->mfx.md )
- BUG();
+ c->mfx.md = md_open(sig->digest_algo, 0);
if( !opt.pgp2_workarounds )
;
- else if( sig->digest_algo == GCRY_MD_MD5
+ else if( sig->digest_algo == DIGEST_ALGO_MD5
&& is_RSA( sig->pubkey_algo ) ) {
/* enable a workaround for a pgp2 bug */
- c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0 );
- if ( !c->mfx.md2 )
- BUG();
+ c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0 );
}
- else if( sig->digest_algo == GCRY_MD_SHA1
- && sig->pubkey_algo == GCRY_PK_DSA
+ else if( sig->digest_algo == DIGEST_ALGO_SHA1
+ && sig->pubkey_algo == PUBKEY_ALGO_DSA
&& sig->sig_class == 0x01 ) {
/* enable the workaround also for pgp5 when the detached
* signature has been created in textmode */
- c->mfx.md2 = gcry_md_open( sig->digest_algo, 0 );
- if ( !c->mfx.md2 )
- BUG();
+ c->mfx.md2 = md_open( sig->digest_algo, 0 );
}
#if 0 /* workaround disabled */
/* Here we have another hack to work around a pgp 2 bug
@@ -1263,6 +1575,11 @@ proc_tree( CTX c, KBNODE node )
*/
/* c->mfx.md2? 0 :(sig->sig_class == 0x01) */
#endif
+ if ( DBG_HASHING ) {
+ md_start_debug( c->mfx.md, "verify" );
+ if ( c->mfx.md2 )
+ md_start_debug( c->mfx.md2, "verify2" );
+ }
if( c->sigs_only ) {
rc = hash_datafiles( c->mfx.md, c->mfx.md2,
c->signed_data, c->sigfilename,
@@ -1270,23 +1587,33 @@ proc_tree( CTX c, KBNODE node )
}
else {
rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2,
- iobuf_get_fname(c->iobuf),
+ iobuf_get_real_fname(c->iobuf),
(sig->sig_class == 0x01) );
}
if( rc ) {
- log_error("can't hash datafile: %s\n", gpg_errstr(rc));
+ log_error("can't hash datafile: %s\n", g10_errstr(rc));
return;
}
}
- else
+ else if ( c->signed_data ) {
+ log_error (_("not a detached signature\n") );
+ return;
+ }
+ else if ( c->pipemode.op == 'B' )
+ ; /* this is a detached signature trough the pipemode handler */
+ else if (!opt.quiet)
log_info(_("old style (PGP 2.x) signature\n"));
- check_sig_and_print( c, node );
+ for( n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )) )
+ check_sig_and_print( c, n1 );
}
- else
+ else {
+ dump_kbnode (c->list);
log_error(_("invalid root packet detected in proc_tree()\n"));
-
+ dump_kbnode (node);
+ }
}
+
diff --git a/g10/mdfilter.c b/g10/mdfilter.c
index c41ad857e..d6ccacecf 100644
--- a/g10/mdfilter.c
+++ b/g10/mdfilter.c
@@ -1,5 +1,5 @@
/* mdfilter.c - filter data and calculate a message digest
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,9 +25,9 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "errors.h"
#include "iobuf.h"
+#include "memory.h"
#include "util.h"
#include "filter.h"
@@ -50,9 +50,9 @@ md_filter( void *opaque, int control,
i = iobuf_read( a, buf, size );
if( i == -1 ) i = 0;
if( i ) {
- gcry_md_write(mfx->md, buf, i );
+ md_write(mfx->md, buf, i );
if( mfx->md2 )
- gcry_md_write(mfx->md2, buf, i );
+ md_write(mfx->md2, buf, i );
}
else
rc = -1; /* eof */
@@ -67,8 +67,8 @@ md_filter( void *opaque, int control,
void
free_md_filter_context( md_filter_context_t *mfx )
{
- gcry_md_close(mfx->md);
- gcry_md_close(mfx->md2);
+ md_close(mfx->md);
+ md_close(mfx->md2);
mfx->md = NULL;
mfx->md2 = NULL;
mfx->maxbuf_size = 0;
diff --git a/g10/misc.c b/g10/misc.c
index 2348e46f0..c2330d959 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -1,5 +1,5 @@
/* misc.c - miscellaneous functions
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -22,28 +22,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <errno.h>
+#ifdef HAVE_STAT
+#include <sys/stat.h>
+#endif
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include <asm/sysinfo.h>
#include <asm/unistd.h>
#endif
#ifdef HAVE_SETRLIMIT
+ #include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
-#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
#include "main.h"
+#include "photoid.h"
#include "options.h"
#include "i18n.h"
-#define MAX_EXTERN_MPI_BITS 16384
+const char *g10m_revision_string(int);
+const char *g10c_revision_string(int);
+const char *g10u_revision_string(int);
+
+#ifdef __GNUC__
+volatile
+#endif
+ void
+pull_in_libs(void)
+{
+ g10m_revision_string(0);
+ g10c_revision_string(0);
+ g10u_revision_string(0);
+}
+
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
-#warning using trap_unaligned
static int
setsysinfo(unsigned long op, void *buffer, unsigned long size,
int *start, void *arg, unsigned long flag)
@@ -68,7 +84,6 @@ trap_unaligned(void)
#endif
-
int
disable_core_dumps()
{
@@ -91,166 +106,23 @@ disable_core_dumps()
-/****************
- * write an mpi to out.
- */
-int
-mpi_write( IOBUF out, MPI a )
-{
- char buffer[(MAX_EXTERN_MPI_BITS+7)/8];
- size_t nbytes;
- int rc;
-
- nbytes = (MAX_EXTERN_MPI_BITS+7)/8;
- rc = gcry_mpi_print( GCRYMPI_FMT_PGP, buffer, &nbytes, a );
- if( !rc )
- rc = iobuf_write( out, buffer, nbytes );
-
- return rc;
-}
-
-/****************
- * Writye a MPI to out, but in this case it is an opaque one,
- * s used vor v3 protected keys.
- */
-int
-mpi_write_opaque( IOBUF out, MPI a )
-{
- size_t nbytes, nbits;
- int rc;
- char *p;
-
- assert( gcry_mpi_get_flag( a, GCRYMPI_FLAG_OPAQUE ) );
- p = gcry_mpi_get_opaque( a, &nbits );
- nbytes = (nbits+7) / 8;
- iobuf_put( out, nbits >> 8 );
- iobuf_put( out, nbits );
- rc = iobuf_write( out, p, nbytes );
- return rc;
-}
-
-
-/****************
- * Read an external representation of an mpi and return the MPI
- * The external format is a 16 bit unsigned value stored in network byte order,
- * giving the number of bits for the following integer. The integer is stored
- * with MSB first (left padded with zeroes to align on a byte boundary).
- */
-MPI
-mpi_read(IOBUF inp, unsigned int *ret_nread, int secure)
+u16
+checksum_u16( unsigned n )
{
- int c, c1, c2, i;
- unsigned int nbits, nbytes, nread=0;
- MPI a = NULL;
- byte *buf = NULL;
- byte *p;
-
- if( (c = c1 = iobuf_get(inp)) == -1 )
- goto leave;
- nbits = c << 8;
- if( (c = c2 = iobuf_get(inp)) == -1 )
- goto leave;
- nbits |= c;
- if( nbits > MAX_EXTERN_MPI_BITS ) {
- log_error("mpi too large (%u bits)\n", nbits);
- goto leave;
- }
- nread = 2;
- nbytes = (nbits+7) / 8;
- buf = secure? gcry_xmalloc_secure( nbytes+2 ) : gcry_xmalloc( nbytes+2 );
- p = buf;
- p[0] = c1;
- p[1] = c2;
- for( i=0 ; i < nbytes; i++ ) {
- p[i+2] = iobuf_get(inp) & 0xff;
- nread++;
- }
- nread += nbytes;
- if( gcry_mpi_scan( &a, GCRYMPI_FMT_PGP, buf, &nread ) )
- a = NULL;
-
- leave:
- gcry_free(buf);
- if( nread > *ret_nread )
- log_bug("mpi larger than packet");
- else
- *ret_nread = nread;
- return a;
-}
+ u16 a;
-/****************
- * Same as mpi_read but the value is stored as an opaque MPI.
- * This function is used to read encrypted MPI of v3 packets.
- */
-GCRY_MPI
-mpi_read_opaque(IOBUF inp, unsigned *ret_nread )
-{
- int c, c1, c2, i;
- unsigned nbits, nbytes, nread=0;
- GCRY_MPI a = NULL;
- byte *buf = NULL;
- byte *p;
-
- if( (c = c1 = iobuf_get(inp)) == -1 )
- goto leave;
- nbits = c << 8;
- if( (c = c2 = iobuf_get(inp)) == -1 )
- goto leave;
- nbits |= c;
- if( nbits > MAX_EXTERN_MPI_BITS ) {
- log_error("mpi too large (%u bits)\n", nbits);
- goto leave;
- }
- nread = 2;
- nbytes = (nbits+7) / 8;
- buf = gcry_xmalloc( nbytes );
- p = buf;
- for( i=0 ; i < nbytes; i++ ) {
- p[i] = iobuf_get(inp) & 0xff;
+ a = (n >> 8) & 0xff;
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
+ a |= n & 0xff;
+ log_debug("csum_u16 emulated for n=%u\n", n);
}
- nread += nbytes;
- a = gcry_mpi_set_opaque(NULL, buf, nbits );
- buf = NULL;
-
- leave:
- gcry_free(buf);
- if( nread > *ret_nread )
- log_bug("mpi larger than packet");
else
- *ret_nread = nread;
+ a += n & 0xff;
return a;
}
-
-int
-mpi_print( FILE *fp, MPI a, int mode )
-{
- int n=0;
-
- if( !a )
- return fprintf(fp, "[MPI_NULL]");
- if( !mode ) {
- unsigned int n1;
- n1 = gcry_mpi_get_nbits(a);
- n += fprintf(fp, "[%u bits]", n1);
- }
- else {
- int rc;
- char *buffer;
-
- rc = gcry_mpi_aprint( GCRYMPI_FMT_HEX, (void **)&buffer, NULL, a );
- assert( !rc );
- fputs( buffer, fp );
- n += strlen(buffer);
- gcry_free( buffer );
- }
- return n;
-}
-
-
-
-u16
-checksum_u16( unsigned n )
+static u16
+checksum_u16_nobug( unsigned n )
{
u16 a;
@@ -272,22 +144,47 @@ checksum( byte *p, unsigned n )
u16
checksum_mpi( MPI a )
{
- int rc;
u16 csum;
byte *buffer;
- size_t nbytes;
-
- rc = gcry_mpi_print( GCRYMPI_FMT_PGP, NULL, &nbytes, a );
- assert( !rc );
- /* fixme: for numbers not in the suecre memory we
- * should use a stack based buffer and only allocate
- * a larger one when the mpi_print return an error
+ unsigned nbytes;
+ unsigned nbits;
+
+ buffer = mpi_get_buffer( a, &nbytes, NULL );
+ /* some versions of gpg encode wrong values for the length of an mpi
+ * so that mpi_get_nbits() which counts the mpi yields another (shorter)
+ * value than the one store with the mpi. mpi_get_nbit_info() returns
+ * this stored value if it is still available.
*/
- buffer = gcry_is_secure(a)? gcry_xmalloc_secure(nbytes) : gcry_xmalloc(nbytes);
- rc = gcry_mpi_print( GCRYMPI_FMT_PGP, buffer, &nbytes, a );
- assert( !rc );
- csum = checksum( buffer, nbytes );
- gcry_free( buffer );
+
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM )
+ nbits = 0;
+ else
+ nbits = mpi_get_nbit_info(a);
+ if( !nbits )
+ nbits = mpi_get_nbits(a);
+ csum = checksum_u16( nbits );
+ csum += checksum( buffer, nbytes );
+ m_free( buffer );
+ return csum;
+}
+
+/****************
+ * This is the correct function
+ */
+u16
+checksum_mpi_counted_nbits( MPI a )
+{
+ u16 csum;
+ byte *buffer;
+ unsigned nbytes;
+ unsigned nbits;
+
+ buffer = mpi_get_buffer( a, &nbytes, NULL );
+ nbits = mpi_get_nbits(a);
+ mpi_set_nbit_info(a,nbits);
+ csum = checksum_u16_nobug( nbits );
+ csum += checksum( buffer, nbytes );
+ m_free( buffer );
return csum;
}
@@ -327,11 +224,13 @@ print_cipher_algo_note( int algo )
{
if( algo >= 100 && algo <= 110 )
no_exp_algo();
- else if( algo == GCRY_CIPHER_3DES
- || algo == GCRY_CIPHER_CAST5
- || algo == GCRY_CIPHER_BLOWFISH
- || algo == GCRY_CIPHER_RIJNDAEL
- || algo == GCRY_CIPHER_TWOFISH
+ else if( algo == CIPHER_ALGO_3DES
+ || algo == CIPHER_ALGO_CAST5
+ || algo == CIPHER_ALGO_BLOWFISH
+ || algo == CIPHER_ALGO_TWOFISH
+ || algo == CIPHER_ALGO_RIJNDAEL
+ || algo == CIPHER_ALGO_RIJNDAEL192
+ || algo == CIPHER_ALGO_RIJNDAEL256
)
;
else {
@@ -339,7 +238,7 @@ print_cipher_algo_note( int algo )
if( !did_note ) {
did_note = 1;
- log_info(_("this cipher algorithm is depreciated; "
+ log_info(_("this cipher algorithm is deprecated; "
"please use a more standard one!\n"));
}
}
@@ -353,6 +252,32 @@ print_digest_algo_note( int algo )
}
+/* Return a string which is used as a kind of process ID */
+const byte *
+get_session_marker( size_t *rlen )
+{
+ static byte marker[SIZEOF_UNSIGNED_LONG*2];
+ static int initialized;
+
+ if ( !initialized ) {
+ volatile ulong aa, bb; /* we really want the uninitialized value */
+ ulong a, b;
+
+ initialized = 1;
+ /* also this marker is guessable it is not easy to use this
+ * for a faked control packet because an attacker does not
+ * have enough control about the time the verification does
+ * take place. Of course, we can add just more random but
+ * than we need the random generator even for verification
+ * tasks - which does not make sense. */
+ a = aa ^ (ulong)getpid();
+ b = bb ^ (ulong)time(NULL);
+ memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
+ memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
+ }
+ *rlen = sizeof(marker);
+ return marker;
+}
/****************
* Wrapper around the libgcrypt function with addional checks on
@@ -362,122 +287,405 @@ int
openpgp_cipher_test_algo( int algo )
{
if( algo < 0 || algo > 110 )
- return GCRYERR_INV_CIPHER_ALGO;
- return gcry_cipher_test_algo(algo);
+ return G10ERR_CIPHER_ALGO;
+ return check_cipher_algo(algo);
}
int
openpgp_pk_test_algo( int algo, unsigned int usage_flags )
{
- size_t n = usage_flags;
-
if( algo < 0 || algo > 110 )
- return GCRYERR_INV_PK_ALGO;
- return gcry_pk_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, &n );
+ return G10ERR_PUBKEY_ALGO;
+ return check_pubkey_algo2( algo, usage_flags );
}
int
openpgp_pk_algo_usage ( int algo )
{
- int usage = 0;
+ int use = 0;
- /* some are hardwired */
+ /* they are hardwired in gpg 1.0 */
switch ( algo ) {
- case GCRY_PK_RSA:
- usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+ case PUBKEY_ALGO_RSA:
+ use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
break;
- case GCRY_PK_RSA_E:
- usage = GCRY_PK_USAGE_ENCR;
+ case PUBKEY_ALGO_RSA_E:
+ use = PUBKEY_USAGE_ENC;
break;
- case GCRY_PK_RSA_S:
- usage = GCRY_PK_USAGE_SIGN;
+ case PUBKEY_ALGO_RSA_S:
+ use = PUBKEY_USAGE_SIG;
break;
- case GCRY_PK_ELG_E:
- usage = GCRY_PK_USAGE_ENCR;
+ case PUBKEY_ALGO_ELGAMAL_E:
+ use = PUBKEY_USAGE_ENC;
break;
- case GCRY_PK_DSA:
- usage = GCRY_PK_USAGE_SIGN;
+ case PUBKEY_ALGO_DSA:
+ use = PUBKEY_USAGE_SIG;
break;
- case GCRY_PK_ELG:
- usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+ case PUBKEY_ALGO_ELGAMAL:
+ use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
break;
default:
- usage = gcry_pk_algo_info ( algo, GCRYCTL_GET_ALGO_USAGE,
- NULL, NULL);
+ break;
}
- return usage;
-
+ return use;
}
-
-
int
openpgp_md_test_algo( int algo )
{
if( algo < 0 || algo > 110 )
- return GCRYERR_INV_MD_ALGO;
- return gcry_md_test_algo(algo);
+ return G10ERR_DIGEST_ALGO;
+ return check_digest_algo(algo);
}
-
int
-pubkey_get_npkey( int algo )
+check_permissions(const char *path,int extension,int checkonly)
{
- int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, 0 );
- return n > 0? n : 0;
+#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
+ char *tmppath;
+ struct stat statbuf;
+ int ret=1;
+ int isdir=0;
+
+ if(opt.no_perm_warn)
+ return 0;
+
+ if(extension && path[0]!=DIRSEP_C)
+ {
+ if(strchr(path,DIRSEP_C))
+ tmppath=make_filename(path,NULL);
+ else
+ tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
+ }
+ else
+ tmppath=m_strdup(path);
+
+ /* It's okay if the file doesn't exist */
+ if(stat(tmppath,&statbuf)!=0)
+ {
+ ret=0;
+ goto end;
+ }
+
+ isdir=S_ISDIR(statbuf.st_mode);
+
+ /* We may have to revisit this if we start piping keyrings to gpg
+ over a named pipe or keyserver character device :) */
+ if(!isdir && !S_ISREG(statbuf.st_mode))
+ {
+ ret=0;
+ goto end;
+ }
+
+ /* Per-user files must be owned by the user. Extensions must be
+ owned by the user or root. */
+ if((!extension && statbuf.st_uid != getuid()) ||
+ (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
+ {
+ if(!checkonly)
+ log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
+ isdir?"directory":extension?"extension":"file",path);
+ goto end;
+ }
+
+ /* This works for both directories and files - basically, we don't
+ care what the owner permissions are, so long as the group and
+ other permissions are 0 for per-user files, and non-writable for
+ extensions. */
+ if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
+ (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
+ {
+ char *dir;
+
+ /* However, if the directory the directory/file is in is owned
+ by the user and is 700, then this is not a problem.
+ Theoretically, we could walk this test up to the root
+ directory /, but for the sake of sanity, I'm stopping at one
+ level down. */
+
+ dir=make_dirname(tmppath);
+ if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
+ S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
+ {
+ m_free(dir);
+ ret=0;
+ goto end;
+ }
+
+ m_free(dir);
+
+ if(!checkonly)
+ log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
+ isdir?"directory":extension?"extension":"file",path);
+ goto end;
+ }
+
+ ret=0;
+
+ end:
+ m_free(tmppath);
+
+ return ret;
+
+#endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
+
+ return 0;
}
-int
-pubkey_get_nskey( int algo )
+/* Special warning for the IDEA cipher */
+void
+idea_cipher_warn(int show)
{
- int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, 0 );
- return n > 0? n : 0;
+ static int warned=0;
+
+ if(!warned || show)
+ {
+ log_info(_("the IDEA cipher plugin is not present\n"));
+ log_info(_("please see http://www.gnupg.org/why-not-idea.html "
+ "for more information\n"));
+ warned=1;
+ }
}
-int
-pubkey_get_nsig( int algo )
+/* Expand %-strings. Returns a string which must be m_freed. Returns
+ NULL if the string cannot be expanded (too large). */
+char *
+pct_expando(const char *string,struct expando_args *args)
{
- int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, 0 );
- return n > 0? n : 0;
+ const char *ch=string;
+ int idx=0,maxlen=0,done=0;
+ u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
+ char *ret=NULL;
+
+ if(args->pk)
+ keyid_from_pk(args->pk,pk_keyid);
+
+ if(args->sk)
+ keyid_from_sk(args->sk,sk_keyid);
+
+ if(!args->pk && args->sk)
+ keyid_from_sk(args->sk,pk_keyid);
+
+ while(*ch!='\0')
+ {
+ char *str=NULL;
+
+ if(!done)
+ {
+ /* 8192 is way bigger than we'll need here */
+ if(maxlen>=8192)
+ goto fail;
+
+ maxlen+=1024;
+ ret=m_realloc(ret,maxlen);
+ }
+
+ done=0;
+
+ if(*ch=='%')
+ {
+ switch(*(ch+1))
+ {
+ case 's': /* short key id */
+ if(idx+8<maxlen)
+ {
+ sprintf(&ret[idx],"%08lX",(ulong)sk_keyid[1]);
+ idx+=8;
+ done=1;
+ }
+ break;
+
+ case 'S': /* long key id */
+ if(idx+16<maxlen)
+ {
+ sprintf(&ret[idx],"%08lX%08lX",
+ (ulong)sk_keyid[0],(ulong)sk_keyid[1]);
+ idx+=16;
+ done=1;
+ }
+ break;
+
+ case 'k': /* short key id */
+ if(idx+8<maxlen)
+ {
+ sprintf(&ret[idx],"%08lX",(ulong)pk_keyid[1]);
+ idx+=8;
+ done=1;
+ }
+ break;
+
+ case 'K': /* long key id */
+ if(idx+16<maxlen)
+ {
+ sprintf(&ret[idx],"%08lX%08lX",
+ (ulong)pk_keyid[0],(ulong)pk_keyid[1]);
+ idx+=16;
+ done=1;
+ }
+ break;
+
+ case 'f': /* fingerprint */
+ {
+ byte array[MAX_FINGERPRINT_LEN];
+ size_t len;
+ int i;
+
+ if(args->pk)
+ fingerprint_from_pk(args->pk,array,&len);
+ else
+ memset(array,0,MAX_FINGERPRINT_LEN);
+
+ if(idx+(len*2)<maxlen)
+ {
+ for(i=0;i<len;i++)
+ {
+ sprintf(&ret[idx],"%02X",array[i]);
+ idx+=2;
+ }
+ done=1;
+ }
+ }
+ break;
+
+ case 't': /* e.g. "jpg" */
+ str=image_type_to_string(args->imagetype,0);
+ /* fall through */
+
+ case 'T': /* e.g. "image/jpeg" */
+ if(str==NULL)
+ str=image_type_to_string(args->imagetype,2);
+
+ if(idx+strlen(str)<maxlen)
+ {
+ strcpy(&ret[idx],str);
+ idx+=strlen(str);
+ done=1;
+ }
+ break;
+
+ case '%':
+ if(idx+1<maxlen)
+ {
+ ret[idx++]='%';
+ ret[idx]='\0';
+ done=1;
+ }
+ break;
+
+ /* Any unknown %-keys (like %i, %o, %I, and %O) are
+ passed through for later expansion. Note this also
+ handles the case where the last character in the
+ string is a '%' - the terminating \0 will end up here
+ and properly terminate the string. */
+ default:
+ if(idx+2<maxlen)
+ {
+ ret[idx++]='%';
+ ret[idx++]=*(ch+1);
+ ret[idx]='\0';
+ done=1;
+ }
+ break;
+ }
+
+ if(done)
+ ch++;
+ }
+ else
+ {
+ if(idx+1<maxlen)
+ {
+ ret[idx++]=*ch;
+ ret[idx]='\0';
+ done=1;
+ }
+ }
+
+ if(done)
+ ch++;
+ }
+
+ return ret;
+
+ fail:
+ m_free(ret);
+ return NULL;
}
int
-pubkey_get_nenc( int algo )
+hextobyte( const char *s )
{
- int n = gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, 0 );
- return n > 0? n : 0;
+ int c;
+
+ if( *s >= '0' && *s <= '9' )
+ c = 16 * (*s - '0');
+ else if( *s >= 'A' && *s <= 'F' )
+ c = 16 * (10 + *s - 'A');
+ else if( *s >= 'a' && *s <= 'f' )
+ c = 16 * (10 + *s - 'a');
+ else
+ return -1;
+ s++;
+ if( *s >= '0' && *s <= '9' )
+ c += *s - '0';
+ else if( *s >= 'A' && *s <= 'F' )
+ c += 10 + *s - 'A';
+ else if( *s >= 'a' && *s <= 'f' )
+ c += 10 + *s - 'a';
+ else
+ return -1;
+ return c;
}
-
-unsigned int
-pubkey_nbits( int algo, MPI *key )
+void
+deprecated_warning(const char *configname,unsigned int configlineno,
+ const char *option,const char *repl1,const char *repl2)
{
- int rc, nbits;
- GCRY_SEXP sexp;
+ if(configname)
+ {
+ if(strncmp("--",option,2)==0)
+ option+=2;
- if( algo == GCRY_PK_DSA ) {
- rc = gcry_sexp_build ( &sexp, NULL,
- "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
- key[0], key[1], key[2], key[3] );
- }
- else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &sexp, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- key[0], key[1], key[2] );
- }
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &sexp, NULL,
- "(public-key(rsa(n%m)(e%m)))",
- key[0], key[1] );
+ if(strncmp("--",repl1,2)==0)
+ repl1+=2;
+
+ log_info(_("%s:%d: deprecated option \"%s\"\n"),
+ configname,configlineno,option);
}
- else
- return 0;
+ else
+ log_info(_("WARNING: \"%s\" is a deprecated option\n"),option);
+
+ log_info(_("please use \"%s%s\" instead\n"),repl1,repl2);
+}
+
+const char *
+compress_algo_to_string(int algo)
+{
+ const char *s="?";
- if ( rc )
- BUG ();
+ switch(algo)
+ {
+ case 0:
+ s="Uncompressed";
+ break;
- nbits = gcry_pk_get_nbits( sexp );
- gcry_sexp_release( sexp );
- return nbits;
+ case 1:
+ s="ZIP";
+ break;
+
+ case 2:
+ s="ZLIB";
+ break;
+ }
+
+ return s;
}
+int
+check_compress_algo(int algo)
+{
+ if(algo>=0 && algo<=2)
+ return 0;
+
+ return G10ERR_COMPR_ALGO;
+}
diff --git a/g10/mkdtemp.c b/g10/mkdtemp.c
new file mode 100644
index 000000000..0323486a3
--- /dev/null
+++ b/g10/mkdtemp.c
@@ -0,0 +1,98 @@
+/* mkdtemp.c - libc replacement function
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* This is a replacement function for mkdtemp in case the platform
+ we're building on (like mine!) doesn't have it. */
+
+#include <config.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "types.h"
+#include "cipher.h"
+
+#ifdef MKDIR_TAKES_ONE_ARG
+# undef mkdir
+# define mkdir(a,b) mkdir(a)
+#endif
+
+char *mkdtemp(char *template)
+{
+ int attempts,idx,count=0;
+ byte *ch;
+
+ idx=strlen(template);
+
+ /* Walk backwards to count all the Xes */
+ while(idx>0 && template[idx-1]=='X')
+ {
+ count++;
+ idx--;
+ }
+
+ if(count==0)
+ {
+ errno=EINVAL;
+ return NULL;
+ }
+
+ ch=&template[idx];
+
+ /* Try 4 times to make the temp directory */
+ for(attempts=0;attempts<4;attempts++)
+ {
+ int remaining=count;
+ char *marker=ch;
+ byte *randombits;
+
+ idx=0;
+
+ /* Using really random bits is probably overkill here. The
+ worst thing that can happen with a directory name collision
+ is that the function will return an error. */
+
+ randombits=get_random_bits(4*remaining,0,0);
+
+ while(remaining>1)
+ {
+ sprintf(marker,"%02X",randombits[idx++]);
+ marker+=2;
+ remaining-=2;
+ }
+
+ /* Any leftover Xes? get_random_bits rounds up to full bytes,
+ so this is safe. */
+ if(remaining>0)
+ sprintf(marker,"%X",randombits[idx]&0xF);
+
+ m_free(randombits);
+
+ if(mkdir(template,0700)==0)
+ break;
+ }
+
+ if(attempts==4)
+ return NULL; /* keeps the errno from mkdir, whatever it is */
+
+ return template;
+}
diff --git a/g10/openfile.c b/g10/openfile.c
index 340cfd6fa..1bc4cf04c 100644
--- a/g10/openfile.c
+++ b/g10/openfile.c
@@ -1,5 +1,5 @@
/* openfile.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,7 +29,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "util.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "ttyio.h"
#include "options.h"
#include "main.h"
@@ -39,11 +39,11 @@
#ifdef USE_ONLY_8DOT3
#define SKELEXT ".skl"
#else
- #define SKELEXT ".skel"
+ #define SKELEXT EXTSEP_S "skel"
#endif
-#ifdef HAVE_DRIVE_LETTERS
- #define CMP_FILENAME(a,b) stricmp( (a), (b) )
+#if defined (HAVE_DRIVE_LETTERS) || defined (__riscos__)
+ #define CMP_FILENAME(a,b) ascii_strcasecmp( (a), (b) )
#else
#define CMP_FILENAME(a,b) strcmp( (a), (b) )
#endif
@@ -99,24 +99,23 @@ make_outfile_name( const char *iname )
size_t n;
if( (!iname || (*iname=='-' && !iname[1]) ))
- return gcry_xstrdup("-");
+ return m_strdup("-");
n = strlen(iname);
- if( n > 4 && ( !CMP_FILENAME(iname+n-4,".gpg")
- || !CMP_FILENAME(iname+n-4,".pgp")
- || !CMP_FILENAME(iname+n-4,".sig")
- || !CMP_FILENAME(iname+n-4,".asc") ) ) {
- char *buf = gcry_xstrdup( iname );
+ if( n > 4 && ( !CMP_FILENAME(iname+n-4, EXTSEP_S "gpg")
+ || !CMP_FILENAME(iname+n-4, EXTSEP_S "pgp")
+ || !CMP_FILENAME(iname+n-4, EXTSEP_S "sig")
+ || !CMP_FILENAME(iname+n-4, EXTSEP_S "asc") ) ) {
+ char *buf = m_strdup( iname );
buf[n-4] = 0;
return buf;
}
- else if( n > 5 && !CMP_FILENAME(iname+n-5,".sign") ) {
- char *buf = gcry_xstrdup( iname );
+ else if( n > 5 && !CMP_FILENAME(iname+n-5, EXTSEP_S "sign") ) {
+ char *buf = m_strdup( iname );
buf[n-5] = 0;
return buf;
}
-
log_info(_("%s: unknown suffix\n"), iname );
return NULL;
}
@@ -143,19 +142,21 @@ ask_outfile_name( const char *name, size_t namelen )
n = strlen(s) + namelen + 10;
defname = name && namelen? make_printable_string( name, namelen, 0): NULL;
- prompt = gcry_xmalloc(n);
+ prompt = m_alloc(n);
if( defname )
sprintf(prompt, "%s [%s]: ", s, defname );
else
sprintf(prompt, "%s: ", s );
fname = cpr_get("openfile.askoutname", prompt );
cpr_kill_prompt();
- gcry_free(prompt);
+ m_free(prompt);
if( !*fname ) {
- gcry_free( fname ); fname = NULL;
+ m_free( fname ); fname = NULL;
fname = defname; defname = NULL;
}
- gcry_free(defname);
+ m_free(defname);
+ if (fname)
+ trim_spaces (fname);
return fname;
}
@@ -177,7 +178,7 @@ open_outfile( const char *iname, int mode, IOBUF *a )
if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) {
if( !(*a = iobuf_create(NULL)) ) {
log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) );
- rc = GPGERR_CREATE_FILE;
+ rc = G10ERR_CREATE_FILE;
}
else if( opt.verbose )
log_info(_("writing to stdout\n"));
@@ -203,7 +204,7 @@ open_outfile( const char *iname, int mode, IOBUF *a )
const char *newsfx = mode==1 ? ".asc" :
mode==2 ? ".sig" : ".gpg";
- buf = gcry_xmalloc(strlen(iname)+4+1);
+ buf = m_alloc(strlen(iname)+4+1);
strcpy(buf,iname);
dot = strchr(buf, '.' );
if( dot && dot > buf && dot[1] && strlen(dot) <= 4
@@ -215,24 +216,34 @@ open_outfile( const char *iname, int mode, IOBUF *a )
else
strcat( buf, newsfx );
#else
- buf = gcry_xmalloc(strlen(iname)+4+1);
- strcpy(stpcpy(buf,iname), mode==1 ? ".asc" :
- mode==2 ? ".sig" : ".gpg");
+ buf = m_alloc(strlen(iname)+4+1);
+ strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" :
+ mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg");
#endif
name = buf;
}
- if( overwrite_filep( name ) ) {
+ rc = 0;
+ while( !overwrite_filep (name) ) {
+ char *tmp = ask_outfile_name (NULL, 0);
+ if ( !tmp || !*tmp ) {
+ m_free (tmp);
+ rc = G10ERR_FILE_EXISTS;
+ break;
+ }
+ m_free (buf);
+ name = buf = tmp;
+ }
+
+ if( !rc ) {
if( !(*a = iobuf_create( name )) ) {
log_error(_("%s: can't create: %s\n"), name, strerror(errno) );
- rc = GPGERR_CREATE_FILE;
+ rc = G10ERR_CREATE_FILE;
}
else if( opt.verbose )
log_info(_("writing to `%s'\n"), name );
}
- else
- rc = GPGERR_FILE_EXISTS;
- gcry_free(buf);
+ m_free(buf);
}
return rc;
}
@@ -251,16 +262,16 @@ open_sigfile( const char *iname )
if( iname && !(*iname == '-' && !iname[1]) ) {
len = strlen(iname);
- if( len > 4 && ( !strcmp(iname + len - 4, ".sig")
- || ( len > 5 && !strcmp(iname + len - 5, ".sign") )
- || !strcmp(iname + len - 4, ".asc")) ) {
+ if( len > 4 && ( !strcmp(iname + len - 4, EXTSEP_S "sig")
+ || ( len > 5 && !strcmp(iname + len - 5, EXTSEP_S "sign") )
+ || !strcmp(iname + len - 4, EXTSEP_S "asc")) ) {
char *buf;
- buf = gcry_xstrdup(iname);
- buf[len-4] = 0 ;
+ buf = m_strdup(iname);
+ buf[len-(buf[len-1]=='n'?5:4)] = 0 ;
a = iobuf_open( buf );
- if( opt.verbose )
+ if( a && opt.verbose )
log_info(_("assuming signed data in `%s'\n"), buf );
- gcry_free(buf);
+ m_free(buf);
}
}
return a;
@@ -282,20 +293,20 @@ copy_options_file( const char *destdir )
if( opt.dry_run )
return;
- fname = gcry_xmalloc( strlen(datadir) + strlen(destdir) + 15 );
- strcpy(stpcpy(fname, datadir), "/options" SKELEXT );
+ fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 );
+ strcpy(stpcpy(fname, datadir), DIRSEP_S "options" SKELEXT );
src = fopen( fname, "r" );
if( !src ) {
log_error(_("%s: can't open: %s\n"), fname, strerror(errno) );
- gcry_free(fname);
+ m_free(fname);
return;
}
- strcpy(stpcpy(fname, destdir), "/options" );
+ strcpy(stpcpy(fname, destdir), DIRSEP_S "options" );
dst = fopen( fname, "w" );
if( !dst ) {
log_error(_("%s: can't create: %s\n"), fname, strerror(errno) );
fclose( src );
- gcry_free(fname);
+ m_free(fname);
return;
}
@@ -310,7 +321,7 @@ copy_options_file( const char *destdir )
fclose( dst );
fclose( src );
log_info(_("%s: new options file created\n"), fname );
- gcry_free(fname);
+ m_free(fname);
}
@@ -325,12 +336,12 @@ try_make_homedir( const char *fname )
* To cope with HOME, we do compare only the suffix if we see that
* the default homedir does start with a tilde.
*/
- if( opt.dry_run )
+ if( opt.dry_run || opt.no_homedir_creation )
return;
if ( ( *defhome == '~'
&& ( strlen(fname) >= strlen (defhome+1)
- && !strcmp(fname+strlen(defhome+1)-strlen(defhome+1),
+ && !strcmp(fname+strlen(fname)-strlen(defhome+1),
defhome+1 ) ))
|| ( *defhome != '~'
&& !compare_filenames( fname, defhome ) )
@@ -343,9 +354,6 @@ try_make_homedir( const char *fname )
copy_options_file( fname );
log_info(_("you have to start GnuPG again, "
"so it can read the new options file\n") );
- gpg_exit(1);
+ g10_exit(1);
}
}
-
-
-
diff --git a/g10/options.h b/g10/options.h
index b7ef09fe7..74cebe575 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -1,5 +1,5 @@
/* options.h
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -17,52 +17,82 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_OPTIONS_H
-#define GPG_OPTIONS_H
+#ifndef G10_OPTIONS_H
+#define G10_OPTIONS_H
#include <types.h>
+#include "main.h"
+#include "packet.h"
#undef ENABLE_COMMENT_PACKETS /* don't create comment packets */
+#ifndef EXTERN_UNLESS_MAIN_MODULE
+/* Norcraft can't cope with common symbols */
+ #if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
+ #define EXTERN_UNLESS_MAIN_MODULE extern
+ #else
+ #define EXTERN_UNLESS_MAIN_MODULE
+ #endif
+#endif
+EXTERN_UNLESS_MAIN_MODULE
struct {
int verbose;
int quiet;
- unsigned int debug;
+ unsigned debug;
int armor;
int compress;
char *outfile;
int dry_run;
int list_only;
int textmode;
+ int expert;
+ int ask_sig_expire;
+ int ask_cert_expire;
int batch; /* run in batch mode */
int answer_yes; /* answer yes on most questions */
int answer_no; /* answer no on most questions */
int check_sigs; /* check key signatures */
int with_colons;
int with_key_data;
+ int with_fingerprint; /* opt --with-fingerprint active */
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
int no_armor;
- int list_packets; /* list-packets mode */
+ int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
int def_cipher_algo;
int force_v3_sigs;
+ int force_v4_certs;
int force_mdc;
+ int disable_mdc;
int def_digest_algo;
+ int cert_digest_algo;
int def_compress_algo;
const char *def_secret_key;
char *def_recipient;
int def_recipient_self;
- int no_comment;
+ int def_cert_check_level;
+ int sk_comments;
int no_version;
int marginals_needed;
int completes_needed;
int max_cert_depth;
const char *homedir;
+
+ char *display; /* 5 options to be passed to the gpg-agent */
+ char *ttyname;
+ char *ttytype;
+ char *lc_ctype;
+ char *lc_messages;
+
int skip_verify;
int compress_keys;
int compress_sigs;
int always_trust;
+ int pgp2;
+ int pgp6;
+ int pgp7; /* if we get any more of these, it's time to look at a
+ special emulate_pgp variable... */
int rfc1991;
int rfc2440;
int pgp2_workarounds;
@@ -71,33 +101,77 @@ struct {
const char *set_filename;
const char *comment_string;
int throw_keyid;
+ int show_photos;
+ const char *photo_viewer;
int s2k_mode;
int s2k_digest_algo;
int s2k_cipher_algo;
+ int simple_sk_checksum; /* create the deprecated rfc2440 secret
+ key protection*/
int not_dash_escaped;
int escape_from;
int lock_once;
- const char *keyserver_name;
+ char *keyserver_scheme;
+ char *keyserver_host;
+ char *keyserver_port;
+ struct
+ {
+ int verbose;
+ int include_revoked;
+ int include_disabled;
+ int include_subkeys;
+ int honor_http_proxy;
+ int broken_http_proxy;
+ int use_temp_files;
+ int keep_temp_files;
+ int fake_v3_keyids;
+ int auto_key_retrieve;
+ STRLIST other;
+ } keyserver_options;
+ int exec_disable;
+ char *def_preference_list;
+ prefitem_t *personal_cipher_prefs,
+ *personal_digest_prefs,
+ *personal_compress_prefs;
+ int no_perm_warn;
+ char *temp_dir;
int no_encrypt_to;
int interactive;
- STRLIST notation_data;
- const char *set_policy_url;
+ STRLIST sig_notation_data;
+ STRLIST cert_notation_data;
+ int show_notation;
+ STRLIST sig_policy_url;
+ STRLIST cert_policy_url;
+ int show_policy_url;
int use_embedded_filename;
int allow_non_selfsigned_uid;
int allow_freeform_uid;
int no_literal;
ulong set_filesize;
- int honor_http_proxy;
int fast_list_mode;
+ int fixed_list_mode;
int ignore_time_conflict;
+ int ignore_valid_from;
+ int ignore_crc_error;
int command_fd;
- int auto_key_retrieve;
+ const char *override_session_key;
+ int show_session_key;
int use_agent;
+ const char *gpg_agent_info;
int merge_only;
int try_all_secrets;
+ int no_expensive_trust_checks;
+ int no_sig_cache;
+ int no_sig_create_check;
+ int no_auto_check_trustdb;
+ int preserve_permissions;
+ int no_homedir_creation;
+ int show_keyring;
+ struct groupitem *grouplist;
} opt;
+#define EMUBUG_GPGCHKSUM 1
#define EMUBUG_3DESS2K 2
#define EMUBUG_MDENCODE 4
@@ -112,14 +186,15 @@ struct {
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
+#define DBG_EXTPROG_VALUE 1024 /* debug external program calls */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
-#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
-#define DBG_CIPHER (opt.debug & DBG_CIPHER_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
+#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
+
-#endif /*GPG_OPTIONS_H*/
+#endif /*G10_OPTIONS_H*/
diff --git a/g10/options.skel b/g10/options.skel
index 646e0152b..93bcfcd57 100644
--- a/g10/options.skel
+++ b/g10/options.skel
@@ -2,6 +2,15 @@ These first three lines are not copied to the options file in
the users home directory.
$Id$
# Options for GnuPG
+# Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Unless you you specify which option file to use (with the
# commandline option "--options filename"), GnuPG uses the
@@ -22,6 +31,7 @@ $Id$
#default-key 621CC013
+
# If you do not pass a recipient to gpg, it will ask for one.
# Using this option you can encrypt to a default key. key validation
# will not be done in this case.
@@ -30,31 +40,32 @@ $Id$
#default-recipient some-user-id
#default-recipient-self
-
-# The next option is enabled because this one is needed for interoperation
-# with PGP 5 users. To enable full OpenPGP compliance you have to remove
-# this option.
-
-force-v3-sigs
+# By default GnuPG creates version 3 signatures for data files. This
+# is not OpenPGP compliant but PGP 6 requires them. To disable it,
+# you may use this option or --openpgp.
+#no-force-v3-sigs
# Because some mailers change lines starting with "From " to ">From "
# it is good to handle such lines in a special way when creating
-# cleartext signatures; all other PGP versions it this way too.
-# To enable full OpenPGP compliance you have to remove this option.
-
-escape-from-lines
-
-# If you do not use the Latin-1 (ISO-8859-1) charset, you should
-# tell GnuPG which is the native character set. Please check
-# the man page for supported character sets.
-#charset koi8-r
-
-
-# You may define aliases like this:
-# alias mynames -u 0x12345678 -u 0x456789ab -z 9
-# everytime you use --mynames, it will be expanded to the options
-# in the above defintion. The name of the alias may not be abbreviated.
-# NOTE: This is not yet implemented
+# cleartext signatures; all other PGP versions do it this way too.
+# To enable full OpenPGP compliance you may want to use this option.
+#no-escape-from-lines
+
+# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
+# GnuPG which is the native character set. Please check the man page
+# for supported character sets. This character set is only used for
+# Meta data and not for the actual message which does not undergo any
+# translation. Note that future version of GnuPG will change to UTF-8
+# as default character set.
+#charset utf-8
+
+# Group names may be defined like this:
+# group mynames paige 0x12345678 joe patti
+#
+# Any time "mynames" is a receipient (-r or --recipient), it will be
+# expanded to the names "paige", "joe", and "patti", and the key ID
+# "0x12345678". Note there is only one level of expansion - you
+# cannot make an group that points to another group.
# lock the file only once for the lifetime of a process.
# if you do not define this, the lock will be obtained and released
@@ -70,17 +81,122 @@ lock-once
#load-extension rndunix
#load-extension rndegd
+# GnuPG can send and receive keys to and from a keyserver. These
+# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
+# support).
+#
+# Example HKP keyserver:
+# x-hkp://keyserver.cryptnet.net
+#
+# Example email keyserver:
+# mailto:pgp-public-keys@keys.nl.pgp.net
+#
+# Example LDAP keyserver:
+# ldap://pgp.surfnet.nl:11370
+#
+# Regular URL syntax applies, and you can set an alternate port
+# through the usual method:
+# x-hkp://keyserver.example.net:22742
+#
+# If you have problems connecting to a HKP server through a buggy http
+# proxy, you can use keyserver option broken-http-proxy (see below),
+# but first you should make sure that you have read the man page
+# regarding proxies (keyserver option honor-http-proxy)
+#
+# Most users just set the name and type of their preferred keyserver.
+# Most servers do synchronize with each other and DNS round-robin may
+# give you a quasi-random server each time.
-# GnuPG can import a key from a HKP keyerver if one is missing
-# for sercain operations. Is you set this option to a keyserver
-# you will be asked in such a case whether GnuPG should try to
-# import the key from that server (server do syncronize with each
-# others and DNS Round-Robin may give you a random server each time).
-# Use "host -l pgp.net | grep www" to figure out a keyserver.
-#keyserver wwwkeys.eu.pgp.net
+#keyserver x-hkp://keyserver.cryptnet.net
+#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
+#keyserver ldap://pgp.surfnet.nl:11370
-# The environment variable http_proxy is only used when the
-# this option is set.
+# Options for keyserver functions
+#
+# include-disabled = when searching, include keys marked as "disabled"
+# on the keyserver (not all keyservers support this).
+#
+# include-revoked = when searching, include keys marked as "revoked"
+# on the keyserver.
+#
+# verbose = show more information as the keys are fetched.
+# Can be used more than once to increase the amount
+# of information shown.
+#
+# use-temp-files = use temporary files instead of a pipe to talk to the
+# keyserver. Some platforms (Win32 for one) always
+# have this on.
+#
+# keep-temp-files = do not delete temporary files after using them
+# (really only useful for debugging)
+#
+# honor-http-proxy = if the keyserver uses HTTP, honor the http_proxy
+# environment variable
+#
+# broken-http-proxy = try to work around a buggy HTTP proxy
+#
+# auto-key-retrieve = automatically fetch keys as needed from the
+# keyserver when verifying signatures or when importing
+# keys that have been revoked by a revocation key that
+# is not present on the keyring.
+
+#keyserver-options auto-key-retrieve include-disabled include-revoked
-honor-http-proxy
+# Uncomment this line to display photo user IDs in key listings
+#show-photos
+# Use this program to display photo user IDs
+#
+# %i is expanded to a temporary file that contains the photo.
+# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
+# %k is expanded to the key ID of the key.
+# %K is expanded to the long OpenPGP key ID of the key.
+# %t is expanded to the extension of the image (e.g. "jpg").
+# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
+# %f is expanded to the fingerprint of the key.
+# %% is %, of course.
+#
+# If %i or %I are not present, then the photo is supplied to the
+# viewer on standard input. If your platform supports it, standard
+# input is the best way to do this as it avoids the time and effort in
+# generating and then cleaning up a secure temp file.
+#
+# The default program is "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"
+#
+# Some other viewers:
+# photo-viewer "qiv %i"
+# photo-viewer "ee %i"
+# photo-viewer "display -title 'KeyID 0x%k'"
+#
+# This one saves a copy of the photo ID in your home directory:
+# photo-viewer "cat > ~/photoid-for-key-%k.%t"
+#
+# Use your MIME handler to view photos:
+# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
+#
+# Use the Win32 registry to pick a viewer for you:
+# On Win95/98/Me (also the default on Win32):
+# photo-viewer "start /w"
+# On NT/2k/XP:
+# photo-viewer "cmd /c start /w"
+
+
+# Passphrase agent
+#
+# We support the old experimental passphrase agent protocol as well
+# as the new Assuan based one (currently available in the "newpg" package
+# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent, you have
+# to run an agent as daemon and use the option
+#
+# use-agent
+#
+# which tries to use the agent but will fallback to the regular mode
+# if there is a problem connecting to the agent. The normal way to
+# locate the agent is by looking at the environment variable
+# GPG_AGENT_INFO which should have been set during gpg-agent startup.
+# In certain situations the use of this variable is not possible, thus
+# the option
+#
+# --gpg-agent-info=<path>:<pid>:1
+#
+# may be used to override it.
diff --git a/g10/packet.h b/g10/packet.h
index 2f7f16f8c..023680b9e 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -1,5 +1,5 @@
-/* packet.h - packet read/write stuff
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* packet.h - packet definitions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,22 +18,15 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_PACKET_H
-#define GPG_PACKET_H
+#ifndef G10_PACKET_H
+#define G10_PACKET_H
#include "types.h"
#include "iobuf.h"
+#include "mpi.h"
+#include "cipher.h"
#include "filter.h"
-
-#ifndef DID_MPI_TYPEDEF
- typedef struct gcry_mpi *MPI;
- #define DID_MPI_TYPEDEF
-#endif
-
-#define GNUPG_MAX_NPKEY 4
-#define GNUPG_MAX_NSKEY 6
-#define GNUPG_MAX_NSIG 2
-#define GNUPG_MAX_NENC 2
+#include "global.h"
#define DEBUG_PARSE_PACKET 1
@@ -54,14 +47,34 @@ typedef enum {
PKT_USER_ID =13, /* user id packet */
PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */
PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */
- PKT_PHOTO_ID =17, /* PGP's photo ID */
+ PKT_ATTRIBUTE =17, /* PGP's attribute packet */
PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */
PKT_MDC =19, /* manipulaion detection code packet */
PKT_COMMENT =61, /* new comment packet (private) */
+ PKT_GPG_CONTROL =63 /* internal control packet */
} pkttype_t;
typedef struct packet_struct PACKET;
+/* PKT_GPG_CONTROL types */
+typedef enum {
+ CTRLPKT_CLEARSIGN_START = 1,
+ CTRLPKT_PIPEMODE = 2,
+ CTRLPKT_PLAINTEXT_MARK =3
+} ctrlpkttype_t;
+
+typedef enum {
+ PREFTYPE_NONE = 0,
+ PREFTYPE_SYM = 1,
+ PREFTYPE_HASH = 2,
+ PREFTYPE_ZIP = 3
+} preftype_t;
+
+typedef struct {
+ byte type;
+ byte value;
+} prefitem_t;
+
typedef struct {
int mode;
byte hash_algo;
@@ -82,7 +95,7 @@ typedef struct {
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
byte throw_keyid;
- MPI data[GNUPG_MAX_NENC];
+ MPI data[PUBKEY_MAX_NENC];
} PKT_pubkey_enc;
@@ -96,25 +109,74 @@ typedef struct {
typedef struct {
+ size_t size; /* allocated */
+ size_t len; /* used */
+ byte data[1];
+} subpktarea_t;
+
+struct revocation_key {
+ byte class;
+ byte algid;
+ byte fpr[MAX_FINGERPRINT_LEN];
+};
+
+typedef struct {
ulong local_id; /* internal use, valid if > 0 */
struct {
unsigned checked:1; /* signature has been checked */
unsigned valid:1; /* signature is good (if checked is set) */
unsigned unknown_critical:1;
+ unsigned exportable:1;
+ unsigned revocable:1;
+ unsigned policy_url:1; /* Policy URL is present */
+ unsigned notation:1; /* At least one notation is present */
+ unsigned expired:1;
} flags;
u32 keyid[2]; /* 64 bit keyid */
u32 timestamp; /* signature made */
+ u32 expiredate; /* expires at this date or 0 if not at all */
byte version;
byte sig_class; /* sig classification, append for MD calculation*/
byte pubkey_algo; /* algorithm used for public key scheme */
- /* (GCRY_PK_xxx) */
- byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
- byte *hashed_data; /* all subpackets with hashed data (v4 only) */
- byte *unhashed_data; /* ditto for unhashed data */
+ /* (PUBKEY_ALGO_xxx) */
+ byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
+ struct revocation_key **revkey;
+ int numrevkeys;
+ subpktarea_t *hashed; /* all subpackets with hashed data (v4 only) */
+ subpktarea_t *unhashed; /* ditto for unhashed data */
byte digest_start[2]; /* first 2 bytes of the digest */
- MPI data[GNUPG_MAX_NSIG];
+ MPI data[PUBKEY_MAX_NSIG];
} PKT_signature;
+#define ATTRIB_IMAGE 1
+
+/* This is the cooked form of attributes */
+struct user_attribute {
+ byte type;
+ const byte *data;
+ unsigned long len;
+};
+
+typedef struct {
+ int ref; /* reference counter */
+ int len; /* length of the name */
+ struct user_attribute *attribs;
+ int numattribs;
+ byte *attrib_data; /* if this is not NULL, the packet is an attribute */
+ unsigned long attrib_len;
+ int help_key_usage;
+ u32 help_key_expire;
+ int is_primary;
+ int is_revoked;
+ int is_expired;
+ u32 expiredate; /* expires at this date or 0 if not at all */
+ prefitem_t *prefs; /* list of preferences (may be NULL)*/
+ int mdc_feature;
+ u32 created; /* according to the self-signature */
+ byte selfsigversion;
+ char name[1];
+} PKT_user_id;
+
/****************
* Note about the pkey/skey elements: We assume that the secret keys
@@ -125,31 +187,38 @@ typedef struct {
typedef struct {
u32 timestamp; /* key made */
u32 expiredate; /* expires at this date or 0 if not at all */
+ u32 max_expiredate; /* must not expire past this date */
byte hdrbytes; /* number of header bytes */
byte version;
+ byte selfsigversion; /* highest version of all of the self-sigs */
byte pubkey_algo; /* algorithm used for public key scheme */
- byte pubkey_usage; /* the actual allowed usage as set by getkey() */
- u32 created; /* according to the self-signature */
+ byte pubkey_usage; /* for now only used to pass it to getkey() */
byte req_usage; /* hack to pass a request to getkey() */
byte req_algo; /* Ditto */
u32 has_expired; /* set to the expiration date if expired */
int is_revoked; /* key has been revoked */
int is_valid; /* key (especially subkey) is valid */
+ int dont_cache; /* do not cache this */
ulong local_id; /* internal use, valid if > 0 */
u32 main_keyid[2]; /* keyid of the primary key */
u32 keyid[2]; /* calculated by keyid_from_pk() */
+ prefitem_t *prefs; /* list of preferences (may be NULL) */
+ int mdc_feature; /* mdc feature set */
byte *namehash; /* if != NULL: found by this name */
- MPI pkey[GNUPG_MAX_NPKEY];
+ PKT_user_id *user_id; /* if != NULL: found by that uid */
+ struct revocation_key *revkey;
+ int numrevkeys;
+ MPI pkey[PUBKEY_MAX_NPKEY];
} PKT_public_key;
typedef struct {
u32 timestamp; /* key made */
u32 expiredate; /* expires at this date or 0 if not at all */
+ u32 max_expiredate; /* must not expire past this date */
byte hdrbytes; /* number of header bytes */
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
byte pubkey_usage;
- u32 created; /* according to the self-signature */
byte req_usage;
byte req_algo;
u32 has_expired; /* set to the expiration date if expired */
@@ -164,11 +233,12 @@ typedef struct {
/* and should never be passed to a mpi_xxx() */
struct {
byte algo; /* cipher used to protect the secret information*/
+ byte sha1chk; /* SHA1 is used instead of a 16 bit checksum */
STRING2KEY s2k;
byte ivlen; /* used length of the iv */
byte iv[16]; /* initialization vector for CFB mode */
} protect;
- MPI skey[GNUPG_MAX_NSKEY];
+ MPI skey[PUBKEY_MAX_NSKEY];
u16 csum; /* checksum */
} PKT_secret_key;
@@ -179,19 +249,6 @@ typedef struct {
} PKT_comment;
typedef struct {
- ulong stored_at; /* the stream offset where it was stored
- * by build-packet */
- int len; /* length of the name */
- char *photo; /* if this is not NULL, the packet is a photo ID */
- int photolen; /* and the length of the photo */
- int help_key_usage;
- u32 help_key_expire;
- int is_primary;
- u32 created; /* according to the self-signature */
- char name[1];
-} PKT_user_id;
-
-typedef struct {
u32 len; /* reserved */
byte new_ctb;
byte algorithm;
@@ -200,6 +257,7 @@ typedef struct {
typedef struct {
u32 len; /* length of encrypted data */
+ int extralen; /* this is (blocksize+2) */
byte new_ctb; /* uses a new CTB */
byte mdc_method; /* > 0: integrity protected encrypted data packet */
IOBUF buf; /* IOBUF reference */
@@ -211,18 +269,25 @@ typedef struct {
typedef struct {
unsigned int trustval;
+ unsigned int sigcache;
} PKT_ring_trust;
typedef struct {
u32 len; /* length of encrypted data */
IOBUF buf; /* IOBUF reference */
byte new_ctb;
+ byte is_partial; /* partial length encoded */
int mode;
u32 timestamp;
int namelen;
char name[1];
} PKT_plaintext;
+typedef struct {
+ int control;
+ size_t datalen;
+ char data[1];
+} PKT_gpg_control;
/* combine all packets into a union */
struct packet_struct {
@@ -242,6 +307,7 @@ struct packet_struct {
PKT_mdc *mdc; /* PKT_MDC */
PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
+ PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
} pkt;
};
@@ -276,7 +342,7 @@ typedef enum {
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
SIGSUBPKT_FEATURES =30, /* feature flags */
- SIGSUBPKT_PRIV_ADD_SIG =101,/* signatur is also valid for this uid */
+ SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result (obsolete)*/
SIGSUBPKT_FLAG_CRITICAL=128
} sigsubpkttype_t;
@@ -293,39 +359,62 @@ int list_packets( IOBUF a );
int set_packet_list_mode( int mode );
#if DEBUG_PARSE_PACKET
-int dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos, const char* file, int lineno );
-int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt, ulong *pos,
+int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
+ const char* file, int lineno );
+int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
const char* file, int lineno );
-int dbg_copy_all_packets( IOBUF inp, IOBUF out, const char* file, int lineno );
-int dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff, const char* file, int lineno );
-int dbg_skip_some_packets( IOBUF inp, unsigned n, const char* file, int lineno );
-#define search_packet( a,b,c,d ) dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
-#define parse_packet( a, b, c ) dbg_parse_packet( (a), (b), (c), __FILE__, __LINE__ )
-#define copy_all_packets( a,b ) dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
-#define copy_some_packets( a,b,c ) dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
-#define skip_some_packets( a,b ) dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
+int dbg_copy_all_packets( IOBUF inp, IOBUF out,
+ const char* file, int lineno );
+int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
+ const char* file, int lineno );
+int dbg_skip_some_packets( IOBUF inp, unsigned n,
+ const char* file, int lineno );
+#define search_packet( a,b,c,d ) \
+ dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
+#define parse_packet( a, b ) \
+ dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
+#define copy_all_packets( a,b ) \
+ dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
+#define copy_some_packets( a,b,c ) \
+ dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
+#define skip_some_packets( a,b ) \
+ dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
#else
-int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos );
-int parse_packet( IOBUF inp, PACKET *ret_pkt, ulong *retpos);
+int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid );
+int parse_packet( IOBUF inp, PACKET *ret_pkt);
int copy_all_packets( IOBUF inp, IOBUF out );
-int copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff );
+int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
int skip_some_packets( IOBUF inp, unsigned n );
#endif
-const byte *enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
- size_t *ret_n, int *start );
-const byte *parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
- size_t *ret_n );
-const byte *parse_sig_subpkt2( PKT_signature *sig,
- sigsubpkttype_t reqtype, size_t *ret_n );
+const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical );
+const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n );
+const byte *parse_sig_subpkt2 ( PKT_signature *sig,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n );
+int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
+void parse_revkeys(PKT_signature *sig);
+int parse_attribute_subpkts(PKT_user_id *uid);
+void make_attribute_uidname(PKT_user_id *uid);
+PACKET *create_gpg_control ( ctrlpkttype_t type,
+ const byte *data,
+ size_t datalen );
/*-- build-packet.c --*/
int build_packet( IOBUF inp, PACKET *pkt );
u32 calc_packet_length( PACKET *pkt );
-void hash_public_key( GCRY_MD_HD md, PKT_public_key *pk );
+void hash_public_key( MD_HANDLE md, PKT_public_key *pk );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig( PKT_signature *sig );
+int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
+void build_attribute_subpkt(PKT_user_id *uid,byte type,
+ const void *buf,int buflen,
+ const void *header,int headerlen);
/*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc );
@@ -336,18 +425,16 @@ void release_public_key_parts( PKT_public_key *pk );
void free_public_key( PKT_public_key *key );
void release_secret_key_parts( PKT_secret_key *sk );
void free_secret_key( PKT_secret_key *sk );
+void free_attributes(PKT_user_id *uid);
void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
+prefitem_t *copy_prefs (const prefitem_t *prefs);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
-PKT_public_key *copy_public_key_new_namehash( PKT_public_key *d,
- PKT_public_key *s,
- const byte *namehash );
-void copy_public_parts_to_secret_key( PKT_public_key *pk,
- PKT_secret_key *sk );
+void copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
-PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
+PKT_user_id *scopy_user_id (PKT_user_id *sd );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
int cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b );
int cmp_signatures( PKT_signature *a, PKT_signature *b );
@@ -356,7 +443,9 @@ int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
/*-- sig-check.c --*/
-int signature_check( PKT_signature *sig, GCRY_MD_HD digest );
+int signature_check( PKT_signature *sig, MD_HANDLE digest );
+int signature_check2( PKT_signature *sig, MD_HANDLE digest,
+ u32 *r_expiredate, int *r_expired );
/*-- seckey-cert.c --*/
int is_secret_key_protected( PKT_secret_key *sk );
@@ -365,6 +454,7 @@ int protect_secret_key( PKT_secret_key *sk, DEK *dek );
/*-- pubkey-enc.c --*/
int get_session_key( PKT_pubkey_enc *k, DEK *dek );
+int get_override_session_key( DEK *dek, const char *string );
/*-- compress.c --*/
int handle_compressed( void *ctx, PKT_compressed *cd,
@@ -376,7 +466,7 @@ int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek );
/*-- plaintext.c --*/
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
int nooutput, int clearsig );
-int ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
+int ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
const char *inname, int textmode );
/*-- comment.c --*/
@@ -385,12 +475,19 @@ int write_comment( IOBUF out, const char *s );
/*-- sign.c --*/
int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
- PKT_secret_key *sk,
- int sigclass, int digest_algo,
+ PKT_secret_key *sk, int sigclass, int digest_algo,
+ int sigversion, u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
+int update_keysig_packet( PKT_signature **ret_sig,
+ PKT_signature *orig_sig,
+ PKT_public_key *pk,
+ PKT_user_id *uid,
+ PKT_secret_key *sk,
+ int (*mksubpkt)(PKT_signature *, void *),
+ void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id(void);
-#endif /*GPG_PACKET_H*/
+#endif /*G10_PACKET_H*/
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 691be6662..d57659b6b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1,5 +1,5 @@
/* parse-packet.c - read packets
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,11 +24,14 @@
#include <string.h>
#include <assert.h>
-#include <gcrypt.h>
#include "packet.h"
#include "iobuf.h"
+#include "mpi.h"
#include "util.h"
+#include "cipher.h"
+#include "memory.h"
#include "filter.h"
+#include "photoid.h"
#include "options.h"
#include "main.h"
#include "i18n.h"
@@ -36,8 +39,8 @@
static int mpi_print_mode = 0;
static int list_mode = 0;
-static int parse( IOBUF inp, PACKET *pkt, int reqtype,
- ulong *retpos, int *skip, IOBUF out, int do_skip
+static int parse( IOBUF inp, PACKET *pkt, int onlykeypkts,
+ off_t *retpos, int *skip, IOBUF out, int do_skip
#ifdef DEBUG_PARSE_PACKET
,const char *dbg_w, const char *dbg_f, int dbg_l
#endif
@@ -59,7 +62,7 @@ static int parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
byte *hdr, int hdrlen, PACKET *packet );
static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet );
-static int parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen,
+static int parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet );
static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet );
@@ -73,6 +76,8 @@ static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet, int new_ctb);
static int parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet, int new_ctb);
+static int parse_gpg_control( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
static unsigned short
read_16(IOBUF inp)
@@ -100,7 +105,7 @@ set_packet_list_mode( int mode )
{
int old = list_mode;
list_mode = mode;
- mpi_print_mode = (opt.debug & DBG_MPI_VALUE);
+ mpi_print_mode = DBG_MPI;
return old;
}
@@ -127,53 +132,51 @@ unknown_pubkey_warning( int algo )
*/
#ifdef DEBUG_PARSE_PACKET
int
-dbg_parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos,
- const char *dbg_f, int dbg_l )
+dbg_parse_packet( IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l )
{
int skip, rc;
do {
- rc = parse( inp, pkt, 0, retpos,
- &skip, NULL, 0, "parse", dbg_f, dbg_l );
+ rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0, "parse", dbg_f, dbg_l );
} while( skip );
return rc;
}
#else
int
-parse_packet( IOBUF inp, PACKET *pkt, ulong *retpos )
+parse_packet( IOBUF inp, PACKET *pkt )
{
int skip, rc;
do {
- rc = parse( inp, pkt, 0, retpos, &skip, NULL, 0 );
+ rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 );
} while( skip );
return rc;
}
#endif
/****************
- * Like parse packet, but only return packets of the given type.
+ * Like parse packet, but only return secret or public (sub)key packets.
*/
#ifdef DEBUG_PARSE_PACKET
int
-dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos,
+dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
const char *dbg_f, int dbg_l )
{
int skip, rc;
do {
- rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
+ rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
} while( skip );
return rc;
}
#else
int
-search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos )
+search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid )
{
int skip, rc;
do {
- rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
+ rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 );
} while( skip );
return rc;
}
@@ -213,7 +216,7 @@ copy_all_packets( IOBUF inp, IOBUF out )
*/
#ifdef DEBUG_PARSE_PACKET
int
-dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff,
+dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
const char *dbg_f, int dbg_l )
{
PACKET pkt;
@@ -228,7 +231,7 @@ dbg_copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff,
}
#else
int
-copy_some_packets( IOBUF inp, IOBUF out, ulong stopoff )
+copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff )
{
PACKET pkt;
int skip, rc=0;
@@ -275,14 +278,14 @@ skip_some_packets( IOBUF inp, unsigned n )
/****************
- * Parse packet. Set the variable skip points to to 1 if the packet
- * should be skipped; this is the case if either there is a
- * requested packet type and the parsed packet doesn't match or the
+ * Parse packet. Set the variable skip points to 1 if the packet
+ * should be skipped; this is the case if either ONLYKEYPKTS is set
+ * and the parsed packet isn't one or the
* packet-type is 0, indicating deleted stuff.
* if OUT is not NULL, a special copymode is used.
*/
static int
-parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
+parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
int *skip, IOBUF out, int do_skip
#ifdef DEBUG_PARSE_PACKET
,const char *dbg_w, const char *dbg_f, int dbg_l
@@ -294,6 +297,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
byte hdr[8];
int hdrlen;
int new_ctb = 0;
+ int with_uid = (onlykeypkts == 2);
*skip = 0;
assert( !pkt->pkt.generic );
@@ -307,9 +311,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
hdrlen=0;
hdr[hdrlen++] = ctb;
if( !(ctb & 0x80) ) {
- log_error("%s: invalid packet (ctb=%02x) near %lu\n",
- iobuf_where(inp), ctb, iobuf_tell(inp) );
- rc = GPGERR_INVALID_PACKET;
+ log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
pktlen = 0;
@@ -318,7 +321,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
pkttype = ctb & 0x3f;
if( (c = iobuf_get(inp)) == -1 ) {
log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
hdr[hdrlen++] = c;
@@ -328,7 +331,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
pktlen = (c - 192) * 256;
if( (c = iobuf_get(inp)) == -1 ) {
log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
hdr[hdrlen++] = c;
@@ -340,7 +343,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
if( (c = iobuf_get(inp)) == -1 ) {
log_error("%s: 4 byte length invalid\n", iobuf_where(inp) );
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
pktlen |= (hdr[hdrlen++] = c );
@@ -366,15 +369,30 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
}
}
+ if (pktlen == 0xffffffff) {
+ /* with a some probability this is caused by a problem in the
+ * the uncompressing layer - in some error cases it just loops
+ * and spits out 0xff bytes. */
+ log_error ("%s: garbled packet detected\n", iobuf_where(inp) );
+ g10_exit (2);
+ }
+
if( out && pkttype ) {
if( iobuf_write( out, hdr, hdrlen ) == -1 )
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
else
rc = copy_packet(inp, out, pkttype, pktlen );
goto leave;
}
- if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
+ if (with_uid && pkttype == PKT_USER_ID)
+ ;
+ else if( do_skip
+ || !pkttype
+ || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
+ && pkttype != PKT_PUBLIC_KEY
+ && pkttype != PKT_SECRET_SUBKEY
+ && pkttype != PKT_SECRET_KEY ) ) {
skip_rest(inp, pktlen);
*skip = 1;
rc = 0;
@@ -392,16 +410,16 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
#endif
}
pkt->pkttype = pkttype;
- rc = GPGERR_UNKNOWN_PACKET; /* default error */
+ rc = G10ERR_UNKNOWN_PACKET; /* default error */
switch( pkttype ) {
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
- pkt->pkt.public_key = gcry_xcalloc( 1,sizeof *pkt->pkt.public_key );
+ pkt->pkt.public_key = m_alloc_clear(sizeof *pkt->pkt.public_key );
rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
break;
case PKT_SECRET_KEY:
case PKT_SECRET_SUBKEY:
- pkt->pkt.secret_key = gcry_xcalloc( 1,sizeof *pkt->pkt.secret_key );
+ pkt->pkt.secret_key = m_alloc_clear(sizeof *pkt->pkt.secret_key );
rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt );
break;
case PKT_SYMKEY_ENC:
@@ -411,19 +429,19 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt );
break;
case PKT_SIGNATURE:
- pkt->pkt.signature = gcry_xcalloc( 1,sizeof *pkt->pkt.signature );
+ pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
break;
case PKT_ONEPASS_SIG:
- pkt->pkt.onepass_sig = gcry_xcalloc( 1,sizeof *pkt->pkt.onepass_sig );
+ pkt->pkt.onepass_sig = m_alloc_clear(sizeof *pkt->pkt.onepass_sig );
rc = parse_onepass_sig(inp, pkttype, pktlen, pkt->pkt.onepass_sig );
break;
case PKT_USER_ID:
rc = parse_user_id(inp, pkttype, pktlen, pkt );
break;
- case PKT_PHOTO_ID:
- pkt->pkttype = pkttype = PKT_USER_ID; /* must fix it */
- rc = parse_photo_id(inp, pkttype, pktlen, pkt);
+ case PKT_ATTRIBUTE:
+ pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */
+ rc = parse_attribute(inp, pkttype, pktlen, pkt);
break;
case PKT_OLD_COMMENT:
case PKT_COMMENT:
@@ -446,6 +464,9 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
case PKT_MDC:
rc = parse_mdc(inp, pkttype, pktlen, pkt, new_ctb );
break;
+ case PKT_GPG_CONTROL:
+ rc = parse_gpg_control(inp, pkttype, pktlen, pkt );
+ break;
default:
skip_packet(inp, pkttype, pktlen);
break;
@@ -453,7 +474,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
leave:
if( !rc && iobuf_error(inp) )
- rc = GPGERR_INV_KEYRING;
+ rc = G10ERR_INV_KEYRING;
return rc;
}
@@ -483,23 +504,23 @@ copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen )
if( iobuf_in_block_mode(inp) ) {
while( (n = iobuf_read( inp, buf, 100 )) != -1 )
if( iobuf_write(out, buf, n ) )
- return GPGERR_WRITE_FILE; /* write error */
+ return G10ERR_WRITE_FILE; /* write error */
}
else if( !pktlen && pkttype == PKT_COMPRESSED ) {
log_debug("copy_packet: compressed!\n");
/* compressed packet, copy till EOF */
while( (n = iobuf_read( inp, buf, 100 )) != -1 )
if( iobuf_write(out, buf, n ) )
- return GPGERR_WRITE_FILE; /* write error */
+ return G10ERR_WRITE_FILE; /* write error */
}
else {
for( ; pktlen; pktlen -= n ) {
n = pktlen > 100 ? 100 : pktlen;
n = iobuf_read( inp, buf, n );
if( n == -1 )
- return GPGERR_READ_FILE;
+ return G10ERR_READ_FILE;
if( iobuf_write(out, buf, n ) )
- return GPGERR_WRITE_FILE; /* write error */
+ return G10ERR_WRITE_FILE; /* write error */
}
}
return 0;
@@ -559,7 +580,7 @@ read_rest( IOBUF inp, size_t pktlen )
p = NULL;
}
else {
- p = gcry_xmalloc( pktlen );
+ p = m_alloc( pktlen );
for(i=0; pktlen; pktlen--, i++ )
p[i] = iobuf_get(inp);
}
@@ -572,19 +593,23 @@ static int
parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{
PKT_symkey_enc *k;
+ int rc = 0;
int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;
if( pktlen < 4 ) {
log_error("packet(%d) too short\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
version = iobuf_get_noeof(inp); pktlen--;
if( version != 4 ) {
log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( pktlen > 200 ) { /* (we encode the seskeylen in a byte) */
log_error("packet(%d) too large\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
cipher_algo = iobuf_get_noeof(inp); pktlen--;
@@ -606,10 +631,11 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
}
if( minlen > pktlen ) {
log_error("packet with S2K %d too short\n", s2kmode );
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
seskeylen = pktlen - minlen;
- k = packet->pkt.symkey_enc = gcry_xcalloc( 1, sizeof *packet->pkt.symkey_enc
+ k = packet->pkt.symkey_enc = m_alloc_clear( sizeof *packet->pkt.symkey_enc
+ seskeylen - 1 );
k->version = version;
k->cipher_algo = cipher_algo;
@@ -642,24 +668,27 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
leave:
skip_rest(inp, pktlen);
- return 0;
+ return rc;
}
static int
parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{
- unsigned n;
+ unsigned int n;
+ int rc = 0;
int i, ndata;
PKT_pubkey_enc *k;
- k = packet->pkt.pubkey_enc = gcry_xcalloc( 1,sizeof *packet->pkt.pubkey_enc);
+ k = packet->pkt.pubkey_enc = m_alloc_clear(sizeof *packet->pkt.pubkey_enc);
if( pktlen < 12 ) {
log_error("packet(%d) too short\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
k->version = iobuf_get_noeof(inp); pktlen--;
if( k->version != 2 && k->version != 3 ) {
log_error("packet(%d) with unknown version %d\n", pkttype, k->version);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
k->keyid[0] = read_32(inp); pktlen -= 4;
@@ -686,12 +715,14 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
mpi_print(stdout, k->data[i], mpi_print_mode );
putchar('\n');
}
+ if (!k->data[i])
+ rc = G10ERR_INVALID_PACKET;
}
}
leave:
skip_rest(inp, pktlen);
- return 0;
+ return rc;
}
@@ -713,6 +744,7 @@ dump_sig_subpkt( int hashed, int type, int critical,
type, (unsigned)length );
}
+
printf("\t%s%ssubpkt %d len %u (", /*)*/
critical ? "critical ":"",
hashed ? "hashed ":"", type, (unsigned)length );
@@ -737,13 +769,20 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf("%sexportable", *buffer? "":"not ");
break;
case SIGSUBPKT_TRUST:
- p = "trust signature";
+ if(length!=2)
+ p="[invalid trust signature]";
+ else
+ printf("trust signature of level %d, amount %d",buffer[0],buffer[1]);
break;
case SIGSUBPKT_REGEXP:
- p = "regular expression";
+ if(!length)
+ p="[invalid regexp]";
+ else
+ printf("regular expression: \"%s\"",buffer);
break;
case SIGSUBPKT_REVOCABLE:
- p = "revocable";
+ if( length )
+ printf("%srevocable", *buffer? "":"not ");
break;
case SIGSUBPKT_KEY_EXPIRE:
if( length >= 4 )
@@ -806,7 +845,9 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf(" %d", buffer[i] );
break;
case SIGSUBPKT_KS_FLAGS:
- p = "key server preferences";
+ fputs("key server preferences:",stdout);
+ for(i=0;i<length;i++)
+ printf(" %02X", buffer[i]);
break;
case SIGSUBPKT_PREF_KS:
p = "preferred key server";
@@ -822,12 +863,12 @@ dump_sig_subpkt( int hashed, int type, int critical,
fputs ( "key flags:", stdout );
for( i=0; i < length; i++ )
printf(" %02X", buffer[i] );
- break;
+ break;
case SIGSUBPKT_SIGNERS_UID:
p = "signer's user ID";
break;
case SIGSUBPKT_REVOC_REASON:
- if( length ) {
+ if( length ) {
printf("revocation reason 0x%02x (", *buffer );
print_string( stdout, buffer+1, length-1, ')' );
p = ")";
@@ -846,10 +887,10 @@ dump_sig_subpkt( int hashed, int type, int critical,
case SIGSUBPKT_FEATURES:
fputs ( "features:", stdout );
for( i=0; i < length; i++ )
- printf(" %02X", buffer[i] );
- break;
- case SIGSUBPKT_PRIV_ADD_SIG: /* gnupg private - to be removed */
- p = "signs additional user ID";
+ printf(" %02x", buffer[i] );
+ break;
+ case SIGSUBPKT_PRIV_VERIFY_CACHE:
+ p = "obsolete verification cache";
break;
default: p = "?"; break;
}
@@ -863,10 +904,14 @@ dump_sig_subpkt( int hashed, int type, int critical,
* -2 unsupported type
* -3 subpacket too short
*/
-static int
+int
parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
{
switch( type ) {
+ case SIGSUBPKT_REV_KEY:
+ if(n < 22)
+ break;
+ return 0;
case SIGSUBPKT_SIG_CREATED:
case SIGSUBPKT_SIG_EXPIRE:
case SIGSUBPKT_KEY_EXPIRE:
@@ -874,12 +919,19 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
break;
return 0;
case SIGSUBPKT_KEY_FLAGS:
- return 0;
+ case SIGSUBPKT_KS_FLAGS:
+ case SIGSUBPKT_PREF_SYM:
+ case SIGSUBPKT_PREF_HASH:
+ case SIGSUBPKT_PREF_COMPR:
+ case SIGSUBPKT_POLICY:
+ case SIGSUBPKT_FEATURES:
+ return 0;
case SIGSUBPKT_EXPORTABLE:
+ case SIGSUBPKT_REVOCABLE:
if( !n )
break;
return 0;
- case SIGSUBPKT_ISSUER:/* issuer key ID */
+ case SIGSUBPKT_ISSUER: /* issuer key ID */
if( n < 8 )
break;
return 0;
@@ -891,23 +943,23 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
if( !n )
break;
return 0;
- case SIGSUBPKT_PREF_SYM:
- case SIGSUBPKT_PREF_HASH:
- case SIGSUBPKT_PREF_COMPR:
- case SIGSUBPKT_FEATURES:
- case SIGSUBPKT_POLICY:
- return 0;
case SIGSUBPKT_PRIMARY_UID:
if ( n != 1 )
break;
return 0;
- case SIGSUBPKT_PRIV_ADD_SIG:
- /* because we use private data, we check the GNUPG marker */
- if( n < 24 )
+ case SIGSUBPKT_PRIV_VERIFY_CACHE:
+ /* We used this in gpg 1.0.5 and 1.0.6 to cache signature
+ * verification results - it is no longer used.
+ * "GPG" 0x00 <mode> <stat>
+ * where mode == 1: valid data, stat == 0: invalid signature
+ * stat == 1: valid signature
+ * (because we use private data, we check our marker) */
+ if( n < 6 )
break;
- if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
+ if( buffer[0] != 'G' || buffer[1] != 'P'
+ || buffer[2] != 'G' || buffer[3] )
return -2;
- return 3;
+ return 4;
default: return -1;
}
return -3;
@@ -927,15 +979,18 @@ can_handle_critical( const byte *buffer, size_t n, int type )
case SIGSUBPKT_SIG_EXPIRE:
case SIGSUBPKT_KEY_EXPIRE:
case SIGSUBPKT_EXPORTABLE:
+ case SIGSUBPKT_REVOCABLE:
+ case SIGSUBPKT_REV_KEY:
case SIGSUBPKT_ISSUER:/* issuer key ID */
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
- case SIGSUBPKT_FEATURES:
case SIGSUBPKT_KEY_FLAGS:
+ case SIGSUBPKT_PRIMARY_UID:
+ case SIGSUBPKT_FEATURES:
+ case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
return 1;
- case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
default:
return 0;
}
@@ -943,37 +998,40 @@ can_handle_critical( const byte *buffer, size_t n, int type )
const byte *
-enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
- size_t *ret_n, int *start )
+enum_sig_subpkt( const subpktarea_t *pktbuf, sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical )
{
+ const byte *buffer;
int buflen;
int type;
- int critical;
+ int critical_dummy;
int offset;
size_t n;
int seq = 0;
int reqseq = start? *start: 0;
- if( !buffer || reqseq == -1 ) {
+ if(!critical)
+ critical=&critical_dummy;
+
+ if( !pktbuf || reqseq == -1 ) {
/* return some value different from NULL to indicate that
- * there is no crtitical bit we do not understand. The caller
+ * there is no critical bit we do not understand. The caller
* will never use the value. Yes I know, it is an ugly hack */
- return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&buffer : NULL;
+ return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&pktbuf : NULL;
}
- buflen = (*buffer << 8) | buffer[1];
- buffer += 2;
+ buffer = pktbuf->data;
+ buflen = pktbuf->len;
while( buflen ) {
n = *buffer++; buflen--;
- if( n == 255 ) {
+ if( n == 255 ) { /* 4 byte length header */
if( buflen < 4 )
goto too_short;
n = (buffer[0] << 24) | (buffer[1] << 16)
- | (buffer[2] << 8) | buffer[3];
+ | (buffer[2] << 8) | buffer[3];
buffer += 4;
buflen -= 4;
-
}
- else if( n >= 192 ) {
+ else if( n >= 192 ) { /* 2 byte special encoded length header */
if( buflen < 2 )
goto too_short;
n = (( n - 192 ) << 8) + *buffer + 192;
@@ -985,14 +1043,14 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
type = *buffer;
if( type & 0x80 ) {
type &= 0x7f;
- critical = 1;
+ *critical = 1;
}
else
- critical = 0;
+ *critical = 0;
if( !(++seq > reqseq) )
;
else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) {
- if( critical ) {
+ if( *critical ) {
if( n-1 > buflen+1 )
goto too_short;
if( !can_handle_critical(buffer+1, n-1, type ) ) {
@@ -1006,7 +1064,7 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
}
else if( reqtype < 0 ) /* list packets */
dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
- type, critical, buffer, buflen, n );
+ type, *critical, buffer, buflen, n );
else if( type == reqtype ) { /* found */
buffer++;
n--;
@@ -1048,23 +1106,49 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype,
const byte *
-parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
+parse_sig_subpkt (const subpktarea_t *buffer, sigsubpkttype_t reqtype,
+ size_t *ret_n)
{
- return enum_sig_subpkt( buffer, reqtype, ret_n, NULL );
+ return enum_sig_subpkt( buffer, reqtype, ret_n, NULL, NULL );
}
const byte *
-parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
+parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype,
+ size_t *ret_n )
{
const byte *p;
- p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
+ p = parse_sig_subpkt (sig->hashed, reqtype, ret_n );
if( !p )
- p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
+ p = parse_sig_subpkt (sig->unhashed, reqtype, ret_n );
return p;
}
-
+/* Find all revocation keys. Look in hashed area only. */
+void parse_revkeys(PKT_signature *sig)
+{
+ struct revocation_key *revkey;
+ int seq=0;
+ size_t len;
+
+ if(sig->sig_class!=0x1F)
+ return;
+
+ while((revkey=
+ (struct revocation_key *)enum_sig_subpkt(sig->hashed,
+ SIGSUBPKT_REV_KEY,
+ &len,&seq,NULL)))
+ {
+ if(len==sizeof(struct revocation_key) &&
+ (revkey->class&0x80)) /* 0x80 bit must be set */
+ {
+ sig->revkey=m_realloc(sig->revkey,
+ sizeof(struct revocation_key *)*(sig->numrevkeys+1));
+ sig->revkey[sig->numrevkeys]=revkey;
+ sig->numrevkeys++;
+ }
+ }
+}
static int
parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
@@ -1085,6 +1169,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
is_v4=1;
else if( sig->version != 2 && sig->version != 3 ) {
log_error("packet(%d) with unknown version %d\n", pkttype, sig->version);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
@@ -1099,19 +1184,22 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
}
sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
sig->digest_algo = iobuf_get_noeof(inp); pktlen--;
+ sig->flags.exportable=1;
+ sig->flags.revocable=1;
if( is_v4 ) { /* read subpackets */
n = read_16(inp); pktlen -= 2; /* length of hashed data */
if( n > 10000 ) {
log_error("signature packet: hashed data too long\n");
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( n ) {
- sig->hashed_data = gcry_xmalloc( n + 2 );
- sig->hashed_data[0] = n >> 8;
- sig->hashed_data[1] = n;
- if( iobuf_read(inp, sig->hashed_data+2, n ) != n ) {
- log_error("premature eof while reading hashed signature data\n");
+ sig->hashed = m_alloc (sizeof (*sig->hashed) + n - 1 );
+ sig->hashed->size = n;
+ sig->hashed->len = n;
+ if( iobuf_read (inp, sig->hashed->data, n ) != n ) {
+ log_error ("premature eof while reading "
+ "hashed signature data\n");
rc = -1;
goto leave;
}
@@ -1120,15 +1208,19 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
n = read_16(inp); pktlen -= 2; /* length of unhashed data */
if( n > 10000 ) {
log_error("signature packet: unhashed data too long\n");
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( n ) {
- sig->unhashed_data = gcry_xmalloc( n + 2 );
- sig->unhashed_data[0] = n >> 8;
- sig->unhashed_data[1] = n;
- if( iobuf_read(inp, sig->unhashed_data+2, n ) != n ) {
- log_error("premature eof while reading unhashed signature data\n");
+ /* we add 8 extra bytes so that we have space for the signature
+ * status cache. Well we are wastin this if there is a cache
+ * packet already, but in the other case it avoids an realloc */
+ sig->unhashed = m_alloc (sizeof(*sig->unhashed) + n + 8 - 1 );
+ sig->unhashed->size = n + 8;
+ sig->unhashed->len = n;
+ if( iobuf_read(inp, sig->unhashed->data, n ) != n ) {
+ log_error("premature eof while reading "
+ "unhashed signature data\n");
rc = -1;
goto leave;
}
@@ -1138,7 +1230,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
if( pktlen < 5 ) { /* sanity check */
log_error("packet(%d) too short\n", pkttype);
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
@@ -1150,14 +1242,14 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
/* set sig->flags.unknown_critical if there is a
* critical bit set for packets which we do not understand */
- if( !parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_TEST_CRITICAL, NULL)
- || !parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_TEST_CRITICAL,
+ if( !parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)
+ || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL,
NULL) )
{
sig->flags.unknown_critical = 1;
}
- p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL );
if( !p )
log_error("signature packet without timestamp\n");
else
@@ -1169,6 +1261,37 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
sig->keyid[0] = buffer_to_u32(p);
sig->keyid[1] = buffer_to_u32(p+4);
}
+
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_SIG_EXPIRE,NULL);
+ if(p)
+ sig->expiredate=sig->timestamp+buffer_to_u32(p);
+ if(sig->expiredate && sig->expiredate<=make_timestamp())
+ sig->flags.expired=1;
+
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,NULL);
+ if(p)
+ sig->flags.policy_url=1;
+
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,NULL);
+ if(p)
+ sig->flags.notation=1;
+
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_REVOCABLE,NULL);
+ if(p && *p==0)
+ sig->flags.revocable=0;
+
+ /* We accept the exportable subpacket from either the hashed
+ or unhashed areas as older versions of gpg put it in the
+ unhashed area. In theory, anyway, we should never see this
+ packet off of a local keyring. */
+
+ p=parse_sig_subpkt2(sig,SIGSUBPKT_EXPORTABLE,NULL);
+ if(p && *p==0)
+ sig->flags.exportable=0;
+
+ /* Find all revocation keys. */
+ if(sig->sig_class==0x1F)
+ parse_revkeys(sig);
}
if( list_mode ) {
@@ -1181,8 +1304,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
sig->digest_algo,
sig->digest_start[0], sig->digest_start[1] );
if( is_v4 ) {
- parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_LIST_HASHED, NULL );
- parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL);
+ parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL );
+ parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
}
}
@@ -1206,6 +1329,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
mpi_print(stdout, sig->data[i], mpi_print_mode );
putchar('\n');
}
+ if (!sig->data[i])
+ rc = G10ERR_INVALID_PACKET;
}
}
@@ -1220,14 +1345,17 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
PKT_onepass_sig *ops )
{
int version;
+ int rc = 0;
if( pktlen < 13 ) {
log_error("packet(%d) too short\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
version = iobuf_get_noeof(inp); pktlen--;
if( version != 3 ) {
log_error("onepass_sig with unknown version %d\n", version);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
ops->sig_class = iobuf_get_noeof(inp); pktlen--;
@@ -1246,7 +1374,7 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen,
leave:
skip_rest(inp, pktlen);
- return 0;
+ return rc;
}
@@ -1258,14 +1386,14 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
{
int i, version, algorithm;
unsigned n;
- unsigned long timestamp, expiredate;
+ unsigned long timestamp, expiredate, max_expiredate;
int npkey, nskey;
int is_v4=0;
int rc=0;
version = iobuf_get_noeof(inp); pktlen--;
if( pkttype == PKT_PUBLIC_SUBKEY && version == '#' ) {
- /* early versions of gpg use old PGP comments packets;
+ /* early versions of G10 use old PGP comments packets;
* luckily all those comments are started by a hash */
if( list_mode ) {
printf(":rfc1991 comment packet: \"" );
@@ -1286,17 +1414,21 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
is_v4=1;
else if( version != 2 && version != 3 ) {
log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( pktlen < 11 ) {
log_error("packet(%d) too short\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
timestamp = read_32(inp); pktlen -= 4;
- if( is_v4 )
+ if( is_v4 ) {
expiredate = 0; /* have to get it from the selfsignature */
+ max_expiredate = 0;
+ }
else {
unsigned short ndays;
ndays = read_16(inp); pktlen -= 2;
@@ -1304,6 +1436,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
expiredate = timestamp + ndays * 86400L;
else
expiredate = 0;
+
+ max_expiredate=expiredate;
}
algorithm = iobuf_get_noeof(inp); pktlen--;
if( list_mode )
@@ -1320,23 +1454,25 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
sk->timestamp = timestamp;
sk->expiredate = expiredate;
+ sk->max_expiredate = max_expiredate;
sk->hdrbytes = hdrlen;
sk->version = version;
sk->is_primary = pkttype == PKT_SECRET_KEY;
sk->pubkey_algo = algorithm;
sk->req_usage = 0;
- sk->pubkey_usage = 0; /* will be set by getkey functions */
+ sk->pubkey_usage = 0; /* not yet used */
}
else {
PKT_public_key *pk = pkt->pkt.public_key;
pk->timestamp = timestamp;
pk->expiredate = expiredate;
+ pk->max_expiredate = max_expiredate;
pk->hdrbytes = hdrlen;
pk->version = version;
pk->pubkey_algo = algorithm;
- pk->req_usage = 0;
- pk->pubkey_usage = 0; /* will be set bey getkey functions */
+ pk->req_usage = 0;
+ pk->pubkey_usage = 0; /* not yet used */
pk->is_revoked = 0;
pk->keyid[0] = 0;
pk->keyid[1] = 0;
@@ -1355,8 +1491,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
byte temp[16];
if( !npkey ) {
- sk->skey[0] = gcry_mpi_set_opaque( NULL,
- read_rest(inp, pktlen), pktlen*8 );
+ sk->skey[0] = mpi_set_opaque( NULL,
+ read_rest(inp, pktlen), pktlen );
pktlen = 0;
goto leave;
}
@@ -1368,16 +1504,22 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
mpi_print(stdout, sk->skey[i], mpi_print_mode );
putchar('\n');
}
+ if (!sk->skey[i])
+ rc = G10ERR_INVALID_PACKET;
}
+ if (rc) /* one of the MPIs were bad */
+ goto leave;
sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
+ sk->protect.sha1chk = 0;
if( sk->protect.algo ) {
sk->is_protected = 1;
sk->protect.s2k.count = 0;
- if( sk->protect.algo == 255 ) {
+ if( sk->protect.algo == 254 || sk->protect.algo == 255 ) {
if( pktlen < 3 ) {
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
+ sk->protect.sha1chk = (sk->protect.algo == 254);
sk->protect.algo = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--;
sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
@@ -1389,7 +1531,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
if( list_mode )
printf( "\tunknown S2K %d\n",
sk->protect.s2k.mode );
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
/* here we know that it is a gnu extension
@@ -1421,13 +1563,15 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
printf( "\tunknown %sS2K %d\n",
sk->protect.s2k.mode < 1000? "":"GNU ",
sk->protect.s2k.mode );
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
if( list_mode ) {
- printf(", algo: %d, hash: %d",
+ printf(", algo: %d,%s hash: %d",
sk->protect.algo,
+ sk->protect.sha1chk?" SHA1 protection,"
+ :" simple checksum,",
sk->protect.s2k.hash_algo );
if( sk->protect.s2k.mode == 1
|| sk->protect.s2k.mode == 3 ) {
@@ -1440,7 +1584,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
if( sk->protect.s2k.mode == 3 ) {
if( pktlen < 1 ) {
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
sk->protect.s2k.count = iobuf_get(inp);
@@ -1452,7 +1596,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
}
else { /* old version; no S2K, so we set mode to 0, hash MD5 */
sk->protect.s2k.mode = 0;
- sk->protect.s2k.hash_algo = GCRY_MD_MD5;
+ sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5;
if( list_mode )
printf( "\tprotect algo: %d (hash algo: %d)\n",
sk->protect.algo, sk->protect.s2k.hash_algo );
@@ -1477,7 +1621,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
sk->protect.ivlen = 0;
if( pktlen < sk->protect.ivlen ) {
- rc = GPGERR_INVALID_PACKET;
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
@@ -1498,26 +1642,25 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
* So we put the key into secure memory when we unprotect it. */
if( sk->protect.s2k.mode == 1001 ) {
/* better set some dummy stuff here */
- sk->skey[npkey] = mpi_set_opaque(NULL, gcry_xstrdup("dummydata"), 10);
+ sk->skey[npkey] = mpi_set_opaque(NULL, m_strdup("dummydata"), 10);
pktlen = 0;
}
else if( is_v4 && sk->is_protected ) {
/* ugly; the length is encrypted too, so we read all
* stuff up to the end of the packet into the first
* skey element */
- sk->skey[npkey] = gcry_mpi_set_opaque(NULL,
- read_rest(inp, pktlen), pktlen*8 );
+ sk->skey[npkey] = mpi_set_opaque(NULL,
+ read_rest(inp, pktlen), pktlen );
pktlen = 0;
if( list_mode ) {
printf("\tencrypted stuff follows\n");
}
}
- else { /* unencrypted v4 or v3 method (where length is not encrypted) */
+ else { /* v3 method: the mpi length is not encrypted */
for(i=npkey; i < nskey; i++ ) {
- n = pktlen;
- sk->skey[i] = sk->is_protected ? mpi_read_opaque(inp, &n )
- : mpi_read( inp, &n, 1 );
- pktlen -=n;
+ n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
+ if( sk->is_protected && sk->skey[i] )
+ mpi_set_protect_flag(sk->skey[i]);
if( list_mode ) {
printf( "\tskey[%d]: ", i);
if( sk->is_protected )
@@ -1527,7 +1670,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
putchar('\n');
}
}
+ if (!sk->skey[i])
+ rc = G10ERR_INVALID_PACKET;
}
+ if (rc)
+ goto leave;
sk->csum = read_16(inp); pktlen -= 2;
if( list_mode ) {
@@ -1539,8 +1686,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
PKT_public_key *pk = pkt->pkt.public_key;
if( !npkey ) {
- pk->pkey[0] = gcry_mpi_set_opaque( NULL,
- read_rest(inp, pktlen), pktlen*8 );
+ pk->pkey[0] = mpi_set_opaque( NULL,
+ read_rest(inp, pktlen), pktlen );
pktlen = 0;
goto leave;
}
@@ -1552,7 +1699,11 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
mpi_print(stdout, pk->pkey[i], mpi_print_mode );
putchar('\n');
}
+ if (!pk->pkey[i])
+ rc = G10ERR_INVALID_PACKET;
}
+ if (rc)
+ goto leave;
}
leave:
@@ -1560,16 +1711,95 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
return rc;
}
+/* Attribute subpackets have the same format as v4 signature
+ subpackets. This is not part of OpenPGP, but is done in several
+ versions of PGP nevertheless. */
+int
+parse_attribute_subpkts(PKT_user_id *uid)
+{
+ size_t n;
+ int count=0;
+ struct user_attribute *attribs=NULL;
+ const byte *buffer=uid->attrib_data;
+ int buflen=uid->attrib_len;
+ byte type;
+
+ m_free(uid->attribs);
+
+ while(buflen)
+ {
+ n = *buffer++; buflen--;
+ if( n == 255 ) { /* 4 byte length header */
+ if( buflen < 4 )
+ goto too_short;
+ n = (buffer[0] << 24) | (buffer[1] << 16)
+ | (buffer[2] << 8) | buffer[3];
+ buffer += 4;
+ buflen -= 4;
+ }
+ else if( n >= 192 ) { /* 2 byte special encoded length header */
+ if( buflen < 2 )
+ goto too_short;
+ n = (( n - 192 ) << 8) + *buffer + 192;
+ buffer++;
+ buflen--;
+ }
+ if( buflen < n )
+ goto too_short;
+
+ attribs=m_realloc(attribs,(count+1)*sizeof(struct user_attribute));
+ memset(&attribs[count],0,sizeof(struct user_attribute));
+
+ type=*buffer;
+ buffer++;
+ buflen--;
+ n--;
+
+ attribs[count].type=type;
+ attribs[count].data=buffer;
+ attribs[count].len=n;
+ buffer+=n;
+ buflen-=n;
+ count++;
+ }
+
+ uid->attribs=attribs;
+ uid->numattribs=count;
+ return count;
+
+ too_short:
+ log_error("buffer shorter than attribute subpacket\n");
+ uid->attribs=attribs;
+ uid->numattribs=count;
+ return count;
+}
+
+static void setup_user_id(PACKET *packet)
+{
+ packet->pkt.user_id->ref = 1;
+ packet->pkt.user_id->attribs = NULL;
+ packet->pkt.user_id->attrib_data = NULL;
+ packet->pkt.user_id->attrib_len = 0;
+ packet->pkt.user_id->is_primary = 0;
+ packet->pkt.user_id->is_revoked = 0;
+ packet->pkt.user_id->is_expired = 0;
+ packet->pkt.user_id->expiredate = 0;
+ packet->pkt.user_id->created = 0;
+ packet->pkt.user_id->help_key_usage = 0;
+ packet->pkt.user_id->help_key_expire = 0;
+ packet->pkt.user_id->prefs = NULL;
+}
static int
parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{
byte *p;
- packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen);
+ packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen);
packet->pkt.user_id->len = pktlen;
- packet->pkt.user_id->photo = NULL;
- packet->pkt.user_id->photolen = 0;
+
+ setup_user_id(packet);
+
p = packet->pkt.user_id->name;
for( ; pktlen; pktlen--, p++ )
*p = iobuf_get_noeof(inp);
@@ -1578,7 +1808,7 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
if( list_mode ) {
int n = packet->pkt.user_id->len;
printf(":user ID packet: \"");
- /* fixme: Hey why don't we replace this wioth print_string?? */
+ /* fixme: Hey why don't we replace this with print_string?? */
for(p=packet->pkt.user_id->name; n; p++, n-- ) {
if( *p >= ' ' && *p <= 'z' )
putchar(*p);
@@ -1590,28 +1820,60 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
return 0;
}
+void
+make_attribute_uidname(PKT_user_id *uid)
+{
+ if(uid->numattribs<=0)
+ sprintf(uid->name,"[bad attribute packet of size %lu]",uid->attrib_len);
+ else if(uid->numattribs>1)
+ sprintf(uid->name,"[%d attributes of size %lu]",
+ uid->numattribs,uid->attrib_len);
+ else
+ {
+ /* Only one attribute, so list it as the "user id" */
+
+ if(uid->attribs->type==ATTRIB_IMAGE)
+ {
+ u32 len;
+ byte type;
+
+ if(parse_image_header(uid->attribs,&type,&len))
+ sprintf(uid->name,"[%s image of size %lu]",
+ image_type_to_string(type,1),(ulong)len);
+ else
+ sprintf(uid->name,"[invalid image]");
+ }
+ else
+ sprintf(uid->name,"[unknown attribute of size %lu]",uid->attribs->len);
+ }
+
+ uid->len = strlen(uid->name);
+}
-/****************
- * PGP generates a packet of type 17. We assume this is a photo ID and
- * simply store it here as a comment packet.
- */
static int
-parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
+parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{
byte *p;
- packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + 30);
- sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen );
- packet->pkt.user_id->len = strlen(packet->pkt.user_id->name);
+ packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + 70);
+
+ setup_user_id(packet);
- packet->pkt.user_id->photo = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen);
- packet->pkt.user_id->photolen = pktlen;
- p = packet->pkt.user_id->photo;
+ packet->pkt.user_id->attrib_data = m_alloc(pktlen);
+ packet->pkt.user_id->attrib_len = pktlen;
+ p = packet->pkt.user_id->attrib_data;
for( ; pktlen; pktlen--, p++ )
*p = iobuf_get_noeof(inp);
+ /* Now parse out the individual attribute subpackets. This is
+ somewhat pointless since there is only one currently defined
+ attribute type (jpeg), but it is correct by the spec. */
+ parse_attribute_subpkts(packet->pkt.user_id);
+
+ make_attribute_uidname(packet->pkt.user_id);
+
if( list_mode ) {
- printf(":photo_id packet: %s\n", packet->pkt.user_id->name );
+ printf(":attribute packet: %s\n", packet->pkt.user_id->name );
}
return 0;
}
@@ -1622,7 +1884,7 @@ parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{
byte *p;
- packet->pkt.comment = gcry_xmalloc(sizeof *packet->pkt.comment + pktlen - 1);
+ packet->pkt.comment = m_alloc(sizeof *packet->pkt.comment + pktlen - 1);
packet->pkt.comment->len = pktlen;
p = packet->pkt.comment->data;
for( ; pktlen; pktlen--, p++ )
@@ -1647,13 +1909,34 @@ parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
static void
parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
{
- int c;
-
- c = iobuf_get_noeof(inp);
- pkt->pkt.ring_trust = gcry_xmalloc( sizeof *pkt->pkt.ring_trust );
- pkt->pkt.ring_trust->trustval = c;
- if( list_mode )
- printf(":trust packet: flag=%02x\n", c );
+ int c;
+
+ if (pktlen)
+ {
+ c = iobuf_get_noeof(inp);
+ pktlen--;
+ pkt->pkt.ring_trust = m_alloc( sizeof *pkt->pkt.ring_trust );
+ pkt->pkt.ring_trust->trustval = c;
+ pkt->pkt.ring_trust->sigcache = 0;
+ if (!c && pktlen==1)
+ {
+ c = iobuf_get_noeof (inp);
+ pktlen--;
+ /* we require that bit 7 of the sigcache is 0 (easier eof handling)*/
+ if ( !(c & 0x80) )
+ pkt->pkt.ring_trust->sigcache = c;
+ }
+ if( list_mode )
+ printf(":trust packet: flag=%02x sigcache=%02x\n",
+ pkt->pkt.ring_trust->trustval,
+ pkt->pkt.ring_trust->sigcache);
+ }
+ else
+ {
+ if( list_mode )
+ printf(":trust packet: empty\n");
+ }
+ skip_rest (inp, pktlen);
}
@@ -1661,21 +1944,29 @@ static int
parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *pkt, int new_ctb )
{
- int mode, namelen;
+ int rc = 0;
+ int mode, namelen, partial=0;
PKT_plaintext *pt;
byte *p;
int c, i;
if( pktlen && pktlen < 6 ) {
log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
+ /* A packet length of zero indicates partial body length. A zero
+ data length isn't a zero length packet due to the header (mode,
+ name, etc), so this is accurate. */
+ if(pktlen==0)
+ partial=1;
mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
- pt = pkt->pkt.plaintext = gcry_xmalloc(sizeof *pkt->pkt.plaintext + namelen -1);
+ pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
pt->new_ctb = new_ctb;
pt->mode = mode;
pt->namelen = namelen;
+ pt->is_partial = partial;
if( pktlen ) {
for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
pt->name[i] = iobuf_get_noeof(inp);
@@ -1707,7 +1998,7 @@ parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
}
leave:
- return 0;
+ return rc;
}
@@ -1721,7 +2012,7 @@ parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
* (this should be the last object in a file or
* the compress algorithm should know the length)
*/
- zd = pkt->pkt.compressed = gcry_xmalloc(sizeof *pkt->pkt.compressed );
+ zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed );
zd->len = 0; /* not yet used */
zd->algorithm = iobuf_get_noeof(inp);
zd->new_ctb = new_ctb;
@@ -1736,10 +2027,18 @@ static int
parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *pkt, int new_ctb )
{
+ int rc = 0;
PKT_encrypted *ed;
+ unsigned long orig_pktlen = pktlen;
- ed = pkt->pkt.encrypted = gcry_xmalloc(sizeof *pkt->pkt.encrypted );
+ ed = pkt->pkt.encrypted = m_alloc(sizeof *pkt->pkt.encrypted );
ed->len = pktlen;
+ /* we don't know the extralen which is (cipher_blocksize+2)
+ because the algorithm ist not specified in this packet.
+ However, it is only important to know this for somesanity
+ checks on the pkacet length - it doesn't matter that we can't
+ do it */
+ ed->extralen = 0;
ed->buf = NULL;
ed->new_ctb = new_ctb;
ed->mdc_method = 0;
@@ -1747,22 +2046,27 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
/* fixme: add some pktlen sanity checks */
int version;
- version = iobuf_get_noeof(inp); pktlen--;
+ version = iobuf_get_noeof(inp);
+ if (orig_pktlen)
+ pktlen--;
if( version != 1 ) {
log_error("encrypted_mdc packet with unknown version %d\n",
version);
+ /*skip_rest(inp, pktlen); should we really do this? */
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
- ed->mdc_method = GCRY_MD_SHA1;
+ ed->mdc_method = DIGEST_ALGO_SHA1;
}
- if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
+ if( orig_pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */
log_error("packet(%d) too short\n", pkttype);
+ rc = G10ERR_INVALID_PACKET;
skip_rest(inp, pktlen);
goto leave;
}
if( list_mode ) {
- if( pktlen )
- printf(":encrypted data packet:\n\tlength: %lu\n", pktlen);
+ if( orig_pktlen )
+ printf(":encrypted data packet:\n\tlength: %lu\n", orig_pktlen);
else
printf(":encrypted data packet:\n\tlength: unknown\n");
if( ed->mdc_method )
@@ -1773,7 +2077,7 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
pktlen = 0;
leave:
- return 0;
+ return rc;
}
@@ -1781,14 +2085,16 @@ static int
parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *pkt, int new_ctb )
{
+ int rc = 0;
PKT_mdc *mdc;
byte *p;
- mdc = pkt->pkt.mdc= gcry_xmalloc(sizeof *pkt->pkt.mdc );
+ mdc = pkt->pkt.mdc= m_alloc(sizeof *pkt->pkt.mdc );
if( list_mode )
printf(":mdc packet: length=%lu\n", pktlen);
if( !new_ctb || pktlen != 20 ) {
log_error("mdc_packet with invalid encoding\n");
+ rc = G10ERR_INVALID_PACKET;
goto leave;
}
p = mdc->hash;
@@ -1796,6 +2102,90 @@ parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen,
*p = iobuf_get_noeof(inp);
leave:
+ return rc;
+}
+
+
+/*
+ * This packet is internally generated by PGG (by armor.c) to
+ * transfer some information to the lower layer. To make sure that
+ * this packet is really a GPG faked one and not one comming from outside,
+ * we first check that tehre is a unique tag in it.
+ * The format of such a control packet is:
+ * n byte session marker
+ * 1 byte control type CTRLPKT_xxxxx
+ * m byte control data
+ */
+
+static int
+parse_gpg_control( IOBUF inp,
+ int pkttype, unsigned long pktlen, PACKET *packet )
+{
+ byte *p;
+ const byte *sesmark;
+ size_t sesmarklen;
+ int i;
+
+ if ( list_mode )
+ printf(":packet 63: length %lu ", pktlen);
+
+ sesmark = get_session_marker ( &sesmarklen );
+ if ( pktlen < sesmarklen+1 ) /* 1 is for the control bytes */
+ goto skipit;
+ for( i=0; i < sesmarklen; i++, pktlen-- ) {
+ if ( sesmark[i] != iobuf_get_noeof(inp) )
+ goto skipit;
+ }
+ if ( list_mode )
+ puts ("- gpg control packet");
+
+ packet->pkt.gpg_control = m_alloc(sizeof *packet->pkt.gpg_control
+ + pktlen - 1);
+ packet->pkt.gpg_control->control = iobuf_get_noeof(inp); pktlen--;
+ packet->pkt.gpg_control->datalen = pktlen;
+ p = packet->pkt.gpg_control->data;
+ for( ; pktlen; pktlen--, p++ )
+ *p = iobuf_get_noeof(inp);
+
return 0;
+
+ skipit:
+ if ( list_mode ) {
+ int c;
+
+ i=0;
+ printf("- private (rest length %lu)\n", pktlen);
+ if( iobuf_in_block_mode(inp) ) {
+ while( (c=iobuf_get(inp)) != -1 )
+ dump_hex_line(c, &i);
+ }
+ else {
+ for( ; pktlen; pktlen-- )
+ dump_hex_line(iobuf_get(inp), &i);
+ }
+ putchar('\n');
+ }
+ skip_rest(inp,pktlen);
+ return G10ERR_INVALID_PACKET;
}
+/* create a gpg control packet to be used internally as a placeholder */
+PACKET *
+create_gpg_control( ctrlpkttype_t type, const byte *data, size_t datalen )
+{
+ PACKET *packet;
+ byte *p;
+
+ packet = m_alloc( sizeof *packet );
+ init_packet(packet);
+ packet->pkttype = PKT_GPG_CONTROL;
+ packet->pkt.gpg_control = m_alloc(sizeof *packet->pkt.gpg_control
+ + datalen - 1);
+ packet->pkt.gpg_control->control = type;
+ packet->pkt.gpg_control->datalen = datalen;
+ p = packet->pkt.gpg_control->data;
+ for( ; datalen; datalen--, p++ )
+ *p = *data++;
+
+ return packet;
+}
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 6b06df72e..c8ebad620 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -1,5 +1,5 @@
/* passphrase.c - Get a passphrase
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -19,26 +19,60 @@
*/
#include <config.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
+#if !defined(HAVE_DOSISH_SYSTEM) && !defined(__riscos__)
#include <sys/socket.h>
#include <sys/un.h>
-#include <unistd.h>
+#endif
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+# include <windows.h>
+#endif
#include <errno.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "options.h"
#include "ttyio.h"
+#include "cipher.h"
#include "keydb.h"
#include "main.h"
#include "i18n.h"
#include "status.h"
-#include "gpga-prot.h"
+
+
+enum gpga_protocol_codes {
+ /* Request codes */
+ GPGA_PROT_GET_VERSION = 1,
+ GPGA_PROT_GET_PASSPHRASE = 2,
+ GPGA_PROT_CLEAR_PASSPHRASE= 3,
+ GPGA_PROT_SHUTDOWN = 4,
+ GPGA_PROT_FLUSH = 5,
+
+ /* Reply codes */
+ GPGA_PROT_REPLY_BASE = 0x10000,
+ GPGA_PROT_OKAY = 0x10001,
+ GPGA_PROT_GOT_PASSPHRASE = 0x10002,
+
+ /* Error codes */
+ GPGA_PROT_ERROR_BASE = 0x20000,
+ GPGA_PROT_PROTOCOL_ERROR = 0x20001,
+ GPGA_PROT_INVALID_REQUEST= 0x20002,
+ GPGA_PROT_CANCELED = 0x20003,
+ GPGA_PROT_NO_PASSPHRASE = 0x20004,
+ GPGA_PROT_BAD_PASSPHRASE = 0x20005,
+ GPGA_PROT_INVALID_DATA = 0x20006,
+ GPGA_PROT_NOT_IMPLEMENTED= 0x20007,
+ GPGA_PROT_UI_PROBLEM = 0x20008
+};
+
#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
(*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
@@ -49,11 +83,25 @@
((byte*)p)[3] = (byte)((a) ); \
} while(0)
+#define digitp(p) (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a) \
+ || (*(a) >= 'A' && *(a) <= 'F') \
+ || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+
static char *fd_passwd = NULL;
static char *next_pw = NULL;
static char *last_pw = NULL;
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+static int read_fd = 0;
+static int write_fd = 0;
+#endif
+
static void hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create );
int
@@ -71,10 +119,10 @@ have_static_passphrase()
void
set_next_passphrase( const char *s )
{
- gcry_free(next_pw);
+ m_free(next_pw);
next_pw = NULL;
if( s ) {
- next_pw = gcry_xmalloc_secure( strlen(s)+1 );
+ next_pw = m_alloc_secure( strlen(s)+1 );
strcpy(next_pw, s );
}
}
@@ -101,7 +149,6 @@ read_passphrase_from_fd( int fd )
if ( opt.use_agent )
return; /* not used here */
-
if( !opt.batch )
tty_printf("Reading passphrase from file descriptor %d ...", fd );
@@ -109,7 +156,7 @@ read_passphrase_from_fd( int fd )
if( i >= len-1 ) {
char *pw2 = pw;
len += 100;
- pw = gcry_xmalloc_secure( len );
+ pw = m_alloc_secure( len );
if( pw2 )
memcpy(pw, pw2, i );
else
@@ -122,16 +169,33 @@ read_passphrase_from_fd( int fd )
if( !opt.batch )
tty_printf("\b\b\b \n" );
- gcry_free( fd_passwd );
+ m_free( fd_passwd );
fd_passwd = pw;
}
-
static int
writen ( int fd, const void *buf, size_t nbytes )
{
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ DWORD nwritten, nleft = nbytes;
+
+ while (nleft > 0) {
+ if ( !WriteFile( (HANDLE)write_fd, buf, nleft, &nwritten, NULL) ) {
+ log_error("write failed: ec=%d\n", (int)GetLastError());
+ return -1;
+ }
+ /*log_info("** WriteFile fd=%d nytes=%d nwritten=%d\n",
+ write_fd, nbytes, (int)nwritten);*/
+ Sleep(100);
+
+ nleft -= nwritten;
+ buf = (const BYTE *)buf + nwritten;
+ }
+#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ /* not implemented */
+#else
size_t nleft = nbytes;
- ssize_t nwritten;
+ int nwritten;
while( nleft > 0 ) {
nwritten = write( fd, buf, nleft );
@@ -139,13 +203,15 @@ writen ( int fd, const void *buf, size_t nbytes )
if ( errno == EINTR )
nwritten = 0;
else {
- log_error ( "writen() failed: %s\n", strerror (errno) );
+ log_error ( "write() failed: %s\n", strerror (errno) );
return -1;
}
}
nleft -= nwritten;
buf = (const char*)buf + nwritten;
}
+#endif
+
return 0;
}
@@ -153,6 +219,29 @@ writen ( int fd, const void *buf, size_t nbytes )
static int
readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
{
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ DWORD nread, nleft = buflen;
+
+ while (nleft > 0) {
+ if ( !ReadFile( (HANDLE)read_fd, buf, nleft, &nread, NULL) ) {
+ log_error("read() error: ec=%d\n", (int)GetLastError());
+ return -1;
+ }
+ if (!nread || GetLastError() == ERROR_BROKEN_PIPE)
+ break;
+ /*log_info("** ReadFile fd=%d buflen=%d nread=%d\n",
+ read_fd, buflen, (int)nread);*/
+ Sleep(100);
+
+ nleft -= nread;
+ buf = (BYTE *)buf + nread;
+ }
+ if (ret_nread)
+ *ret_nread = buflen - nleft;
+
+#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ /* not implemented */
+#else
size_t nleft = buflen;
int nread;
char *p;
@@ -175,9 +264,161 @@ readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
}
if( ret_nread )
*ret_nread = buflen - nleft;
+#endif
+
return 0;
}
+/* read an entire line */
+static int
+readline (int fd, char *buf, size_t buflen)
+{
+ size_t nleft = buflen;
+ char *p;
+ int nread = 0;
+
+ while (nleft > 0)
+ {
+ int n = read (fd, buf, nleft);
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1; /* read error */
+ }
+ else if (!n)
+ {
+ return -1; /* incomplete line */
+ }
+ p = buf;
+ nleft -= n;
+ buf += n;
+ nread += n;
+
+ for (; n && *p != '\n'; n--, p++)
+ ;
+ if (n)
+ {
+ break; /* at least one full line available - that's enough.
+ This function is just a temporary hack until we use
+ the assuna lib in gpg. So it is okay to forget
+ about pending bytes */
+ }
+ }
+
+ return nread;
+}
+
+
+
+#if !defined (__riscos__)
+
+#if !defined (__MINGW32__) && !defined (__CYGWIN32__)
+/* For the new Assuan protocol we may have to send options */
+static int
+agent_send_option (int fd, const char *name, const char *value)
+{
+ char buf[200];
+ int nread;
+ char *line;
+ int i;
+
+ line = m_alloc (7 + strlen (name) + 1 + strlen (value) + 2);
+ strcpy (stpcpy (stpcpy (stpcpy (
+ stpcpy (line, "OPTION "), name), "="), value), "\n");
+ i = writen (fd, line, strlen (line));
+ m_free (line);
+ if (i)
+ return -1;
+
+ /* get response */
+ nread = readline (fd, buf, DIM(buf)-1);
+ if (nread < 3)
+ return -1;
+
+ if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
+ return 0; /* okay */
+
+ return -1;
+}
+
+static int
+agent_send_all_options (int fd)
+{
+ char *dft_display = NULL;
+ char *dft_ttyname = NULL;
+ char *dft_ttytype = NULL;
+ char *old_lc = NULL;
+ char *dft_lc = NULL;
+ int rc = 0;
+
+ dft_display = getenv ("DISPLAY");
+ if (opt.display || dft_display)
+ {
+ if (agent_send_option (fd, "display",
+ opt.display ? opt.display : dft_display))
+ return -1;
+ }
+
+ if (!opt.ttyname && ttyname (1))
+ dft_ttyname = ttyname (1);
+ if (opt.ttyname || dft_ttyname)
+ {
+ if (agent_send_option (fd, "ttyname",
+ opt.ttyname ? opt.ttyname : dft_ttyname))
+ return -1;
+ }
+
+ dft_ttytype = getenv ("TERM");
+ if (opt.ttytype || (dft_ttyname && dft_ttytype))
+ {
+ if (agent_send_option (fd, "ttytype",
+ opt.ttyname ? opt.ttytype : dft_ttytype))
+ return -1;
+ }
+
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+ old_lc = setlocale (LC_CTYPE, NULL);
+ if (old_lc)
+ old_lc = m_strdup (old_lc);
+ dft_lc = setlocale (LC_CTYPE, "");
+#endif
+ if (opt.lc_ctype || (dft_ttyname && dft_lc))
+ {
+ rc = agent_send_option (fd, "lc-ctype",
+ opt.lc_ctype ? opt.lc_ctype : dft_lc);
+ }
+#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
+ if (old_lc)
+ {
+ setlocale (LC_CTYPE, old_lc);
+ m_free (old_lc);
+ }
+#endif
+ if (rc)
+ return rc;
+
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+ old_lc = setlocale (LC_MESSAGES, NULL);
+ if (old_lc)
+ old_lc = m_strdup (old_lc);
+ dft_lc = setlocale (LC_MESSAGES, "");
+#endif
+ if (opt.lc_messages || (dft_ttyname && dft_lc))
+ {
+ rc = agent_send_option (fd, "lc-messages",
+ opt.lc_messages ? opt.lc_messages : dft_lc);
+ }
+#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
+ if (old_lc)
+ {
+ setlocale (LC_MESSAGES, old_lc);
+ m_free (old_lc);
+ }
+#endif
+ return rc;
+}
+#endif /*!__MINGW32__ && !__CYGWIN32__*/
/*
@@ -186,33 +427,101 @@ readn ( int fd, void *buf, size_t buflen, size_t *ret_nread )
*/
static int
-agent_open ()
+agent_open (int *ret_prot)
{
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ int fd;
+ char *infostr, *p;
+ HANDLE h;
+ char pidstr[128];
+
+ *ret_prot = 0;
+ if ( !(infostr = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
+ "agentPID"))
+ || *infostr == '0') {
+ log_error( _("gpg-agent is not available in this session\n"));
+ return -1;
+ }
+ free(infostr);
+
+ sprintf(pidstr, "%u", (unsigned int)GetCurrentProcessId());
+ if (write_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
+ "agentCID", pidstr)) {
+ log_error( _("can't set client pid for the agent\n") );
+ return -1;
+ }
+ h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
+ SetEvent(h);
+ Sleep(50); /* some time for the server */
+ if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
+ "agentReadFD")) ) {
+ log_error( _("can't get server read FD for the agent\n") );
+ return -1;
+ }
+ read_fd = atol(p);
+ free(p);
+ if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
+ "agentWriteFD")) ) {
+ log_error ( _("can't get server write FD for the agent\n") );
+ return -1;
+ }
+ write_fd = atol(p);
+ free(p);
+ fd = 0;
+
+ if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
+ fd = -1;
+ }
+#else /* Posix */
+
int fd;
char *infostr, *p;
struct sockaddr_un client_addr;
size_t len;
+ int prot;
+
+ if (opt.gpg_agent_info)
+ infostr = m_strdup (opt.gpg_agent_info);
+ else
+ {
+ infostr = getenv ( "GPG_AGENT_INFO" );
+ if ( !infostr ) {
+ log_error (_("gpg-agent is not available in this session\n"));
+ opt.use_agent = 0;
+ return -1;
+ }
+ infostr = m_strdup ( infostr );
+ }
- infostr = getenv ( "GPG_AGENT_INFO" );
- if ( !infostr ) {
- log_error (_("gpg-agent is not available in this session\n"));
- return -1;
- }
- infostr = gcry_xstrdup ( infostr );
if ( !(p = strchr ( infostr, ':')) || p == infostr
|| (p-infostr)+1 >= sizeof client_addr.sun_path ) {
- log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
- gcry_free (infostr );
+ log_error( _("malformed GPG_AGENT_INFO environment variable\n"));
+ m_free (infostr );
+ opt.use_agent = 0;
return -1;
}
- *p = 0;
-
+ *p++ = 0;
+ /* See whether this is the new gpg-agent using the Assuna protocl.
+ This agent identifies itself by have an info string with a
+ version number in the 3rd field. */
+ while (*p && *p != ':')
+ p++;
+ prot = *p? atoi (p+1) : 0;
+ if ( prot < 0 || prot > 1) {
+ log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
+ m_free (infostr );
+ opt.use_agent = 0;
+ return -1;
+ }
+ *ret_prot = prot;
+
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) {
log_error ("can't create socket: %s\n", strerror(errno) );
- gcry_free (infostr );
+ m_free (infostr );
+ opt.use_agent = 0;
return -1;
}
-
+
memset( &client_addr, 0, sizeof client_addr );
client_addr.sun_family = AF_UNIX;
strcpy( client_addr.sun_path, infostr );
@@ -222,24 +531,57 @@ agent_open ()
if( connect( fd, (struct sockaddr*)&client_addr, len ) == -1 ) {
log_error ( _("can't connect to `%s': %s\n"),
infostr, strerror (errno) );
- gcry_free (infostr );
+ m_free (infostr );
close (fd );
+ opt.use_agent = 0;
return -1;
}
- gcry_free (infostr);
+ m_free (infostr);
- if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
+ if (!prot) {
+ if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
+ close (fd);
+ fd = -1;
+ }
+ }
+ else { /* assuan based gpg-agent */
+ char line[200];
+ int nread;
+
+ nread = readline (fd, line, DIM(line));
+ if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
+ && (line[2] == '\n' || line[2] == ' ')) ) {
+ log_error ( _("communication problem with gpg-agent\n"));
+ close (fd );
+ opt.use_agent = 0;
+ return -1;
+ }
+
+ if (agent_send_all_options (fd)) {
+ log_error (_("problem with the agent - disabling agent use\n"));
close (fd);
- fd = -1;
+ opt.use_agent = 0;
+ return -1;
+ }
+
}
+#endif
+
return fd;
}
+
static void
agent_close ( int fd )
{
+#if defined (__MINGW32__) || defined (__CYGWIN32__)
+ HANDLE h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
+ ResetEvent(h);
+#else
close (fd);
+#endif
}
+#endif /* !__riscos__ */
@@ -250,210 +592,345 @@ agent_close ( int fd )
* 2: Ditto, but change the text to "repeat entry"
*/
static char *
-agent_get_passphrase ( u32 *keyid, int mode )
+agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text )
{
- size_t n;
- char *atext;
- char buf[50];
- int fd = -1;
- int nread;
- u32 reply;
- char *pw = NULL;
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- byte fpr[MAX_FINGERPRINT_LEN];
+#if defined(__riscos__)
+ return NULL;
+#else
+ size_t n;
+ char *atext;
+ char buf[50];
+ int fd = -1;
+ int nread;
+ u32 reply;
+ char *pw = NULL;
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+ byte fpr[MAX_FINGERPRINT_LEN];
+ int prot;
#if MAX_FINGERPRINT_LEN < 20
- #error agent needs a 20 byte fingerprint
+#error agent needs a 20 byte fingerprint
#endif
- memset (fpr, 0, MAX_FINGERPRINT_LEN );
- if( keyid && get_pubkey( pk, keyid ) )
- pk = NULL; /* oops: no key for some reason */
-
- if ( !mode && pk ) {
- char *uid;
- size_t uidlen;
- const char *algo_name = gcry_pk_algo_name( pk->pubkey_algo );
- const char *timestr;
- char *maink;
- const char *fmtstr;
-
- if ( !algo_name )
- algo_name = "?";
-
- fmtstr = _(" (main key ID %08lX)");
- maink = gcry_xmalloc ( strlen (fmtstr) + 20 );
- if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
- && keyid[1] != keyid[3] )
- sprintf( maink, fmtstr, (ulong)keyid[3] );
- else
- *maink = 0;
-
- uid = get_user_id( keyid, &uidlen );
- timestr = strtimestamp (pk->timestamp);
- fmtstr = _("You need a passphrase to unlock the"
- " secret key for user:\n"
- "\"%.*s\"\n"
- "%u-bit %s key, ID %08lX, created %s%s\n" );
- atext = gcry_xmalloc ( 100 + strlen (fmtstr)
- + uidlen + 15 + strlen(algo_name) + 8
- + strlen (timestr) + strlen (maink) );
- sprintf (atext, fmtstr,
- uidlen, uid,
- nbits_from_pk (pk), algo_name, (ulong)keyid[1], timestr,
- maink );
- gcry_free (uid);
- gcry_free (maink);
-
- {
- size_t dummy;
- fingerprint_from_pk( pk, fpr, &dummy );
- }
-
+ memset (fpr, 0, MAX_FINGERPRINT_LEN );
+ if( keyid && get_pubkey( pk, keyid ) )
+ pk = NULL; /* oops: no key for some reason */
+
+ if ( !mode && pk )
+ {
+ char *uid;
+ size_t uidlen;
+ const char *algo_name = pubkey_algo_to_string ( pk->pubkey_algo );
+ const char *timestr;
+ char *maink;
+ const char *fmtstr;
+
+ if ( !algo_name )
+ algo_name = "?";
+
+ fmtstr = _(" (main key ID %08lX)");
+ maink = m_alloc ( strlen (fmtstr) + 20 );
+ if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
+ && keyid[1] != keyid[3] )
+ sprintf( maink, fmtstr, (ulong)keyid[3] );
+ else
+ *maink = 0;
+
+ uid = get_user_id( keyid, &uidlen );
+ timestr = strtimestamp (pk->timestamp);
+ fmtstr = _("You need a passphrase to unlock the"
+ " secret key for user:\n"
+ "\"%.*s\"\n"
+ "%u-bit %s key, ID %08lX, created %s%s\n" );
+ atext = m_alloc ( 100 + strlen (fmtstr)
+ + uidlen + 15 + strlen(algo_name) + 8
+ + strlen (timestr) + strlen (maink) );
+ sprintf (atext, fmtstr,
+ uidlen, uid,
+ nbits_from_pk (pk), algo_name, (ulong)keyid[1], timestr,
+ maink );
+ m_free (uid);
+ m_free (maink);
+
+ {
+ size_t dummy;
+ fingerprint_from_pk( pk, fpr, &dummy );
+ }
+
}
- else if (mode == 1 )
- atext = gcry_xstrdup ( _("Enter passphrase\n") );
- else
- atext = gcry_xstrdup ( _("Repeat passphrase\n") );
-
-
-
- if ( (fd = agent_open ()) == -1 )
+ else if (mode == 1 )
+ atext = m_strdup ( _("Enter passphrase\n") );
+ else
+ atext = m_strdup ( _("Repeat passphrase\n") );
+
+ if ( (fd = agent_open (&prot)) == -1 )
+ goto failure;
+
+ if (!prot)
+ { /* old style protocol */
+ n = 4 + 20 + strlen (atext);
+ u32tobuf (buf, n );
+ u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE );
+ memcpy (buf+8, fpr, 20 );
+ if ( writen ( fd, buf, 28 ) || writen ( fd, atext, strlen (atext) ) )
goto failure;
-
-
- n = 4 + 20 + strlen (atext);
- u32tobuf (buf, n );
- u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE );
- memcpy (buf+8, fpr, 20 );
- if ( writen ( fd, buf, 28 ) || writen ( fd, atext, strlen (atext) ) )
- goto failure;
- gcry_free (atext); atext = NULL;
-
- /* get response */
- if ( readn ( fd, buf, 12, &nread ) )
+ m_free (atext); atext = NULL;
+
+ /* get response */
+ if ( readn ( fd, buf, 12, &nread ) )
goto failure;
-
- if ( nread < 8 ) {
- log_error ( _("response from agent too short\n") );
- goto failure;
- }
- n = buftou32 ( buf );
- reply = buftou32 ( buf + 4 );
- if ( reply == GPGA_PROT_GOT_PASSPHRASE ) {
- size_t pwlen;
- size_t nn;
-
- if ( nread < 12 || n < 8 ) {
- log_error ( _("response from agent too short\n") );
- goto failure;
+
+ if ( nread < 8 )
+ {
+ log_error ( "response from agent too short\n" );
+ goto failure;
}
- pwlen = buftou32 ( buf + 8 );
- nread -= 12;
- n -= 8;
- if ( pwlen > n || n > 1000 ) {
- log_error (_("passphrase too long\n"));
- /* or protocol error */
- goto failure;
- }
- /* we read the whole block in one chunk to give no hints
- * on how long the passhrase actually is - this wastes some bytes
- * but because we already have this padding we should not loosen
- * the by issuing 2 read calls */
- pw = gcry_xmalloc_secure ( n+1 );
- if ( readn ( fd, pw, n, &nn ) )
+ n = buftou32 ( buf );
+ reply = buftou32 ( buf + 4 );
+ if ( reply == GPGA_PROT_GOT_PASSPHRASE )
+ {
+ size_t pwlen;
+ size_t nn;
+
+ if ( nread < 12 || n < 8 )
+ {
+ log_error ( "response from agent too short\n" );
+ goto failure;
+ }
+ pwlen = buftou32 ( buf + 8 );
+ nread -= 12;
+ n -= 8;
+ if ( pwlen > n || n > 1000 )
+ {
+ log_error (_("passphrase too long\n"));
+ /* or protocol error */
+ goto failure;
+ }
+ /* we read the whole block in one chunk to give no hints
+ * on how long the passhrase actually is - this wastes some bytes
+ * but because we already have this padding we should not loosen
+ * this by issuing 2 read calls */
+ pw = m_alloc_secure ( n+1 );
+ if ( readn ( fd, pw, n, &nn ) )
goto failure;
- if ( n != nn ) {
- log_error (_("invalid response from agent\n"));
- goto failure;
+ if ( n != nn )
+ {
+ log_error (_("invalid response from agent\n"));
+ goto failure;
+ }
+ pw[pwlen] = 0; /* make a C String */
+ agent_close (fd);
+ free_public_key( pk );
+ return pw;
}
- pw[pwlen] = 0; /* make a C String */
- agent_close (fd);
- free_public_key( pk );
- return pw;
- }
- else if ( reply == GPGA_PROT_CANCELED ) {
+ else if ( reply == GPGA_PROT_CANCELED )
log_info ( _("cancelled by user\n") );
- }
- else {
+ else
log_error ( _("problem with the agent: agent returns 0x%lx\n"),
- (ulong)reply );
+ (ulong)reply );
}
+ else
+ { /* The new Assuan protocol */
+ char *line, *p;
+ int i;
+
+ if (!tryagain_text)
+ tryagain_text = "X";
+
+ /* We allocate 2 time the needed space for atext so that there
+ is nenough space for escaping */
+ line = m_alloc (15 + 46
+ + 3*strlen (tryagain_text) + 3*strlen (atext) + 2);
+ strcpy (line, "GET_PASSPHRASE ");
+ p = line+15;
+ if (!mode)
+ {
+ for (i=0; i < 20; i++, p +=2 )
+ sprintf (p, "%02X", fpr[i]);
+ }
+ else
+ *p++ = 'X'; /* no caching */
+ *p++ = ' ';
+ for (i=0; tryagain_text[i]; i++)
+ {
+ if (tryagain_text[i] < ' ' || tryagain_text[i] == '+')
+ {
+ sprintf (p, "%%%02X", tryagain_text[i]);
+ p += 3;
+ }
+ else if (tryagain_text[i] == ' ')
+ *p++ = '+';
+ else
+ *p++ = tryagain_text[i];
+ }
+ *p++ = ' ';
+ *p++ = 'X'; /* Use the standard prompt */
+ *p++ = ' ';
+ /* copy description */
+ for (i=0; atext[i]; i++)
+ {
+ if (atext[i] < ' ' || atext[i] == '+')
+ {
+ sprintf (p, "%%%02X", atext[i]);
+ p += 3;
+ }
+ else if (atext[i] == ' ')
+ *p++ = '+';
+ else
+ *p++ = atext[i];
+ }
+ *p++ = '\n';
+ i = writen (fd, line, p - line);
+ m_free (line);
+ if (i)
+ goto failure;
+ m_free (atext); atext = NULL;
+
+ /* get response */
+ pw = m_alloc_secure (500);
+ nread = readline (fd, pw, 499);
+ if (nread < 3)
+ goto failure;
+
+ if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
+ { /* we got a passphrase - convert it back from hex */
+ size_t pwlen = 0;
+
+ for (i=3; i < nread && hexdigitp (pw+i); i+=2)
+ pw[pwlen++] = xtoi_2 (pw+i);
+ pw[pwlen] = 0; /* make a C String */
+ agent_close (fd);
+ free_public_key( pk );
+ return pw;
+ }
+ else if (nread > 7 && !memcmp (pw, "ERR 111", 7)
+ && (pw[7] == ' ' || pw[7] == '\n') )
+ log_info (_("cancelled by user\n") );
+ else
+ {
+ log_error (_("problem with the agent - disabling agent use\n"));
+ opt.use_agent = 0;
+ }
+ }
+
-
- failure:
- gcry_free (atext);
- if ( fd != -1 )
- agent_close (fd);
- gcry_free (pw );
- free_public_key( pk );
-
- return NULL;
+ failure:
+ m_free (atext);
+ if ( fd != -1 )
+ agent_close (fd);
+ m_free (pw );
+ free_public_key( pk );
+
+ return NULL;
+#endif /* Posix or W32 */
}
-
/*
- * Reste the cached passphrase
+ * Clear the cached passphrase
*/
void
passphrase_clear_cache ( u32 *keyid, int algo )
{
- size_t n;
- char buf[50];
- int fd = -1;
- int nread;
- u32 reply;
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- byte fpr[MAX_FINGERPRINT_LEN];
-
+#if defined(__riscos__)
+ return ;
+#else
+ size_t n;
+ char buf[200];
+ int fd = -1;
+ size_t nread;
+ u32 reply;
+ PKT_public_key *pk;
+ byte fpr[MAX_FINGERPRINT_LEN];
+ int prot;
+
#if MAX_FINGERPRINT_LEN < 20
#error agent needs a 20 byte fingerprint
#endif
- memset (fpr, 0, MAX_FINGERPRINT_LEN );
- if( !keyid || get_pubkey( pk, keyid ) ) {
- log_debug ("oops, no key in passphrase_clear_cache\n");
- goto failure; /* oops: no key for some reason */
- }
-
+ if (!opt.use_agent)
+ return;
+
+ pk = m_alloc_clear ( sizeof *pk );
+ memset (fpr, 0, MAX_FINGERPRINT_LEN );
+ if( !keyid || get_pubkey( pk, keyid ) )
{
- size_t dummy;
- fingerprint_from_pk( pk, fpr, &dummy );
+ log_debug ("oops, no key in passphrase_clear_cache\n");
+ goto failure; /* oops: no key for some reason */
}
+
+ {
+ size_t dummy;
+ fingerprint_from_pk( pk, fpr, &dummy );
+ }
- if ( (fd = agent_open ()) == -1 )
+ if ( (fd = agent_open (&prot)) == -1 )
+ goto failure;
+
+ if (!prot)
+ {
+ n = 4 + 20;
+ u32tobuf (buf, n );
+ u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE );
+ memcpy (buf+8, fpr, 20 );
+ if ( writen ( fd, buf, 28 ) )
goto failure;
-
- n = 4 + 20;
- u32tobuf (buf, n );
- u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE );
- memcpy (buf+8, fpr, 20 );
- if ( writen ( fd, buf, 28 ) )
+
+ /* get response */
+ if ( readn ( fd, buf, 8, &nread ) )
goto failure;
-
- /* get response */
- if ( readn ( fd, buf, 8, &nread ) )
- goto failure;
-
- if ( nread < 8 ) {
- log_error ( _("response from agent too short\n") );
+
+ if ( nread < 8 ) {
+ log_error ( "response from agent too short\n" );
goto failure;
+ }
+
+ reply = buftou32 ( buf + 4 );
+ if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE )
+ {
+ log_error ( _("problem with the agent: agent returns 0x%lx\n"),
+ (ulong)reply );
+ }
}
-
- reply = buftou32 ( buf + 4 );
- if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE ) {
- log_error ( _("problem with the agent: agent returns 0x%lx\n"),
- (ulong)reply );
+ else
+ { /* The assuan protocol */
+ char *line, *p;
+ int i;
+
+ line = m_alloc (17 + 40 + 2);
+ strcpy (line, "CLEAR_PASSPHRASE ");
+ p = line+17;
+ for (i=0; i < 20; i++, p +=2 )
+ sprintf (p, "%02X", fpr[i]);
+ *p++ = '\n';
+ i = writen (fd, line, p - line);
+ m_free (line);
+ if (i)
+ goto failure;
+
+ /* get response */
+ nread = readline (fd, buf, DIM(buf)-1);
+ if (nread < 3)
+ goto failure;
+
+ if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
+ ;
+ else
+ {
+ log_error (_("problem with the agent - disabling agent use\n"));
+ opt.use_agent = 0;
+ }
}
-
- failure:
- if ( fd != -1 )
- agent_close (fd);
- free_public_key( pk );
+ failure:
+ if (fd != -1)
+ agent_close (fd);
+ free_public_key( pk );
+#endif /* Posix or W32 */
}
+
+
/****************
* Get a passphrase for the secret key with KEYID, display TEXT
* if the user needs to enter the passphrase.
@@ -467,31 +944,49 @@ passphrase_clear_cache ( u32 *keyid, int algo )
*/
DEK *
passphrase_to_dek( u32 *keyid, int pubkey_algo,
- int cipher_algo, STRING2KEY *s2k, int mode )
+ int cipher_algo, STRING2KEY *s2k, int mode,
+ const char *tryagain_text)
{
char *pw = NULL;
DEK *dek;
STRING2KEY help_s2k;
if( !s2k ) {
+ /* This is used for the old rfc1991 mode
+ * Note: This must match the code in encode.c with opt.rfc1991 set */
+ int algo = opt.def_digest_algo ? opt.def_digest_algo
+ : opt.s2k_digest_algo;
+
s2k = &help_s2k;
s2k->mode = 0;
- /* this should be MD5 if cipher is IDEA, but because we do
- * not have IDEA, we use the default one, the user
- * can select it from the commandline
- */
- s2k->hash_algo = opt.def_digest_algo?opt.def_digest_algo
- :DEFAULT_DIGEST_ALGO;
+ s2k->hash_algo = algo;
}
if( !next_pw && is_status_enabled() ) {
char buf[50];
+
if( keyid ) {
- sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
- if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
- && keyid[1] != keyid[3] )
- sprintf( buf+strlen(buf), " %08lX%08lX %d 0",
- (ulong)keyid[2], (ulong)keyid[3], pubkey_algo );
+ u32 used_kid[2];
+ char *us;
+
+ if( keyid[2] && keyid[3] ) {
+ used_kid[0] = keyid[2];
+ used_kid[1] = keyid[3];
+ }
+ else {
+ used_kid[0] = keyid[0];
+ used_kid[1] = keyid[1];
+ }
+
+ us = get_long_user_id_string( keyid );
+ write_status_text( STATUS_USERID_HINT, us );
+ m_free(us);
+
+ sprintf( buf, "%08lX%08lX %08lX%08lX %d 0",
+ (ulong)keyid[0], (ulong)keyid[1],
+ (ulong)used_kid[0], (ulong)used_kid[1],
+ pubkey_algo );
+
write_status_text( STATUS_NEED_PASSPHRASE, buf );
}
else {
@@ -501,7 +996,7 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
}
if( keyid && !opt.batch && !next_pw ) {
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
size_t n;
char *p;
@@ -509,11 +1004,11 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
"user: \"") );
p = get_user_id( keyid, &n );
tty_print_utf8_string( p, n );
- gcry_free(p);
+ m_free(p);
tty_printf("\"\n");
if( !get_pubkey( pk, keyid ) ) {
- const char *s = gcry_pk_algo_name( pk->pubkey_algo );
+ const char *s = pubkey_algo_to_string( pk->pubkey_algo );
tty_printf( _("%u-bit %s key, ID %08lX, created %s"),
nbits_from_pk( pk ), s?s:"?", (ulong)keyid[1],
strtimestamp(pk->timestamp) );
@@ -527,33 +1022,46 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
free_public_key( pk );
}
+ agent_died:
if( next_pw ) {
pw = next_pw;
next_pw = NULL;
}
else if ( opt.use_agent ) {
- pw = agent_get_passphrase ( keyid, mode == 2? 1: 0 );
- if ( !pw )
- pw = gcry_xstrdup ("");
+ pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, tryagain_text );
+ if (!pw)
+ {
+ if (!opt.use_agent)
+ goto agent_died;
+ pw = m_strdup ("");
+ }
if( *pw && mode == 2 ) {
- char *pw2 = agent_get_passphrase ( keyid, 2 );
- if ( !pw2 )
- pw2 = gcry_xstrdup ("");
+ char *pw2 = agent_get_passphrase ( keyid, 2, NULL );
+ if (!pw2)
+ {
+ if (!opt.use_agent)
+ {
+ m_free (pw);
+ pw = NULL;
+ goto agent_died;
+ }
+ pw2 = m_strdup ("");
+ }
if( strcmp(pw, pw2) ) {
- gcry_free(pw2);
- gcry_free(pw);
+ m_free(pw2);
+ m_free(pw);
return NULL;
}
- gcry_free(pw2);
+ m_free(pw2);
}
}
else if( fd_passwd ) {
- pw = gcry_xmalloc_secure( strlen(fd_passwd)+1 );
+ pw = m_alloc_secure( strlen(fd_passwd)+1 );
strcpy( pw, fd_passwd );
}
else if( opt.batch ) {
log_error(_("can't query password in batchmode\n"));
- pw = gcry_xstrdup( "" ); /* return an empty passphrase */
+ pw = m_strdup( "" ); /* return an empty passphrase */
}
else {
pw = cpr_get_hidden("passphrase.enter", _("Enter passphrase: ") );
@@ -563,24 +1071,24 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
_("Repeat passphrase: ") );
tty_kill_prompt();
if( strcmp(pw, pw2) ) {
- gcry_free(pw2);
- gcry_free(pw);
+ m_free(pw2);
+ m_free(pw);
return NULL;
}
- gcry_free(pw2);
+ m_free(pw2);
}
}
if( !pw || !*pw )
write_status( STATUS_MISSING_PASSPHRASE );
- dek = gcry_xmalloc_secure( sizeof *dek );
+ dek = m_alloc_secure_clear ( sizeof *dek );
dek->algo = cipher_algo;
if( !*pw && mode == 2 )
dek->keylen = 0;
else
hash_passphrase( dek, pw, s2k, mode==2 );
- gcry_free(last_pw);
+ m_free(last_pw);
last_pw = pw;
return dek;
}
@@ -594,24 +1102,28 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
static void
hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create )
{
- GCRY_MD_HD md;
+ MD_HANDLE md;
int pass, i;
int used = 0;
int pwlen = strlen(pw);
assert( s2k->hash_algo );
- dek->keylen = gcry_cipher_get_algo_keylen( dek->algo );
+ dek->keylen = cipher_get_keylen( dek->algo ) / 8;
if( !(dek->keylen > 0 && dek->keylen <= DIM(dek->key)) )
BUG();
- if( !(md = gcry_md_open( s2k->hash_algo, GCRY_MD_FLAG_SECURE )) )
- BUG();
-
+ md = md_open( s2k->hash_algo, 1);
for(pass=0; used < dek->keylen ; pass++ ) {
if( pass ) {
- gcry_md_reset(md);
+ if( (opt.emulate_bugs & EMUBUG_3DESS2K)) {
+ int tmp = md->finalized;
+ md_reset( md );
+ md->finalized = tmp;
+ }
+ else
+ md_reset(md);
for(i=0; i < pass; i++ ) /* preset the hash context */
- gcry_md_putc(md, 0 );
+ md_putc(md, 0 );
}
if( s2k->mode == 1 || s2k->mode == 3 ) {
@@ -619,7 +1131,7 @@ hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create )
ulong count = len2;
if( create && !pass ) {
- gcry_randomize(s2k->salt, 8, GCRY_STRONG_RANDOM );
+ randomize_buffer(s2k->salt, 8, 1);
if( s2k->mode == 3 )
s2k->count = 96; /* 65536 iterations */
}
@@ -631,27 +1143,27 @@ hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create )
}
/* a little bit complicated because we need a ulong for count */
while( count > len2 ) { /* maybe iterated+salted */
- gcry_md_write( md, s2k->salt, 8 );
- gcry_md_write( md, pw, pwlen );
+ md_write( md, s2k->salt, 8 );
+ md_write( md, pw, pwlen );
count -= len2;
}
if( count < 8 )
- gcry_md_write( md, s2k->salt, count );
+ md_write( md, s2k->salt, count );
else {
- gcry_md_write( md, s2k->salt, 8 );
+ md_write( md, s2k->salt, 8 );
count -= 8;
- gcry_md_write( md, pw, count );
+ md_write( md, pw, count );
}
}
else
- gcry_md_write( md, pw, pwlen );
- gcry_md_final( md );
- i = gcry_md_get_algo_dlen( s2k->hash_algo );
+ md_write( md, pw, pwlen );
+ md_final( md );
+ i = md_digest_length( s2k->hash_algo );
if( i > dek->keylen - used )
i = dek->keylen - used;
- memcpy( dek->key+used, gcry_md_read(md, s2k->hash_algo), i );
+ memcpy( dek->key+used, md_read(md, s2k->hash_algo), i );
used += i;
}
- gcry_md_close(md);
+ md_close(md);
}
diff --git a/g10/photoid.c b/g10/photoid.c
new file mode 100644
index 000000000..66240ecc2
--- /dev/null
+++ b/g10/photoid.c
@@ -0,0 +1,320 @@
+/* photoid.c - photo ID handling code
+ * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_DOSISH_SYSTEM
+#include <windows.h>
+#endif
+#include "packet.h"
+#include "status.h"
+#include "exec.h"
+#include "keydb.h"
+#include "util.h"
+#include "i18n.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "options.h"
+#include "main.h"
+#include "photoid.h"
+
+/* Generate a new photo id packet, or return NULL if canceled */
+PKT_user_id *generate_photo_id(PKT_public_key *pk)
+{
+ PKT_user_id *uid;
+ int error=1,i;
+ unsigned int len;
+ char *filename=NULL;
+ byte *photo=NULL;
+ byte header[16];
+ IOBUF file;
+
+ header[0]=0x10; /* little side of photo header length */
+ header[1]=0; /* big side of photo header length */
+ header[2]=1; /* 1 == version of photo header */
+ header[3]=1; /* 1 == JPEG */
+
+ for(i=4;i<16;i++) /* The reserved bytes */
+ header[i]=0;
+
+ uid=m_alloc_clear(sizeof(*uid)+50);
+
+ printf(_("\nPick an image to use for your photo ID. "
+ "The image must be a JPEG file.\n"
+ "Remember that the image is stored within your public key. "
+ "If you use a\n"
+ "very large picture, your key will become very large as well!\n"
+ "Keeping the image close to 240x288 is a good size to use.\n"));
+
+ while(photo==NULL)
+ {
+ printf("\n");
+
+ m_free(filename);
+
+ filename=cpr_get("photoid.jpeg.add",
+ _("Enter JPEG filename for photo ID: "));
+
+ if(strlen(filename)==0)
+ goto scram;
+
+ file=iobuf_open(filename);
+ if(!file)
+ {
+ log_error(_("Unable to open photo \"%s\": %s\n"),
+ filename,strerror(errno));
+ continue;
+ }
+
+ len=iobuf_get_filelength(file);
+ if(len>6144)
+ {
+ printf("This JPEG is really large (%d bytes) !\n",len);
+ if(!cpr_get_answer_is_yes("photoid.jpeg.size",
+ _("Are you sure you want to use it (y/N)? ")))
+ {
+ iobuf_close(file);
+ continue;
+ }
+ }
+
+ photo=m_alloc(len);
+ iobuf_read(file,photo,len);
+ iobuf_close(file);
+
+ /* Is it a JPEG? */
+ if(photo[0]!=0xFF || photo[1]!=0xD8 ||
+ photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
+ {
+ log_error(_("\"%s\" is not a JPEG file\n"),filename);
+ m_free(photo);
+ photo=NULL;
+ continue;
+ }
+
+ /* Build the packet */
+ build_attribute_subpkt(uid,1,photo,len,header,16);
+ parse_attribute_subpkts(uid);
+ make_attribute_uidname(uid);
+
+ /* Showing the photo is not safe when noninteractive since the
+ "user" may not be able to dismiss a viewer window! */
+ if(opt.command_fd==-1)
+ {
+ show_photos(uid->attribs,uid->numattribs,pk,NULL);
+ switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
+ _("Is this photo correct (y/N/q)? ")))
+ {
+ case -1:
+ goto scram;
+ case 0:
+ free_attributes(uid);
+ m_free(photo);
+ photo=NULL;
+ continue;
+ }
+ }
+ }
+
+ error=0;
+ uid->ref=1;
+
+ scram:
+ m_free(filename);
+ m_free(photo);
+
+ if(error)
+ {
+ free_attributes(uid);
+ m_free(uid);
+ return NULL;
+ }
+
+ return uid;
+}
+
+/* Returns 0 for error, 1 for valid */
+int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
+{
+ int headerlen;
+
+ if(attr->len<3)
+ return 0;
+
+ /* For historical reasons (i.e. "oops!"), the header length is
+ little endian. */
+ headerlen=(attr->data[1]<<8) | attr->data[0];
+
+ if(headerlen>attr->len)
+ return 0;
+
+ if(type && attr->len>=4)
+ {
+ if(attr->data[2]==1) /* header version 1 */
+ *type=attr->data[3];
+ else
+ *type=0;
+ }
+
+ *len=attr->len-headerlen;
+
+ if(*len==0)
+ return 0;
+
+ return 1;
+}
+
+/* style==0 for extension, 1 for name, 2 for MIME type. Remember that
+ the "name" style string could be used in a user ID name field, so
+ make sure it is not too big (see
+ parse-packet.c:parse_attribute). */
+char *image_type_to_string(byte type,int style)
+{
+ char *string;
+
+ switch(type)
+ {
+ case 1: /* jpeg */
+ if(style==0)
+ string="jpg";
+ else if(style==1)
+ string="jpeg";
+ else
+ string="image/jpeg";
+ break;
+
+ default:
+ if(style==0)
+ string="bin";
+ else if(style==1)
+ string="unknown";
+ else
+ string="image/x-unknown";
+ break;
+ }
+
+ return string;
+}
+
+static const char *get_default_photo_command(void)
+{
+#if defined(HAVE_DOSISH_SYSTEM)
+ OSVERSIONINFO osvi;
+
+ memset(&osvi,0,sizeof(osvi));
+ osvi.dwOSVersionInfoSize=sizeof(osvi);
+ GetVersionEx(&osvi);
+
+ if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
+ return "start /w %i";
+ else
+ return "cmd /c start /w %i";
+#elif defined(__APPLE__)
+ /* OS X. This really needs more than just __APPLE__. */
+ return "open %I";
+#elif defined(__riscos__)
+ return "Filer_Run %I";
+#else
+ return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
+#endif
+}
+
+void show_photos(const struct user_attribute *attrs,
+ int count,PKT_public_key *pk,PKT_secret_key *sk)
+{
+ int i;
+ struct expando_args args;
+ u32 len;
+ u32 kid[2]={0,0};
+
+ memset(&args,0,sizeof(args));
+ args.pk=pk;
+ args.sk=sk;
+
+ if(pk)
+ keyid_from_pk(pk,kid);
+ else if(sk)
+ keyid_from_sk(sk,kid);
+
+ for(i=0;i<count;i++)
+ if(attrs[i].type==ATTRIB_IMAGE &&
+ parse_image_header(&attrs[i],&args.imagetype,&len))
+ {
+ char *command,*name;
+ struct exec_info *spawn;
+ int offset=attrs[i].len-len;
+
+ if(!opt.photo_viewer)
+ opt.photo_viewer=get_default_photo_command();
+
+ /* make command grow */
+ command=pct_expando(opt.photo_viewer,&args);
+ if(!command)
+ goto fail;
+
+ name=m_alloc(16+strlen(EXTSEP_S)+
+ strlen(image_type_to_string(args.imagetype,0))+1);
+
+ /* Make the filename. Notice we are not using the image
+ encoding type for more than cosmetics. Most external image
+ viewers can handle a multitude of types, and even if one
+ cannot understand a partcular type, we have no way to know
+ which. The spec permits this, by the way. -dms */
+
+#ifdef USE_ONLY_8DOT3
+ sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
+ image_type_to_string(args.imagetype,0));
+#else
+ sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
+ image_type_to_string(args.imagetype,0));
+#endif
+
+ if(exec_write(&spawn,NULL,command,name,1,1)!=0)
+ {
+ m_free(name);
+ goto fail;
+ }
+
+#ifdef __riscos__
+ riscos_set_filetype(spawn->tempfile_in,
+ image_type_to_string(args.imagetype,2));
+#endif
+
+ m_free(name);
+
+ fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
+
+ if(exec_read(spawn)!=0)
+ {
+ exec_finish(spawn);
+ goto fail;
+ }
+
+ if(exec_finish(spawn)!=0)
+ goto fail;
+ }
+
+ return;
+
+ fail:
+ log_error("unable to display photo ID!\n");
+}
diff --git a/g10/photoid.h b/g10/photoid.h
new file mode 100644
index 000000000..45d104f8c
--- /dev/null
+++ b/g10/photoid.h
@@ -0,0 +1,14 @@
+/* Photo ID functions */
+
+#ifndef _PHOTOID_H_
+#define _PHOTOID_H_
+
+#include "packet.h"
+
+PKT_user_id *generate_photo_id(PKT_public_key *pk);
+int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
+char *image_type_to_string(byte type,int style);
+void show_photos(const struct user_attribute *attrs,
+ int count,PKT_public_key *pk,PKT_secret_key *sk);
+
+#endif /* !_PHOTOID_H_ */
diff --git a/g10/pipemode.c b/g10/pipemode.c
new file mode 100644
index 000000000..f3351277e
--- /dev/null
+++ b/g10/pipemode.c
@@ -0,0 +1,317 @@
+/* pipemode.c - pipemode handler
+ * Copyright (C) 1998, 1990, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+#include "status.h"
+#include "filter.h"
+
+
+#define CONTROL_PACKET_SPACE 30
+#define FAKED_LITERAL_PACKET_SPACE (9+2+2)
+
+
+enum pipemode_state_e {
+ STX_init = 0,
+ STX_wait_operation,
+ STX_begin,
+ STX_text,
+ STX_detached_signature,
+ STX_detached_signature_wait_text,
+ STX_signed_data,
+ STX_wait_init
+};
+
+struct pipemode_context_s {
+ enum pipemode_state_e state;
+ int operation;
+ int stop;
+ int block_mode;
+ UnarmorPump unarmor_ctx;
+};
+
+
+static size_t
+make_control ( byte *buf, int code, int operation )
+{
+ const byte *sesmark;
+ size_t sesmarklen, n=0;;
+
+ sesmark = get_session_marker( &sesmarklen );
+ if ( sesmarklen > 20 )
+ BUG();
+
+ buf[n++] = 0xff; /* new format, type 63, 1 length byte */
+ n++; /* length will fixed below */
+ memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
+ buf[n++] = CTRLPKT_PIPEMODE;
+ buf[n++] = code;
+ buf[n++] = operation;
+ buf[1] = n-2;
+ return n;
+}
+
+
+
+static int
+pipemode_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ struct pipemode_context_s *stx = opaque;
+ int rc=0;
+ size_t n = 0;
+ int esc = 0;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ *ret_len = 0;
+ /* reserve some space for one control packet */
+ if ( size <= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE )
+ BUG();
+ size -= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE;
+
+ if ( stx->block_mode ) {
+ /* reserve 2 bytes for the block length */
+ buf[n++] = 0;
+ buf[n++] = 0;
+ }
+
+
+ while ( n < size ) {
+ /* FIXME: we have to make sure that we have a large enough
+ * buffer for a control packet even after we already read
+ * something. The easest way to do this is probably by ungetting
+ * the control sequence and returning the buffer we have
+ * already assembled */
+ int c = iobuf_get (a);
+ if (c == -1) {
+ if ( stx->state != STX_init ) {
+ log_error ("EOF encountered at wrong state\n");
+ stx->stop = 1;
+ return -1;
+ }
+ break;
+ }
+ if ( esc ) {
+ switch (c) {
+ case '@':
+ if ( stx->state == STX_text ) {
+ buf[n++] = c;
+ break;
+ }
+ else if ( stx->state == STX_detached_signature ) {
+ esc = 0;
+ goto do_unarmor; /* not a very elegant solution */
+ }
+ else if ( stx->state == STX_detached_signature_wait_text) {
+ esc = 0;
+ break; /* just ignore it in this state */
+ }
+ log_error ("@@ not allowed in current state\n");
+ return -1;
+ case '<': /* begin of stream part */
+ if ( stx->state != STX_init ) {
+ log_error ("nested begin of stream\n");
+ stx->stop = 1;
+ return -1;
+ }
+ stx->state = STX_wait_operation;
+ stx->block_mode = 0;
+ unarmor_pump_release (stx->unarmor_ctx);
+ stx->unarmor_ctx = NULL;
+ break;
+ case '>': /* end of stream part */
+ if ( stx->state != STX_wait_init ) {
+ log_error ("invalid state for @>\n");
+ stx->stop = 1;
+ return -1;
+ }
+ stx->state = STX_init;
+ break;
+ case 'V': /* operation = verify */
+ case 'E': /* operation = encrypt */
+ case 'S': /* operation = sign */
+ case 'B': /* operation = detach sign */
+ case 'C': /* operation = clearsign */
+ case 'D': /* operation = decrypt */
+ if ( stx->state != STX_wait_operation ) {
+ log_error ("invalid state for operation code\n");
+ stx->stop = 1;
+ return -1;
+ }
+ stx->operation = c;
+ if ( stx->operation == 'B') {
+ stx->state = STX_detached_signature;
+ if ( !opt.no_armor )
+ stx->unarmor_ctx = unarmor_pump_new ();
+ }
+ else
+ stx->state = STX_begin;
+ n += make_control ( buf+n, 1, stx->operation );
+ /* must leave after a control packet */
+ goto leave;
+
+ case 't': /* plaintext text follows */
+ if ( stx->state == STX_detached_signature_wait_text )
+ stx->state = STX_detached_signature;
+ if ( stx->state == STX_detached_signature ) {
+ if ( stx->operation != 'B' ) {
+ log_error ("invalid operation for this state\n");
+ stx->stop = 1;
+ return -1;
+ }
+ stx->state = STX_signed_data;
+ n += make_control ( buf+n, 2, 'B' );
+ /* and now we fake a literal data packet much the same
+ * as in armor.c */
+ buf[n++] = 0xaf; /* old packet format, type 11,
+ var length */
+ buf[n++] = 0; /* set the length header */
+ buf[n++] = 6;
+ buf[n++] = 'b'; /* we ignore it anyway */
+ buf[n++] = 0; /* namelength */
+ memset(buf+n, 0, 4); /* timestamp */
+ n += 4;
+ /* and return now so that we are sure to have
+ * more space in the bufer for the next control
+ * packet */
+ stx->block_mode = 1;
+ goto leave2;
+ }
+ else {
+ log_error ("invalid state for @t\n");
+ stx->stop = 1;
+ return -1;
+ }
+ break;
+
+ case '.': /* ready */
+ if ( stx->state == STX_signed_data ) {
+ if (stx->block_mode) {
+ buf[0] = (n-2) >> 8;
+ buf[1] = (n-2);
+ if ( buf[0] || buf[1] ) {
+ /* end of blocks marker */
+ buf[n++] = 0;
+ buf[n++] = 0;
+ }
+ stx->block_mode = 0;
+ }
+ n += make_control ( buf+n, 3, 'B' );
+ }
+ else {
+ log_error ("invalid state for @.\n");
+ stx->stop = 1;
+ return -1;
+ }
+ stx->state = STX_wait_init;
+ goto leave;
+
+ default:
+ log_error ("invalid escape sequence 0x%02x in stream\n",
+ c);
+ stx->stop = 1;
+ return -1;
+ }
+ esc = 0;
+ }
+ else if (c == '@')
+ esc = 1;
+ else if (stx->unarmor_ctx) {
+ do_unarmor: /* used to handle a @@ */
+ c = unarmor_pump (stx->unarmor_ctx, c);
+ if ( !(c & ~255) )
+ buf[n++] = c;
+ else if ( c < 0 ) {
+ /* end of armor or error - we don't care becuase
+ the armor can be modified anyway. The unarmored
+ stuff should stand for itself. */
+ unarmor_pump_release (stx->unarmor_ctx);
+ stx->unarmor_ctx = NULL;
+ stx->state = STX_detached_signature_wait_text;
+ }
+ }
+ else if (stx->state == STX_detached_signature_wait_text)
+ ; /* just wait */
+ else
+ buf[n++] = c;
+ }
+
+ leave:
+ if ( !n ) {
+ stx->stop = 1;
+ rc = -1; /* eof */
+ }
+ if ( stx->block_mode ) {
+ /* fixup the block length */
+ buf[0] = (n-2) >> 8;
+ buf[1] = (n-2);
+ }
+ leave2:
+ /*log_hexdump ("pipemode:", buf, n );*/
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_DESC )
+ *(char**)buf = "pipemode_filter";
+ return rc;
+}
+
+
+
+void
+run_in_pipemode(void)
+{
+ IOBUF fp;
+ armor_filter_context_t afx;
+ struct pipemode_context_s stx;
+ int rc;
+
+ memset( &afx, 0, sizeof afx);
+ memset( &stx, 0, sizeof stx);
+
+ fp = iobuf_open("-");
+ iobuf_push_filter (fp, pipemode_filter, &stx );
+
+ do {
+ write_status (STATUS_BEGIN_STREAM);
+ rc = proc_packets( NULL, fp );
+ write_status (STATUS_END_STREAM);
+ } while ( !stx.stop );
+
+}
+
+
+
+
+
+
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 1170c4088..671b56879 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1,5 +1,5 @@
/* pkclist.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,77 +25,21 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
+#include "main.h"
#include "trustdb.h"
#include "ttyio.h"
#include "status.h"
#include "i18n.h"
-#include "main.h"
#define CONTROL_D ('D' - 'A' + 1)
-/* fixme: we have nearly the same code in keyedit.c */
-static void
-print_fpr( PKT_public_key *pk )
-{
- byte array[MAX_FINGERPRINT_LEN], *p;
- size_t i, n;
-
- fingerprint_from_pk( pk, array, &n );
- p = array;
- /* Translators: this shoud fit into 24 bytes to that the fingerprint
- * data is properly aligned with the user ID */
- tty_printf(_(" Fingerprint:"));
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- tty_printf(" ");
- tty_printf(" %02X%02X", *p, p[1] );
- }
- }
- else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- tty_printf(" ");
- tty_printf(" %02X", *p );
- }
- }
- tty_printf("\n");
-}
-
-static void
-fpr_info( PKT_public_key *pk )
-{
- byte array[MAX_FINGERPRINT_LEN], *p;
- size_t i, n;
- FILE *fp = log_stream();
-
- fingerprint_from_pk( pk, array, &n );
- p = array;
- log_info(_("Fingerprint:"));
- if( n == 20 ) {
- for(i=0; i < n ; i++, i++, p += 2 ) {
- if( i == 10 )
- putc(' ', fp);
- fprintf(fp, " %02X%02X", *p, p[1] );
- }
- }
- else {
- for(i=0; i < n ; i++, p++ ) {
- if( i && !(i%8) )
- putc(' ', fp);
- fprintf(fp, " %02X", *p );
- }
- }
- putc('\n', fp );
-}
-
/****************
* Show the revocation reason as it is stored with the given signature
@@ -108,15 +52,15 @@ do_show_revocation_reason( PKT_signature *sig )
int seq = 0;
const char *text;
- while( (p = enum_sig_subpkt( sig->hashed_data, SIGSUBPKT_REVOC_REASON,
- &n, &seq )) ) {
+ while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
+ &n, &seq, NULL )) ) {
if( !n )
continue; /* invalid - just skip it */
if( *p == 0 )
text = _("No reason specified");
else if( *p == 0x01 )
- text = _("Key is superseeded");
+ text = _("Key is superseded");
else if( *p == 0x02 )
text = _("Key has been compromised");
else if( *p == 0x03 )
@@ -126,7 +70,7 @@ do_show_revocation_reason( PKT_signature *sig )
else
text = NULL;
- log_info( _("Reason for revocation: ") );
+ log_info( _("reason for revocation: ") );
if( text )
fputs( text, log_stream() );
else
@@ -143,7 +87,7 @@ do_show_revocation_reason( PKT_signature *sig )
if( n ) {
pp = memchr( p, '\n', n );
nn = pp? pp - p : n;
- log_info( _("Revocation comment: ") );
+ log_info( _("revocation comment: ") );
print_string( log_stream(), p, nn, 0 );
putc( '\n', log_stream() );
p += nn; n -= nn;
@@ -152,18 +96,20 @@ do_show_revocation_reason( PKT_signature *sig )
}
}
+/* Mode 0: try and find the revocation based on the pk (i.e. check
+ subkeys, etc.) Mode 1: use only the revocation on the main pk */
-static void
-show_revocation_reason( PKT_public_key *pk )
+void
+show_revocation_reason( PKT_public_key *pk, int mode )
{
/* Hmmm, this is not so easy becuase we have to duplicate the code
* used in the trustbd to calculate the keyflags. We need to find
- * a clean way to check revocation certificates on keys and signatures.
- * And there should be no duplicate code. Because we enter this function
- * only when the trustdb toldus, taht we have a revoked key, we could
- * simplylook for a revocation cert and display this one, when there is
- * only one. Let's try to do this until we have a better solution.
- */
+ * a clean way to check revocation certificates on keys and
+ * signatures. And there should be no duplicate code. Because we
+ * enter this function only when the trustdb told us that we have
+ * a revoked key, we could simply look for a revocation cert and
+ * display this one, when there is only one. Let's try to do this
+ * until we have a better solution. */
KBNODE node, keyblock = NULL;
byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
@@ -178,9 +124,10 @@ show_revocation_reason( PKT_public_key *pk )
}
for( node=keyblock; node; node = node->next ) {
- if( ( node->pkt->pkttype == PKT_PUBLIC_KEY
+ if( (mode && node->pkt->pkttype == PKT_PUBLIC_KEY) ||
+ ( ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- && !cmp_public_keys( node->pkt->pkt.public_key, pk ) )
+ && !cmp_public_keys( node->pkt->pkt.public_key, pk ) ) )
break;
}
if( !node ) {
@@ -197,16 +144,23 @@ show_revocation_reason( PKT_public_key *pk )
|| node->pkt->pkt.signature->sig_class == 0x28 ) ) {
/* FIXME: we should check the signature here */
do_show_revocation_reason ( node->pkt->pkt.signature );
+ break;
}
}
+ /* We didn't find it, so check if the whole key is revoked */
+ if(!node && !mode)
+ show_revocation_reason(pk,1);
+
release_kbnode( keyblock );
}
static void
-show_paths( ulong lid, int only_first )
+show_paths (const PKT_public_key *pk, int only_first )
{
+ log_debug("not yet implemented\n");
+#if 0
void *context = NULL;
unsigned otrust, validity;
int last_level, level;
@@ -224,16 +178,17 @@ show_paths( ulong lid, int only_first )
last_level = level;
rc = keyid_from_lid( lid, keyid );
+
if( rc ) {
log_error("ooops: can't get keyid for lid %lu\n", lid);
return;
}
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
rc = get_pubkey( pk, keyid );
if( rc ) {
log_error("key %08lX: public key not found: %s\n",
- (ulong)keyid[1], gpg_errstr(rc) );
+ (ulong)keyid[1], g10_errstr(rc) );
return;
}
@@ -257,11 +212,12 @@ show_paths( ulong lid, int only_first )
p = get_user_id( keyid, &n );
tty_print_utf8_string( p, n ),
- gcry_free(p);
+ m_free(p);
tty_printf("\"\n");
free_public_key( pk );
}
enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
+#endif
tty_printf("\n");
}
@@ -269,207 +225,192 @@ show_paths( ulong lid, int only_first )
/****************
- * Returns true if an ownertrust has changed.
+ * mode: 0 = standard
+ * 1 = Without key info and additional menu option 'm'
+ * this does also add an option to set the key to ultimately trusted.
+ * Returns:
+ * -2 = nothing changed - caller should show some additional info
+ * -1 = quit operation
+ * 0 = nothing changed
+ * 1 = new ownertrust now in new_trust
*/
static int
-do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust, int defer_help )
+do_edit_ownertrust (PKT_public_key *pk, int mode,
+ unsigned *new_trust, int defer_help )
{
- char *p;
- int rc;
- size_t n;
- u32 keyid[2];
- PKT_public_key *pk ;
- int changed=0;
- int quit=0;
- int show=0;
- int did_help=defer_help;
-
- rc = keyid_from_lid( lid, keyid );
- if( rc ) {
- log_error("ooops: can't get keyid for lid %lu\n", lid);
- return 0;
- }
-
- pk = gcry_xcalloc( 1, sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_error("key %08lX: public key not found: %s\n",
- (ulong)keyid[1], gpg_errstr(rc) );
- return 0;
- }
-
-
- for(;;) {
- /* a string with valid answers */
- const char *ans = _("sSmMqQ");
-
- if( !did_help ) {
- if( !mode ) {
- tty_printf(_("No trust value assigned to %lu:\n"
- "%4u%c/%08lX %s \""), lid,
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n ),
- gcry_free(p);
- tty_printf("\"\n");
- print_fpr( pk );
- tty_printf("\n");
- }
- tty_printf(_(
-"Please decide how far you trust this user to correctly\n"
-"verify other users' keys (by looking at passports,\n"
-"checking fingerprints from different sources...)?\n\n"
-" 1 = Don't know\n"
-" 2 = I do NOT trust\n"
-" 3 = I trust marginally\n"
-" 4 = I trust fully\n"
-" s = please show me more information\n") );
- if( mode )
- tty_printf(_(" m = back to the main menu\n"));
- else
- tty_printf(_(" q = quit\n"));
- tty_printf("\n");
- did_help = 1;
- }
- if( strlen(ans) != 6 )
- BUG();
- p = cpr_get("edit_ownertrust.value",_("Your decision? "));
- trim_spaces(p);
- cpr_kill_prompt();
- if( !*p )
- did_help = 0;
- else if( *p && p[1] )
- ;
- else if( !p[1] && (*p >= '1' && *p <= '4') ) {
- unsigned trust;
- switch( *p ) {
- case '1': trust = TRUST_UNDEFINED; break;
- case '2': trust = TRUST_NEVER ; break;
- case '3': trust = TRUST_MARGINAL ; break;
- case '4': trust = TRUST_FULLY ; break;
- default: BUG();
- }
- *new_trust = trust;
- changed = 1;
- break;
- }
- else if( *p == ans[0] || *p == ans[1] ) {
- tty_printf(_(
- "Certificates leading to an ultimately trusted key:\n"));
- show = 1;
- break;
- }
- else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) {
- break ; /* back to the menu */
- }
- else if( !mode && (*p == ans[4] || *p == ans[5] ) ) {
- quit = 1;
- break ; /* back to the menu */
- }
- gcry_free(p); p = NULL;
- }
- gcry_free(p);
- gcry_free(pk);
- return show? -2: quit? -1 : changed;
+ char *p;
+ size_t n;
+ u32 keyid[2];
+ int changed=0;
+ int quit=0;
+ int show=0;
+ int did_help=defer_help;
+
+ keyid_from_pk (pk, keyid);
+ for(;;) {
+ /* a string with valid answers */
+ const char *ans = _("iImMqQsS");
+
+ if( !did_help )
+ {
+ if( !mode )
+ {
+ tty_printf(_("No trust value assigned to:\n"
+ "%4u%c/%08lX %s \""),
+ nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk( pk ) );
+ p = get_user_id( keyid, &n );
+ tty_print_utf8_string( p, n ),
+ m_free(p);
+ tty_printf("\"\n");
+ print_fingerprint (pk, NULL, 2);
+ tty_printf("\n");
+ }
+ tty_printf (_(
+ "Please decide how far you trust this user to correctly\n"
+ "verify other users' keys (by looking at passports,\n"
+ "checking fingerprints from different sources...)?\n\n"));
+ tty_printf (_(" %d = Don't know\n"), 1);
+ tty_printf (_(" %d = I do NOT trust\n"), 2);
+ tty_printf (_(" %d = I trust marginally\n"), 3);
+ tty_printf (_(" %d = I trust fully\n"), 4);
+ if (mode)
+ tty_printf (_(" %d = I trust ultimately\n"), 5);
+ tty_printf (_(" i = please show me more information\n") );
+ if( mode )
+ tty_printf(_(" m = back to the main menu\n"));
+ else
+ {
+ tty_printf(_(" s = skip this key\n"));
+ tty_printf(_(" q = quit\n"));
+ }
+ tty_printf("\n");
+ did_help = 1;
+ }
+ if( strlen(ans) != 8 )
+ BUG();
+ p = cpr_get("edit_ownertrust.value",_("Your decision? "));
+ trim_spaces(p);
+ cpr_kill_prompt();
+ if( !*p )
+ did_help = 0;
+ else if( *p && p[1] )
+ ;
+ else if( !p[1] && (*p >= '1' && *p <= (mode?'5':'4')) )
+ {
+ unsigned int trust;
+ switch( *p )
+ {
+ case '1': trust = TRUST_UNDEFINED; break;
+ case '2': trust = TRUST_NEVER ; break;
+ case '3': trust = TRUST_MARGINAL ; break;
+ case '4': trust = TRUST_FULLY ; break;
+ case '5': trust = TRUST_ULTIMATE ; break;
+ default: BUG();
+ }
+ if (trust == TRUST_ULTIMATE
+ && !cpr_get_answer_is_yes ("edit_ownertrust.set_ultimate.okay",
+ _("Do you really want to set this key"
+ " to ultimate trust? ")))
+ ; /* no */
+ else
+ {
+ *new_trust = trust;
+ changed = 1;
+ break;
+ }
+ }
+ else if( *p == ans[0] || *p == ans[1] )
+ {
+ tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
+ show = 1;
+ break;
+ }
+ else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) )
+ {
+ break ; /* back to the menu */
+ }
+ else if( !mode && (*p == ans[6] || *p == ans[7] ) )
+ {
+ break; /* skip */
+ }
+ else if( !mode && (*p == ans[4] || *p == ans[5] ) )
+ {
+ quit = 1;
+ break ; /* back to the menu */
+ }
+ m_free(p); p = NULL;
+ }
+ m_free(p);
+ return show? -2: quit? -1 : changed;
}
-
+/*
+ * Display a menu to change the ownertrust of the key PK (which should
+ * be a primary key).
+ * For mode values see do_edit_ownertrust ()
+ */
int
-edit_ownertrust( ulong lid, int mode )
+edit_ownertrust (PKT_public_key *pk, int mode )
{
- unsigned int trust;
- int no_help = 0;
-
- for(;;) {
- switch( do_edit_ownertrust( lid, mode, &trust, no_help ) ) {
- case -1:
- return 0;
- case -2:
- show_paths( lid, 1 );
- no_help = 1;
- break;
- case 1:
- trust &= ~TRUST_FLAG_DISABLED;
- trust |= get_ownertrust( lid ) & TRUST_FLAG_DISABLED;
- if( !update_ownertrust( lid, trust ) )
- return 1;
- return 0;
- default:
- return 0;
- }
+ unsigned int trust;
+ int no_help = 0;
+
+ for(;;)
+ {
+ switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
+ {
+ case -1: /* quit */
+ return -1;
+ case -2: /* show info */
+ show_paths(pk, 1);
+ no_help = 1;
+ break;
+ case 1: /* trust value set */
+ trust &= ~TRUST_FLAG_DISABLED;
+ trust |= get_ownertrust (pk) & TRUST_FLAG_DISABLED;
+ update_ownertrust (pk, trust );
+ return 1;
+ default:
+ return 0;
+ }
}
}
-static int
-add_ownertrust_cb( ulong lid )
-{
- unsigned trust;
- int rc = do_edit_ownertrust( lid, 0, &trust, 0 );
-
- if( rc == 1 )
- return trust & TRUST_MASK;
- return rc > 0? 0 : rc;
-}
-
-/****************
- * Try to add some more owner trusts (interactive)
- * This function presents all the signator in a certificate
- * chain who have no ownertrust value assigned.
- * Returns: -1 if no ownertrust were added.
- */
-static int
-add_ownertrust( PKT_public_key *pk, int *quit, unsigned *trustlevel )
-{
- int rc;
- unsigned flags = 0;
-
- *quit = 0;
- *trustlevel = 0;
- tty_printf(
-_("Could not find a valid trust path to the key. Let's see whether we\n"
- "can assign some missing owner trust values.\n\n"));
-
- rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags );
-
- if( !(flags & 1) )
- tty_printf(_("No path leading to one of our keys found.\n\n") );
- else if( !(flags & 2) )
- tty_printf(_("No certificates with undefined trust found.\n\n") );
- else if( !(flags & 4) )
- tty_printf(_("No trust values changed.\n\n") );
-
- return (flags & 4)? 0:-1;
-}
/****************
* Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL
- * Returns: true if we trust. Might change the trustlevel
+ * Returns: true if we trust.
*/
static int
-do_we_trust( PKT_public_key *pk, int *trustlevel )
+do_we_trust( PKT_public_key *pk, unsigned int *trustlevel )
{
- int rc;
- int did_add = 0;
- int trustmask = 0;
-
- retry:
+ unsigned int trustmask = 0;
+
+ /* FIXME: get_pubkey_byname already checks the validity and won't
+ * return keys which are either expired or revoked - so these
+ * question here won't get triggered. We have to find a solution
+ * for this. It might make sense to have a function in getkey.c
+ * which does only the basic checks and returns even revoked and
+ * expired keys. This fnction could then also returhn a list of
+ * keys if the speicified name is ambiguous
+ */
if( (*trustlevel & TRUST_FLAG_REVOKED) ) {
log_info(_("key %08lX: key has been revoked!\n"),
(ulong)keyid_from_pk( pk, NULL) );
- show_revocation_reason( pk );
+ show_revocation_reason( pk, 0 );
if( opt.batch )
- return 0;
+ return 0; /* no */
if( !cpr_get_answer_is_yes("revoked_key.override",
_("Use this key anyway? ")) )
- return 0;
+ return 0; /* no */
trustmask |= TRUST_FLAG_REVOKED;
}
- else if( (*trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
+ if( (*trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
log_info(_("key %08lX: subkey has been revoked!\n"),
(ulong)keyid_from_pk( pk, NULL) );
- show_revocation_reason( pk );
+ show_revocation_reason( pk, 0 );
if( opt.batch )
return 0;
@@ -483,52 +424,25 @@ do_we_trust( PKT_public_key *pk, int *trustlevel )
if( opt.always_trust) {
if( opt.verbose )
log_info("No trust check due to --always-trust option\n");
- /* The problem with this, is that EXPIRE can't be checked as
- * this needs to insert a ne key into the trustdb first and
- * we don't want that */
return 1;
}
-
switch( (*trustlevel & TRUST_MASK) ) {
- case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error("failed to insert it into the trustdb: %s\n",
- gpg_errstr(rc) );
- return 0; /* no */
- }
- rc = check_trust( pk, trustlevel, NULL, NULL, NULL );
- *trustlevel &= ~trustmask;
- if( rc )
- log_fatal("trust check after insert failed: %s\n",
- gpg_errstr(rc) );
- if( *trustlevel == TRUST_UNKNOWN || *trustlevel == TRUST_EXPIRED ) {
- log_debug("do_we_trust: oops at %d\n", __LINE__ );
- return 0;
- }
- return do_we_trust( pk, trustlevel );
-
case TRUST_EXPIRED:
log_info(_("%08lX: key has expired\n"),
(ulong)keyid_from_pk( pk, NULL) );
return 0; /* no */
+ default:
+ log_error ("invalid trustlevel %u returned from validation layer\n",
+ *trustlevel);
+ /* fall thru */
+ case TRUST_UNKNOWN:
case TRUST_UNDEFINED:
- if( opt.batch || opt.answer_no )
- log_info(_("%08lX: no info to calculate a trust probability\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- else {
- int quit;
-
- rc = add_ownertrust( pk, &quit, trustlevel );
- *trustlevel &= ~trustmask;
- if( !rc && !did_add && !quit ) {
- did_add = 1;
- goto retry;
- }
- }
- return 0;
+ log_info(_("%08lX: There is no indication that this key "
+ "really belongs to the owner\n"),
+ (ulong)keyid_from_pk( pk, NULL) );
+ return 0; /* no */
case TRUST_NEVER:
log_info(_("%08lX: We do NOT trust this key\n"),
@@ -550,8 +464,6 @@ do_we_trust( PKT_public_key *pk, int *trustlevel )
if( opt.verbose )
log_info(_("This key belongs to us\n"));
return 1; /* yes */
-
- default: BUG();
}
return 1; /* yes */
@@ -564,7 +476,7 @@ do_we_trust( PKT_public_key *pk, int *trustlevel )
* key anyway.
*/
static int
-do_we_trust_pre( PKT_public_key *pk, int trustlevel )
+do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
{
int rc;
@@ -574,7 +486,8 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel )
return 0;
if( (trustlevel & TRUST_FLAG_SUB_REVOKED) && !rc )
return 0;
- else if( !opt.batch && !rc ) {
+
+ if( !opt.batch && !rc ) {
char *p;
u32 keyid[2];
size_t n;
@@ -585,9 +498,9 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel )
(ulong)keyid[1], datestr_from_pk( pk ) );
p = get_user_id( keyid, &n );
tty_print_utf8_string( p, n ),
- gcry_free(p);
+ m_free(p);
tty_printf("\"\n");
- print_fpr( pk );
+ print_fingerprint (pk, NULL, 2);
tty_printf("\n");
tty_printf(_(
@@ -599,7 +512,7 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel )
_("Use this key anyway? ")) )
rc = 1;
- /* Hmmm: Should we set a flag to tell the user the user about
+ /* Hmmm: Should we set a flag to tell the user about
* his decision the next time he encrypts for this recipient?
*/
}
@@ -620,121 +533,102 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel )
int
check_signatures_trust( PKT_signature *sig )
{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- int trustlevel;
- int did_add = 0;
- int rc=0;
-
-
- if( opt.always_trust ) {
- if( !opt.quiet )
- log_info(_("WARNING: Using untrusted key!\n"));
- return 0;
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
+ unsigned int trustlevel;
+ int rc=0;
+
+ if ( opt.always_trust)
+ {
+ if( !opt.quiet )
+ log_info(_("WARNING: Using untrusted key!\n"));
+ if (opt.with_fingerprint)
+ print_fingerprint (pk, NULL, 1);
+ goto leave;
}
-
- rc = get_pubkey( pk, sig->keyid );
- if( rc ) { /* this should not happen */
- log_error("Ooops; the key vanished - can't check the trust\n");
- rc = GPGERR_NO_PUBKEY;
- goto leave;
+ rc = get_pubkey( pk, sig->keyid );
+ if (rc)
+ { /* this should not happen */
+ log_error("Ooops; the key vanished - can't check the trust\n");
+ rc = G10ERR_NO_PUBKEY;
+ goto leave;
}
- rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
- if( rc ) {
- log_error("check trust failed: %s\n", gpg_errstr(rc));
- goto leave;
- }
+ trustlevel = get_validity (pk, NULL);
- retry:
- if( (trustlevel & TRUST_FLAG_REVOKED) ) {
- write_status( STATUS_KEYREVOKED );
- log_info(_("WARNING: This key has been revoked by its owner!\n"));
- log_info(_(" This could mean that the signature is forgery.\n"));
- show_revocation_reason( pk );
+ if ( (trustlevel & TRUST_FLAG_REVOKED) )
+ {
+ write_status( STATUS_KEYREVOKED );
+ log_info(_("WARNING: This key has been revoked by its owner!\n"));
+ log_info(_(" This could mean that the signature is forgery.\n"));
+ show_revocation_reason( pk, 0 );
}
- else if( (trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
- write_status( STATUS_KEYREVOKED );
- log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
- show_revocation_reason( pk );
+ else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) )
+ {
+ write_status( STATUS_KEYREVOKED );
+ log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
+ show_revocation_reason( pk, 0 );
}
-
-
- switch( (trustlevel & TRUST_MASK) ) {
- case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error("failed to insert it into the trustdb: %s\n",
- gpg_errstr(rc) );
- goto leave;
- }
- rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
- if( rc )
- log_fatal("trust check after insert failed: %s\n",
- gpg_errstr(rc) );
- if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED )
- BUG();
- goto retry;
-
- case TRUST_EXPIRED:
- log_info(_("Note: This key has expired!\n"));
- fpr_info( pk );
- break;
-
- case TRUST_UNDEFINED:
- if( did_add || opt.batch || opt.answer_no ) {
- write_status( STATUS_TRUST_UNDEFINED );
- log_info(_(
- "WARNING: This key is not certified with a trusted signature!\n"));
- log_info(_(
- " There is no indication that the "
- "signature belongs to the owner.\n" ));
- fpr_info( pk );
- }
- else {
- int quit;
- rc = add_ownertrust( pk, &quit, &trustlevel );
- if( rc || quit ) {
- did_add = 1;
- rc = 0;
- }
- goto retry;
- }
- break;
-
- case TRUST_NEVER:
- write_status( STATUS_TRUST_NEVER );
- log_info(_("WARNING: We do NOT trust this key!\n"));
- log_info(_(" The signature is probably a FORGERY.\n"));
- rc = GPGERR_BAD_SIGN;
- break;
-
- case TRUST_MARGINAL:
- write_status( STATUS_TRUST_MARGINAL );
- log_info(_(
- "WARNING: This key is not certified with sufficiently trusted signatures!\n"
- ));
- log_info(_(
- " It is not certain that the signature belongs to the owner.\n"
- ));
- fpr_info( pk );
- break;
-
- case TRUST_FULLY:
- write_status( STATUS_TRUST_FULLY );
- break;
-
- case TRUST_ULTIMATE:
- write_status( STATUS_TRUST_ULTIMATE );
- break;
-
- default: BUG();
+
+ if ((trustlevel & TRUST_FLAG_DISABLED))
+ log_info (_("Note: This key has been disabled.\n"));
+
+ switch ( (trustlevel & TRUST_MASK) )
+ {
+ case TRUST_EXPIRED:
+ log_info(_("Note: This key has expired!\n"));
+ print_fingerprint (pk, NULL, 1);
+ break;
+
+ default:
+ log_error ("invalid trustlevel %u returned from validation layer\n",
+ trustlevel);
+ /* fall thru */
+ case TRUST_UNKNOWN:
+ case TRUST_UNDEFINED:
+ write_status( STATUS_TRUST_UNDEFINED );
+ log_info(_("WARNING: This key is not certified with"
+ " a trusted signature!\n"));
+ log_info(_(" There is no indication that the "
+ "signature belongs to the owner.\n" ));
+ print_fingerprint (pk, NULL, 1);
+ break;
+
+ case TRUST_NEVER:
+ /* currently we won't get that status */
+ write_status( STATUS_TRUST_NEVER );
+ log_info(_("WARNING: We do NOT trust this key!\n"));
+ log_info(_(" The signature is probably a FORGERY.\n"));
+ if (opt.with_fingerprint)
+ print_fingerprint (pk, NULL, 1);
+ rc = G10ERR_BAD_SIGN;
+ break;
+
+ case TRUST_MARGINAL:
+ write_status( STATUS_TRUST_MARGINAL );
+ log_info(_("WARNING: This key is not certified with"
+ " sufficiently trusted signatures!\n"));
+ log_info(_(" It is not certain that the"
+ " signature belongs to the owner.\n" ));
+ print_fingerprint (pk, NULL, 1);
+ break;
+
+ case TRUST_FULLY:
+ write_status( STATUS_TRUST_FULLY );
+ if (opt.with_fingerprint)
+ print_fingerprint (pk, NULL, 1);
+ break;
+
+ case TRUST_ULTIMATE:
+ write_status( STATUS_TRUST_ULTIMATE );
+ if (opt.with_fingerprint)
+ print_fingerprint (pk, NULL, 1);
+ break;
}
-
- leave:
- free_public_key( pk );
- return rc;
+ leave:
+ free_public_key( pk );
+ return rc;
}
@@ -746,7 +640,7 @@ release_pk_list( PK_LIST pk_list )
for( ; pk_list; pk_list = pk_rover ) {
pk_rover = pk_list->next;
free_public_key( pk_list->pk );
- gcry_free( pk_list );
+ m_free( pk_list );
}
}
@@ -775,11 +669,11 @@ default_recipient(void)
int i;
if( opt.def_recipient )
- return gcry_xstrdup( opt.def_recipient );
+ return m_strdup( opt.def_recipient );
if( !opt.def_recipient_self )
return NULL;
- sk = gcry_xcalloc( 1, sizeof *sk );
- i = get_seckey_byname( NULL, sk, NULL, 0, NULL );
+ sk = m_alloc_clear( sizeof *sk );
+ i = get_seckey_byname( sk, NULL, 0 );
if( i ) {
free_secret_key( sk );
return NULL;
@@ -787,7 +681,7 @@ default_recipient(void)
n = MAX_FINGERPRINT_LEN;
fingerprint_from_sk( sk, fpr, &n );
free_secret_key( sk );
- p = gcry_xmalloc( 2*n+3 );
+ p = m_alloc( 2*n+3 );
*p++ = '0';
*p++ = 'x';
for(i=0; i < n; i++ )
@@ -796,31 +690,82 @@ default_recipient(void)
return p;
}
+static int
+expand_id(const char *id,STRLIST *into,unsigned int flags)
+{
+ struct groupitem *groups;
+ int count=0;
+
+ for(groups=opt.grouplist;groups;groups=groups->next)
+ {
+ /* need strcasecmp() here, as this should be localized */
+ if(strcasecmp(groups->name,id)==0)
+ {
+ STRLIST each,sl;
+
+ /* this maintains the current utf8-ness */
+ for(each=groups->values;each;each=each->next)
+ {
+ sl=add_to_strlist(into,each->d);
+ sl->flags=flags;
+ count++;
+ }
+
+ break;
+ }
+ }
+
+ return count;
+}
+
+/* For simplicity, and to avoid potential loops, we only expand once -
+ you can't make an alias that points to an alias. */
+static STRLIST
+expand_group(STRLIST input)
+{
+ STRLIST sl,output=NULL,rover;
+
+ for(rover=input;rover;rover=rover->next)
+ if(expand_id(rover->d,&output,rover->flags)==0)
+ {
+ /* Didn't find any groups, so use the existing string */
+ sl=add_to_strlist(&output,rover->d);
+ sl->flags=rover->flags;
+ }
+
+ return output;
+}
int
-build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
+build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use )
{
PK_LIST pk_list = NULL;
PKT_public_key *pk=NULL;
int rc=0;
int any_recipients=0;
- STRLIST rov;
+ STRLIST rov,remusr;
char *def_rec = NULL;
+ if(opt.grouplist)
+ remusr=expand_group(rcpts);
+ else
+ remusr=rcpts;
+
/* check whether there are any recipients in the list and build the
* list of the encrypt-to ones (we always trust them) */
for( rov = remusr; rov; rov = rov->next ) {
if( !(rov->flags & 1) )
any_recipients = 1;
- else if( (use & GCRY_PK_USAGE_ENCR) && !opt.no_encrypt_to ) {
- pk = gcry_xcalloc( 1, sizeof *pk );
+ else if( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) {
+ pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- if( (rc = get_pubkey_byname( NULL, pk, rov->d, NULL )) ) {
+ if( (rc = get_pubkey_byname( pk, rov->d, NULL, NULL )) ) {
free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) );
- }
- else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
- pk->pubkey_usage)) ) {
+ log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ rov->d, strlen (rov->d), -1);
+ }
+ else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
/* Skip the actual key if the key is already present
* in the list */
if (key_present_in_pk_list(pk_list, pk) == 0) {
@@ -830,7 +775,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else {
PK_LIST r;
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->mark = 0;
@@ -839,44 +784,53 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else {
free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) );
+ log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ rov->d, strlen (rov->d), -1);
}
}
}
if( !any_recipients && !opt.batch ) { /* ask */
- char *answer=NULL;
int have_def_rec;
+ char *answer=NULL;
+ STRLIST backlog=NULL;
def_rec = default_recipient();
have_def_rec = !!def_rec;
if( !have_def_rec )
tty_printf(_(
- "You did not specify a user ID. (you may use \"-r\")\n\n"));
+ "You did not specify a user ID. (you may use \"-r\")\n"));
for(;;) {
rc = 0;
- gcry_free(answer);
+ m_free(answer);
if( have_def_rec ) {
answer = def_rec;
def_rec = NULL;
}
+ else if(backlog) {
+ answer=pop_strlist(&backlog);
+ }
else {
answer = cpr_get_utf8("pklist.user_id.enter",
- _("Enter the user ID: "));
+ _("\nEnter the user ID. End with an empty line: "));
trim_spaces(answer);
cpr_kill_prompt();
}
- if( !*answer )
+ if( !answer || !*answer ) {
+ m_free(answer);
break;
+ }
+ if(expand_id(answer,&backlog,0))
+ continue;
if( pk )
free_public_key( pk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- rc = get_pubkey_byname( NULL, pk, answer, NULL );
+ rc = get_pubkey_byname( pk, answer, NULL, NULL );
if( rc )
tty_printf(_("No such user ID.\n"));
- else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
- pk->pubkey_usage)) ) {
+ else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
if( have_def_rec ) {
if (key_present_in_pk_list(pk_list, pk) == 0) {
free_public_key(pk); pk = NULL;
@@ -884,25 +838,20 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
"already set as default recipient\n") );
}
else {
- PK_LIST r = gcry_xmalloc( sizeof *r );
+ PK_LIST r = m_alloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->mark = 0;
pk_list = r;
}
any_recipients = 1;
- break;
+ continue;
}
else {
int trustlevel;
- rc = check_trust( pk, &trustlevel, pk->namehash,
- NULL, NULL );
- if( rc ) {
- log_error("error checking pk of `%s': %s\n",
- answer, gpg_errstr(rc) );
- }
- else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ trustlevel = get_validity (pk, NULL);
+ if( (trustlevel & TRUST_FLAG_DISABLED) ) {
tty_printf(_("Public key is disabled.\n") );
}
else if( do_we_trust_pre( pk, trustlevel ) ) {
@@ -910,52 +859,71 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
* in the list */
if (key_present_in_pk_list(pk_list, pk) == 0) {
free_public_key(pk); pk = NULL;
- log_info(_("skipped: public key "
- "already set with --encrypt-to\n") );
+ log_info(_("skipped: public key already set\n") );
}
else {
PK_LIST r;
-
- r = gcry_xmalloc( sizeof *r );
+ char *p;
+ size_t n;
+ u32 keyid[2];
+
+ keyid_from_pk( pk, keyid);
+ tty_printf("Added %4u%c/%08lX %s \"",
+ nbits_from_pk( pk ),
+ pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1],
+ datestr_from_pk( pk ) );
+ p = get_user_id( keyid, &n );
+ tty_print_utf8_string( p, n );
+ m_free(p);
+ tty_printf("\"\n");
+
+ r = m_alloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->mark = 0;
pk_list = r;
}
any_recipients = 1;
- break;
+ continue;
}
}
}
- gcry_free(def_rec); def_rec = NULL;
+ m_free(def_rec); def_rec = NULL;
have_def_rec = 0;
}
- gcry_free(answer);
if( pk ) {
free_public_key( pk );
pk = NULL;
}
}
else if( !any_recipients && (def_rec = default_recipient()) ) {
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
+ rc = get_pubkey_byname( pk, def_rec, NULL, NULL );
if( rc )
log_error(_("unknown default recipient `%s'\n"), def_rec );
- else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
- pk->pubkey_usage)) ) {
- PK_LIST r = gcry_xmalloc( sizeof *r );
+ else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
+ /* Mark any_recipients here since the default recipient
+ would have been used if it wasn't already there. It
+ doesn't really matter if we got this key from the default
+ recipient or an encrypt-to. */
+ any_recipients = 1;
+ if (key_present_in_pk_list(pk_list, pk) == 0)
+ log_info(_("skipped: public key already set as default recipient\n"));
+ else {
+ PK_LIST r = m_alloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->mark = 0;
pk_list = r;
- any_recipients = 1;
+ }
}
if( pk ) {
free_public_key( pk );
pk = NULL;
}
- gcry_free(def_rec); def_rec = NULL;
+ m_free(def_rec); def_rec = NULL;
}
else {
any_recipients = 0;
@@ -963,26 +931,27 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
if( (remusr->flags & 1) )
continue; /* encrypt-to keys are already handled */
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
pk->req_usage = use;
- if( (rc = get_pubkey_byname( NULL, pk, remusr->d, NULL )) ) {
+ if( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL )) ) {
free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) );
+ log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d, strlen (remusr->d),
+ -1);
}
- else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo,
- pk->pubkey_usage)) ) {
+ else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
int trustlevel;
- rc = check_trust( pk, &trustlevel, pk->namehash, NULL, NULL );
- if( rc ) {
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: error checking key: %s\n"),
- remusr->d, gpg_errstr(rc) );
- }
- else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ trustlevel = get_validity (pk, pk->namehash);
+ if( (trustlevel & TRUST_FLAG_DISABLED) ) {
free_public_key(pk); pk = NULL;
log_info(_("%s: skipped: public key is disabled\n"),
remusr->d);
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
}
else if( do_we_trust_pre( pk, trustlevel ) ) {
/* note: do_we_trust may have changed the trustlevel */
@@ -1000,7 +969,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else {
PK_LIST r;
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->mark = 0;
@@ -1009,55 +978,103 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else { /* we don't trust this pk */
free_public_key( pk ); pk = NULL;
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
}
}
else {
free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) );
+ write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
+ remusr->d,
+ strlen (remusr->d),
+ -1);
+ log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
}
}
}
if( !rc && !any_recipients ) {
log_error(_("no valid addressees\n"));
- rc = GPGERR_NO_USER_ID;
+ write_status_text (STATUS_NO_RECP, "0");
+ rc = G10ERR_NO_USER_ID;
}
if( rc )
release_pk_list( pk_list );
else
*ret_pk_list = pk_list;
+ if(opt.grouplist)
+ free_strlist(remusr);
return rc;
}
+/* In pgp6 mode, disallow all ciphers except IDEA (1), 3DES (2), and
+ CAST5 (3), all hashes except MD5 (1), SHA1 (2), and RIPEMD160 (3),
+ and all compressions except none (0) and ZIP (1). pgp7 mode
+ expands the cipher list to include AES128 (7), AES192 (8), AES256
+ (9), and TWOFISH (10). For a true PGP key all of this is unneeded
+ as they are the only items present in the preferences subpacket,
+ but checking here covers the weird case of encrypting to a key that
+ had preferences from a different implementation which was then used
+ with PGP. I am not completely comfortable with this as the right
+ thing to do, as it slightly alters the list of what the user is
+ supposedly requesting. It is not against the RFC however, as the
+ preference chosen will never be one that the user didn't specify
+ somewhere ("The implementation may use any mechanism to pick an
+ algorithm in the intersection"), and PGP has no mechanism to fix
+ such a broken preference list, so I'm including it. -dms */
static int
-algo_available( int preftype, int algo )
+algo_available( int preftype, int algo, void *hint )
{
if( preftype == PREFTYPE_SYM ) {
- return algo && !openpgp_cipher_test_algo( algo );
+ if( opt.pgp6 && ( algo != 1 && algo != 2 && algo != 3) )
+ return 0;
+
+ if( opt.pgp7 && (algo != 1 && algo != 2 && algo != 3 &&
+ algo != 7 && algo != 8 && algo != 9 && algo != 10) )
+ return 0;
+
+ return algo && !check_cipher_algo( algo );
}
else if( preftype == PREFTYPE_HASH ) {
- return algo && !openpgp_md_test_algo( algo );
+ int bits=0;
+
+ if(hint)
+ bits=*(int *)hint;
+
+ if(bits && (bits != md_digest_length(algo)))
+ return 0;
+
+ if( (opt.pgp6 || opt.pgp7 ) && ( algo != 1 && algo != 2 && algo != 3) )
+ return 0;
+
+ return algo && !check_digest_algo( algo );
}
- else if( preftype == PREFTYPE_COMPR ) {
- return !algo || algo == 1 || algo == 2;
+ else if( preftype == PREFTYPE_ZIP ) {
+ if ( ( opt.pgp6 || opt.pgp7 ) && ( algo !=0 && algo != 1) )
+ return 0;
+
+ return !check_compress_algo( algo );
}
else
return 0;
}
+
+
/****************
* Return -1 if we could not find an algorithm.
*/
int
-select_algo_from_prefs( PK_LIST pk_list, int preftype )
+select_algo_from_prefs(PK_LIST pk_list, int preftype, int request, void *hint)
{
PK_LIST pkr;
u32 bits[8];
- byte *pref = NULL;
- size_t npref;
+ const prefitem_t *prefs;
int i, j;
int compr_hack=0;
int any;
@@ -1070,43 +1087,65 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype )
u32 mask[8];
memset( mask, 0, 8 * sizeof *mask );
- if( !pkr->pk->local_id ) { /* try to set the local id */
- query_trust_info( pkr->pk, NULL );
- if( !pkr->pk->local_id ) {
- log_debug("select_algo_from_prefs: can't get LID\n");
- continue;
- }
+ if( preftype == PREFTYPE_SYM ) {
+ if( opt.pgp2 &&
+ pkr->pk->version < 4 &&
+ pkr->pk->selfsigversion < 4 )
+ mask[0] |= (1<<1); /* IDEA is implicitly there for v3 keys
+ with v3 selfsigs (rfc2440:12.1) if
+ --pgp2 mode is on. This doesn't
+ mean it's actually available, of
+ course. */
+ else
+ mask[0] |= (1<<2); /* 3DES is implicitly there for everyone else */
}
- if( preftype == PREFTYPE_SYM )
- mask[0] |= (1<<2); /* 3DES is implicitly there */
- gcry_free(pref);
- pref = get_pref_data( pkr->pk->local_id, pkr->pk->namehash, &npref);
+ else if( preftype == PREFTYPE_HASH ) {
+ /* While I am including this code for completeness, note
+ that currently --pgp2 mode locks the hash at MD5, so this
+ function will never even be called. Even if the hash
+ wasn't locked at MD5, we don't support sign+encrypt in
+ --pgp2 mode, and that's the only time PREFTYPE_HASH is
+ used anyway. -dms */
+ if( opt.pgp2 &&
+ pkr->pk->version < 4 &&
+ pkr->pk->selfsigversion < 4 )
+ mask[0] |= (1<<1); /* MD5 is there for v3 keys with v3
+ selfsigs when --pgp2 is on. */
+ else
+ mask[0] |= (1<<2); /* SHA1 is there for everyone else */
+ }
+ else if( preftype == PREFTYPE_ZIP )
+ mask[0] |= (1<<0); /* Uncompressed is implicit */
+
+ if (pkr->pk->user_id) /* selected by user ID */
+ prefs = pkr->pk->user_id->prefs;
+ else
+ prefs = pkr->pk->prefs;
+
any = 0;
- if( pref ) {
- #if 0
- log_hexdump("raw: ", pref, npref );
- #endif
- for(i=0; i+1 < npref; i+=2 ) {
- if( pref[i] == preftype ) {
- mask[pref[i+1]/32] |= 1 << (pref[i+1]%32);
+ if( prefs ) {
+ for (i=0; prefs[i].type; i++ ) {
+ if( prefs[i].type == preftype ) {
+ mask[prefs[i].value/32] |= 1 << (prefs[i].value%32);
any = 1;
}
}
}
- if( (!pref || !any) && preftype == PREFTYPE_COMPR ) {
+
+ if( (!prefs || !any) && preftype == PREFTYPE_ZIP ) {
mask[0] |= 3; /* asume no_compression and old pgp */
compr_hack = 1;
}
#if 0
- log_debug("mask=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
+ log_debug("pref mask=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
(ulong)mask[7], (ulong)mask[6], (ulong)mask[5], (ulong)mask[4],
(ulong)mask[3], (ulong)mask[2], (ulong)mask[1], (ulong)mask[0]);
#endif
for(i=0; i < 8; i++ )
bits[i] &= mask[i];
#if 0
- log_debug("bits=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
+ log_debug("pref bits=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
(ulong)bits[7], (ulong)bits[6], (ulong)bits[5], (ulong)bits[4],
(ulong)bits[3], (ulong)bits[2], (ulong)bits[1], (ulong)bits[0]);
#endif
@@ -1119,28 +1158,42 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype )
*/
i = -1;
any = 0;
- if( pref ) {
- for(j=0; j+1 < npref; j+=2 ) {
- if( pref[j] == preftype ) {
- if( (bits[pref[j+1]/32] & (1<<(pref[j+1]%32))) ) {
- if( algo_available( preftype, pref[j+1] ) ) {
+
+ /* If we have personal prefs set, use them instead of the last key */
+ if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
+ prefs=opt.personal_cipher_prefs;
+ else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
+ prefs=opt.personal_digest_prefs;
+ else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)
+ prefs=opt.personal_compress_prefs;
+
+ if( prefs ) {
+ for(j=0; prefs[j].type; j++ ) {
+ if( prefs[j].type == preftype ) {
+ if( (bits[prefs[j].value/32] & (1<<(prefs[j].value%32))) ) {
+ if( algo_available( preftype, prefs[j].value, hint ) ) {
any = 1;
- i = pref[j+1];
+ i = prefs[j].value;
break;
}
}
}
}
}
- if( !pref || !any ) {
+ if( !prefs || !any ) {
for(j=0; j < 256; j++ )
if( (bits[j/32] & (1<<(j%32))) ) {
- if( algo_available( preftype, j ) ) {
+ if( algo_available( preftype, j, hint ) ) {
i = j;
break;
}
}
}
+
+ /* Can we use the requested algorithm? */
+ if(request>-1 && request==i)
+ return i;
+
#if 0
log_debug("prefs of type %d: selected %d\n", preftype, i );
#endif
@@ -1152,8 +1205,53 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype )
i = 1; /* yep; we can use compression algo 1 */
}
- gcry_free(pref);
+ /* "If you are building an authentication system, the recipient
+ may specify a preferred signing algorithm. However, the signer
+ would be foolish to use a weak algorithm simply because the
+ recipient requests it." RFC2440:13. If we settle on MD5, and
+ SHA1 is also available, use SHA1 instead. Of course, if the
+ user intentinally chose MD5 (by putting it in their personal
+ prefs), then we should do what they say. */
+
+ if(preftype==PREFTYPE_HASH &&
+ i==DIGEST_ALGO_MD5 && (bits[0] & (1<<DIGEST_ALGO_SHA1)))
+ {
+ i=DIGEST_ALGO_SHA1;
+
+ if(opt.personal_digest_prefs)
+ for(j=0; prefs[j].type; j++ )
+ if(opt.personal_digest_prefs[j].type==PREFTYPE_HASH &&
+ opt.personal_digest_prefs[j].value==DIGEST_ALGO_MD5)
+ {
+ i=DIGEST_ALGO_MD5;
+ break;
+ }
+ }
+
return i;
}
+/*
+ * Select the MDC flag from the pk_list. We can only use MDC if all recipients
+ * support this feature
+ */
+int
+select_mdc_from_pklist (PK_LIST pk_list)
+{
+ PK_LIST pkr;
+ if( !pk_list )
+ return 0;
+
+ for (pkr = pk_list; pkr; pkr = pkr->next) {
+ int mdc;
+
+ if (pkr->pk->user_id) /* selected by user ID */
+ mdc = pkr->pk->user_id->mdc_feature;
+ else
+ mdc = pkr->pk->mdc_feature;
+ if (!mdc)
+ return 0; /* at least one recipient does not support it */
+ }
+ return 1; /* can be used */
+}
diff --git a/g10/plaintext.c b/g10/plaintext.c
index 555dd1636..b12fb0f11 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -1,5 +1,5 @@
-/* plaintext.c - process an plaintext packet
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* plaintext.c - process plaintext packets
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -29,7 +29,7 @@
#endif
#include "util.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "options.h"
#include "packet.h"
#include "ttyio.h"
@@ -60,7 +60,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( nooutput )
;
else if( opt.outfile ) {
- fname = gcry_xmalloc( strlen( opt.outfile ) + 1);
+ fname = m_alloc( strlen( opt.outfile ) + 1);
strcpy(fname, opt.outfile );
}
else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
@@ -72,7 +72,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( !fname )
fname = ask_outfile_name( pt->name, pt->namelen );
if( !fname ) {
- rc = GPGERR_CREATE_FILE;
+ rc = G10ERR_CREATE_FILE;
goto leave;
}
}
@@ -89,31 +89,44 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
setmode ( fileno(fp) , O_BINARY );
#endif
}
- else if( !overwrite_filep( fname ) ) {
- rc = GPGERR_CREATE_FILE;
- goto leave;
+ else {
+ while( !overwrite_filep (fname) ) {
+ char *tmp = ask_outfile_name (NULL, 0);
+ if ( !tmp || !*tmp ) {
+ m_free (tmp);
+ rc = G10ERR_CREATE_FILE;
+ goto leave;
+ }
+ m_free (fname);
+ fname = tmp;
+ }
}
if( fp || nooutput )
;
else if( !(fp = fopen(fname,"wb")) ) {
- log_error("Error creating `%s': %s\n", fname, strerror(errno) );
- rc = GPGERR_CREATE_FILE;
+ log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
+ rc = G10ERR_CREATE_FILE;
+#ifdef __riscos__
+ if (errno == 106)
+ log_info("perhaps the output file has the same name as the input file?\n");
+#endif /* __riscos__ */
goto leave;
}
- if( pt->len ) {
+ if( !pt->is_partial ) {
+ /* we have an actual length (which might be zero). */
assert( !clearsig );
if( convert ) { /* text mode */
for( ; pt->len; pt->len-- ) {
if( (c = iobuf_get(pt->buf)) == -1 ) {
log_error("Problem reading source (%u bytes remaining)\n",
(unsigned)pt->len);
- rc = GPGERR_READ_FILE;
+ rc = G10ERR_READ_FILE;
goto leave;
}
if( mfx->md )
- gcry_md_putc(mfx->md, c );
+ md_putc(mfx->md, c );
#ifndef HAVE_DOSISH_SYSTEM
if( c == '\r' ) /* convert to native line ending */
continue; /* fixme: this hack might be too simple */
@@ -122,45 +135,45 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
goto leave;
}
}
}
}
else { /* binary mode */
- byte *buffer = gcry_xmalloc( 32768 );
+ byte *buffer = m_alloc( 32768 );
while( pt->len ) {
int len = pt->len > 32768 ? 32768 : pt->len;
len = iobuf_read( pt->buf, buffer, len );
if( len == -1 ) {
log_error("Problem reading source (%u bytes remaining)\n",
(unsigned)pt->len);
- rc = GPGERR_READ_FILE;
- gcry_free( buffer );
+ rc = G10ERR_READ_FILE;
+ m_free( buffer );
goto leave;
}
if( mfx->md )
- gcry_md_write( mfx->md, buffer, len );
+ md_write( mfx->md, buffer, len );
if( fp ) {
if( fwrite( buffer, 1, len, fp ) != len ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
- gcry_free( buffer );
+ rc = G10ERR_WRITE_FILE;
+ m_free( buffer );
goto leave;
}
}
pt->len -= len;
}
- gcry_free( buffer );
+ m_free( buffer );
}
}
else if( !clearsig ) {
if( convert ) { /* text mode */
while( (c = iobuf_get(pt->buf)) != -1 ) {
if( mfx->md )
- gcry_md_putc(mfx->md, c );
+ md_putc(mfx->md, c );
#ifndef HAVE_DOSISH_SYSTEM
if( convert && c == '\r' )
continue; /* fixme: this hack might be too simple */
@@ -169,14 +182,14 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
goto leave;
}
}
}
}
else { /* binary mode */
- byte *buffer = gcry_xmalloc( 32768 );
+ byte *buffer = m_alloc( 32768 );
int eof;
for( eof=0; !eof; ) {
/* Why do we check for len < 32768:
@@ -191,18 +204,18 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( len < 32768 )
eof = 1;
if( mfx->md )
- gcry_md_write( mfx->md, buffer, len );
+ md_write( mfx->md, buffer, len );
if( fp ) {
if( fwrite( buffer, 1, len, fp ) != len ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
- gcry_free( buffer );
+ rc = G10ERR_WRITE_FILE;
+ m_free( buffer );
goto leave;
}
}
}
- gcry_free( buffer );
+ m_free( buffer );
}
pt->buf = NULL;
}
@@ -214,15 +227,15 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
goto leave;
}
}
if( !mfx->md )
continue;
if( state == 2 ) {
- gcry_md_putc(mfx->md, '\r' );
- gcry_md_putc(mfx->md, '\n' );
+ md_putc(mfx->md, '\r' );
+ md_putc(mfx->md, '\n' );
state = 0;
}
if( !state ) {
@@ -231,18 +244,18 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
else if( c == '\n' )
state = 2;
else
- gcry_md_putc(mfx->md, c );
+ md_putc(mfx->md, c );
}
else if( state == 1 ) {
if( c == '\n' )
state = 2;
else {
- gcry_md_putc(mfx->md, '\r' );
+ md_putc(mfx->md, '\r' );
if( c == '\r' )
state = 1;
else {
state = 0;
- gcry_md_putc(mfx->md, c );
+ md_putc(mfx->md, c );
}
}
}
@@ -253,7 +266,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
if( fp && fp != stdout && fclose(fp) ) {
log_error("Error closing `%s': %s\n", fname, strerror(errno) );
fp = NULL;
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
goto leave;
}
fp = NULL;
@@ -261,12 +274,12 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
leave:
if( fp && fp != stdout )
fclose(fp);
- gcry_free(fname);
+ m_free(fname);
return rc;
}
static void
-do_hash( GCRY_MD_HD md, GCRY_MD_HD md2, IOBUF fp, int textmode )
+do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
{
text_filter_context_t tfx;
int c;
@@ -280,27 +293,27 @@ do_hash( GCRY_MD_HD md, GCRY_MD_HD md2, IOBUF fp, int textmode )
int lc = -1;
while( (c = iobuf_get(fp)) != -1 ) {
if( c == '\n' && lc == '\r' )
- gcry_md_putc(md2, c);
+ md_putc(md2, c);
else if( c == '\n' ) {
- gcry_md_putc(md2, '\r');
- gcry_md_putc(md2, c);
+ md_putc(md2, '\r');
+ md_putc(md2, c);
}
else if( c != '\n' && lc == '\r' ) {
- gcry_md_putc(md2, '\n');
- gcry_md_putc(md2, c);
+ md_putc(md2, '\n');
+ md_putc(md2, c);
}
else
- gcry_md_putc(md2, c);
+ md_putc(md2, c);
if( md )
- gcry_md_putc(md, c );
+ md_putc(md, c );
lc = c;
}
}
else {
while( (c = iobuf_get(fp)) != -1 ) {
if( md )
- gcry_md_putc(md, c );
+ md_putc(md, c );
}
}
}
@@ -311,7 +324,7 @@ do_hash( GCRY_MD_HD md, GCRY_MD_HD md2, IOBUF fp, int textmode )
* INFILE is the name of the input file.
*/
int
-ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
+ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
const char *inname, int textmode )
{
char *answer = NULL;
@@ -323,12 +336,12 @@ ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
int any=0;
tty_printf(_("Detached signature.\n"));
do {
- gcry_free(answer);
+ m_free(answer);
answer = cpr_get("detached_signature.filename",
_("Please enter name of data file: "));
cpr_kill_prompt();
if( any && !*answer ) {
- rc = GPGERR_READ_FILE;
+ rc = G10ERR_READ_FILE;
goto leave;
}
fp = iobuf_open(answer);
@@ -338,7 +351,7 @@ ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
}
else if( !fp ) {
log_error("can't open `%s': %s\n", answer, strerror(errno) );
- rc = GPGERR_READ_FILE;
+ rc = G10ERR_READ_FILE;
goto leave;
}
} while( !fp );
@@ -355,7 +368,7 @@ ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
leave:
- gcry_free(answer);
+ m_free(answer);
return rc;
}
@@ -366,11 +379,11 @@ ask_for_detached_datafile( GCRY_MD_HD md, GCRY_MD_HD md2,
* If FILES is NULL, hash stdin.
*/
int
-hash_datafiles( GCRY_MD_HD md, GCRY_MD_HD md2, STRLIST files,
+hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
const char *sigfilename, int textmode )
{
IOBUF fp;
- STRLIST sl=NULL;
+ STRLIST sl;
if( !files ) {
/* check whether we can open the signed material */
@@ -380,28 +393,26 @@ hash_datafiles( GCRY_MD_HD md, GCRY_MD_HD md2, STRLIST files,
iobuf_close(fp);
return 0;
}
- /* no we can't (no sigfile) - read signed stuff from stdin */
- add_to_strlist( &sl, "-");
+ log_error (_("no signed data\n"));
+ return G10ERR_OPEN_FILE;
}
- else
- sl = files;
- for( ; sl; sl = sl->next ) {
+
+ for (sl=files; sl; sl = sl->next ) {
fp = iobuf_open( sl->d );
if( !fp ) {
log_error(_("can't open signed data `%s'\n"),
print_fname_stdin(sl->d));
- if( !files )
- free_strlist(sl);
- return GPGERR_OPEN_FILE;
+ return G10ERR_OPEN_FILE;
}
do_hash( md, md2, fp, textmode );
iobuf_close(fp);
}
- if( !files )
- free_strlist(sl);
return 0;
}
+
+
+
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 646aca017..2c8771c27 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -1,5 +1,5 @@
/* pubkey-enc.c - public key encoded packet handling
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,12 +23,13 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "packet.h"
+#include "mpi.h"
#include "keydb.h"
#include "trustdb.h"
+#include "cipher.h"
#include "status.h"
#include "options.h"
#include "main.h"
@@ -38,66 +39,31 @@ static int get_it( PKT_pubkey_enc *k,
DEK *dek, PKT_secret_key *sk, u32 *keyid );
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
+/* check that the given algo is mentioned in one of the valid user IDs */
static int
-pk_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+is_algo_in_prefs ( KBNODE keyblock, preftype_t type, int algo )
{
- GCRY_SEXP s_skey, s_data, s_plain;
- int rc;
-
- *result = NULL;
- /* make a sexp from skey */
- if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3] );
- }
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4], skey[5] );
- }
- else
- return GPGERR_PUBKEY_ALGO;
-
- if ( rc )
- BUG ();
-
- /* put data into a S-Exp s_data */
- if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_data, NULL,
- "(enc-val(elg(a%m)(b%m)))", data[0], data[1] );
+ KBNODE k;
+
+ for (k=keyblock; k; k=k->next) {
+ if (k->pkt->pkttype == PKT_USER_ID) {
+ PKT_user_id *uid = k->pkt->pkt.user_id;
+ prefitem_t *prefs = uid->prefs;
+
+ if (uid->created && prefs &&
+ !uid->is_revoked && !uid->is_expired ) {
+ for (; prefs->type; prefs++ )
+ if (prefs->type == type && prefs->value == algo)
+ return 1;
+ }
+ }
}
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &s_data, NULL,
- "(enc-val(rsa(a%m)))", data[0] );
- }
- else
- BUG();
-
- if ( rc )
- BUG ();
-
- rc = gcry_pk_decrypt( &s_plain, s_data, s_skey );
- gcry_sexp_release( s_skey );
- gcry_sexp_release( s_data);
- if( rc )
- return rc;
-
- *result = gcry_sexp_nth_mpi( s_plain, 0, 0 );
- gcry_sexp_release( s_plain );
- if( !*result )
- return -1; /* oops */
-
return 0;
}
/****************
- * Get the session key from a pubkey enc paket and return
+ * Get the session key from a pubkey enc packet and return
* it in DEK, which should have been allocated in secure memory.
*/
int
@@ -106,12 +72,12 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
PKT_secret_key *sk = NULL;
int rc;
- rc = openpgp_pk_test_algo( k->pubkey_algo, 0 );
+ rc = check_pubkey_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC);
if( rc )
goto leave;
if( (k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets ) {
- sk = gcry_xcalloc( 1, sizeof *sk );
+ sk = m_alloc_clear( sizeof *sk );
sk->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/
if( !(rc = get_seckey( sk, k->keyid )) )
rc = get_it( k, dek, sk, k->keyid );
@@ -123,17 +89,17 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
for(;;) {
if( sk )
free_secret_key( sk );
- sk = gcry_xcalloc( 1, sizeof *sk );
+ sk = m_alloc_clear( sizeof *sk );
rc=enum_secret_keys( &enum_context, sk, 1);
if( rc ) {
- rc = GPGERR_NO_SECKEY;
+ rc = G10ERR_NO_SECKEY;
break;
}
if( sk->pubkey_algo != k->pubkey_algo )
continue;
keyid_from_sk( sk, keyid );
- log_info(_("anonymous receiver; trying secret key %08lX ...\n"),
- (ulong)keyid[1] );
+ log_info(_("anonymous recipient; trying secret key %08lX ...\n"),
+ (ulong)keyid[1] );
rc = check_secret_key( sk, 1 ); /* ask only once */
if( !rc )
rc = get_it( k, dek, sk, keyid );
@@ -153,22 +119,19 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
static int
-get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
+get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid )
{
int rc;
MPI plain_dek = NULL;
byte *frame = NULL;
- unsigned int n;
- size_t nframe;
+ unsigned n, nframe;
u16 csum, csum2;
- rc = pk_decrypt(sk->pubkey_algo, &plain_dek, k->data, sk->skey );
+ rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey );
if( rc )
goto leave;
- if( gcry_mpi_aprint( GCRYMPI_FMT_USG, &frame, &nframe, plain_dek ) )
- BUG();
-
- mpi_release( plain_dek ); plain_dek = NULL;
+ frame = mpi_get_buffer( plain_dek, &nframe, NULL );
+ mpi_free( plain_dek ); plain_dek = NULL;
/* Now get the DEK (data encryption key) from the frame
*
@@ -180,8 +143,7 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
*
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
*
- * (mpi_get_buffer already removed the leading zero - still true
- * for gcry_mpi_aprint(0 which is used now?)
+ * (mpi_get_buffer already removed the leading zero).
*
* RND are non-zero randow bytes.
* A is the cipher algorithm
@@ -192,35 +154,37 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
log_hexdump("DEK frame:", frame, nframe );
n=0;
if( n + 7 > nframe )
- { rc = GPGERR_WRONG_SECKEY; goto leave; }
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
if( frame[n] == 1 && frame[nframe-1] == 2 ) {
log_info(_("old encoding of the DEK is not supported\n"));
- rc = GPGERR_CIPHER_ALGO;
+ rc = G10ERR_CIPHER_ALGO;
goto leave;
}
if( frame[n] != 2 ) /* somethink is wrong */
- { rc = GPGERR_WRONG_SECKEY; goto leave; }
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
;
n++; /* and the zero byte */
if( n + 4 > nframe )
- { rc = GPGERR_WRONG_SECKEY; goto leave; }
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
dek->keylen = nframe - (n+1) - 2;
dek->algo = frame[n++];
- if( dek->algo == GCRY_CIPHER_IDEA )
+ if( dek->algo == CIPHER_ALGO_IDEA )
write_status(STATUS_RSA_OR_IDEA);
- rc = openpgp_cipher_test_algo( dek->algo );
+ rc = check_cipher_algo( dek->algo );
if( rc ) {
- if( !opt.quiet && rc == GPGERR_CIPHER_ALGO ) {
- log_info(_("cipher algorithm %d is unknown or disabled\n"),
- dek->algo);
+ if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) {
+ log_info(_("cipher algorithm %d%s is unknown or disabled\n"),
+ dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":"");
+ if(dek->algo==CIPHER_ALGO_IDEA)
+ idea_cipher_warn(0);
}
dek->algo = 0;
goto leave;
}
- if( dek->keylen != gcry_cipher_get_algo_keylen( dek->algo ) ) {
- rc = GPGERR_WRONG_SECKEY;
+ if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) {
+ rc = G10ERR_WRONG_SECKEY;
goto leave;
}
@@ -231,53 +195,102 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
for( csum2=0, n=0; n < dek->keylen; n++ )
csum2 += dek->key[n];
if( csum != csum2 ) {
- rc = GPGERR_WRONG_SECKEY;
+ rc = G10ERR_WRONG_SECKEY;
goto leave;
}
if( DBG_CIPHER )
log_hexdump("DEK is:", dek->key, dek->keylen );
/* check that the algo is in the preferences and whether it has expired */
{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- if( (rc = get_pubkey( pk, keyid )) )
- log_error("public key problem: %s\n", gpg_errstr(rc) );
- else if( !pk->local_id && query_trust_record(pk) )
- log_error("can't check algorithm against preferences\n");
- else if( dek->algo != GCRY_CIPHER_3DES
- && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) {
+ PKT_public_key *pk = NULL;
+ KBNODE pkb = get_pubkeyblock (keyid);
+
+ if( !pkb ) {
+ rc = -1;
+ log_error("oops: public key not found for preference check\n");
+ }
+ else if( pkb->pkt->pkt.public_key->selfsigversion > 3
+ && dek->algo != CIPHER_ALGO_3DES
+ && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ) ) {
/* Don't print a note while we are not on verbose mode,
* the cipher is blowfish and the preferences have twofish
* listed */
- if( opt.verbose || dek->algo != GCRY_CIPHER_BLOWFISH
- || !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM,
- GCRY_CIPHER_TWOFISH ) )
+ if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH
+ || !is_algo_in_prefs( pkb, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH))
log_info(_(
"NOTE: cipher algorithm %d not found in preferences\n"),
dek->algo );
}
-
- if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) {
- log_info(_("NOTE: secret key %08lX expired at %s\n"),
- (ulong)keyid[1], asctimestamp( pk->expiredate) );
- }
-
- /* FIXME: check wheter the key has been revoked and display
- * the revocation reason. Actually the user should know this himself,
- * but the sender might not know already and therefor the user
- * should get a notice that an revoked key has been used to decode
- * the message. The user can than watch out for snakes send by
- * one of those Eves outside his paradise :-)
- */
- free_public_key( pk );
+ if (!rc) {
+ KBNODE k;
+
+ for (k=pkb; k; k = k->next) {
+ if (k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){
+ u32 aki[2];
+ keyid_from_pk(k->pkt->pkt.public_key, aki);
+
+ if (aki[0]==keyid[0] && aki[1]==keyid[1]) {
+ pk = k->pkt->pkt.public_key;
+ break;
+ }
+ }
+ }
+ if (!pk)
+ BUG ();
+ if ( pk->expiredate && pk->expiredate <= make_timestamp() ) {
+ log_info(_("NOTE: secret key %08lX expired at %s\n"),
+ (ulong)keyid[1], asctimestamp( pk->expiredate) );
+ }
+ }
+
+ if ( pk->is_revoked ) {
+ log_info( _("NOTE: key has been revoked") );
+ putc( '\n', log_stream() );
+ show_revocation_reason( pk, 1 );
+ }
+
+ release_kbnode (pkb);
rc = 0;
}
leave:
- mpi_release(plain_dek);
- gcry_free(frame);
+ mpi_free(plain_dek);
+ m_free(frame);
return rc;
}
+/****************
+ * Get the session key from the given string.
+ * String is supposed to be formatted as this:
+ * <algo-id>:<even-number-of-hex-digits>
+ */
+int
+get_override_session_key( DEK *dek, const char *string )
+{
+ const char *s;
+ int i;
+
+ if ( !string )
+ return G10ERR_BAD_KEY;
+ dek->algo = atoi(string);
+ if ( dek->algo < 1 )
+ return G10ERR_BAD_KEY;
+ if ( !(s = strchr ( string, ':' )) )
+ return G10ERR_BAD_KEY;
+ s++;
+ for(i=0; i < DIM(dek->key) && *s; i++, s +=2 ) {
+ int c = hextobyte ( s );
+ if (c == -1)
+ return G10ERR_BAD_KEY;
+ dek->key[i] = c;
+ }
+ if ( *s )
+ return G10ERR_BAD_KEY;
+ dek->keylen = i;
+ return 0;
+}
+
diff --git a/g10/revoke.c b/g10/revoke.c
index e988e5e62..ca67d80e5 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -1,5 +1,5 @@
/* revoke.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -30,7 +30,7 @@
#include "packet.h"
#include "errors.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "ttyio.h"
@@ -52,25 +52,274 @@ revocation_reason_build_cb( PKT_signature *sig, void *opaque )
byte *buffer;
size_t buflen = 1;
+ if(!reason)
+ return 0;
+
if( reason->desc ) {
ud = native_to_utf8( reason->desc );
buflen += strlen(ud);
}
- buffer = gcry_xmalloc( buflen );
+ buffer = m_alloc( buflen );
*buffer = reason->code;
if( ud ) {
memcpy(buffer+1, ud, strlen(ud) );
- gcry_free( ud );
+ m_free( ud );
}
build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
- gcry_free( buffer );
+ m_free( buffer );
return 0;
}
/****************
+ * Generate a revocation certificate for UNAME via a designated revoker
+ */
+int
+gen_desig_revoke( const char *uname )
+{
+ int rc = 0;
+ armor_filter_context_t afx;
+ PACKET pkt;
+ PKT_public_key *pk = NULL;
+ PKT_secret_key *sk = NULL;
+ PKT_signature *sig = NULL;
+ IOBUF out = NULL;
+ struct revocation_reason_info *reason = NULL;
+ KEYDB_HANDLE kdbhd;
+ KEYDB_SEARCH_DESC desc;
+ KBNODE keyblock=NULL,node;
+ u32 keyid[2];
+ int i,any=0;
+
+ if( opt.batch ) {
+ log_error(_("sorry, can't do this in batch mode\n"));
+ return G10ERR_GENERAL;
+ }
+
+ memset( &afx, 0, sizeof afx);
+
+ kdbhd = keydb_new (0);
+ classify_user_id (uname, &desc);
+ rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
+ if (rc) {
+ log_error (_("key `%s' not found: %s\n"),uname, g10_errstr (rc));
+ goto leave;
+ }
+
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
+ if( rc ) {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ /* To parse the revkeys */
+ merge_keys_and_selfsig(keyblock);
+
+ /* get the key from the keyblock */
+ node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+ if( !node )
+ BUG ();
+
+ pk=node->pkt->pkt.public_key;
+
+ keyid_from_pk(pk,keyid);
+
+ /* Are we a designated revoker for this key? */
+
+ if(!pk->revkey && pk->numrevkeys)
+ BUG();
+
+ for(i=0;i<pk->numrevkeys;i++)
+ {
+ if(sk)
+ free_secret_key(sk);
+
+ sk=m_alloc_clear(sizeof(*sk));
+
+ rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
+
+ /* We have the revocation key */
+ if(!rc)
+ {
+ size_t n;
+ char *p;
+ u32 sk_keyid[2];
+ PKT_user_id *uid=NULL;
+ PKT_signature *selfsig=NULL;
+
+ any=1;
+ keyid_from_sk(sk,sk_keyid);
+
+ tty_printf("\npub %4u%c/%08lX %s ",
+ nbits_from_pk( pk ),
+ pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk(pk) );
+
+ p = get_user_id( keyid, &n );
+ tty_print_utf8_string( p, n );
+ m_free(p);
+ tty_printf("\n\n");
+
+ tty_printf(_("To be revoked by:\n"));
+
+ tty_printf("\nsec %4u%c/%08lX %s ",
+ nbits_from_sk( sk ),
+ pubkey_letter( sk->pubkey_algo ),
+ (ulong)sk_keyid[1], datestr_from_sk(sk) );
+
+ p = get_user_id( sk_keyid, &n );
+ tty_print_utf8_string( p, n );
+ m_free(p);
+ tty_printf("\n\n");
+
+ if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
+ _("Create a revocation certificate for this key? ")) )
+ continue;
+
+ /* get the reason for the revocation (this is always v4) */
+ reason = ask_revocation_reason( 1, 0, 1 );
+ if( !reason )
+ continue;
+
+ rc = check_secret_key( sk, 0 );
+ if( rc )
+ continue;
+
+ if( !opt.armor )
+ tty_printf(_("ASCII armored output forced.\n"));
+
+ if( (rc = open_outfile( NULL, 0, &out )) )
+ goto leave;
+
+ afx.what = 1;
+ afx.hdrlines = "Comment: A revocation certificate should follow\n";
+ iobuf_push_filter( out, armor_filter, &afx );
+
+ /* create it */
+ rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
+ 0, 0, 0,
+ revocation_reason_build_cb, reason );
+ if( rc ) {
+ log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
+ goto leave;
+ }
+
+ /* Spit out a minimal pk as well, since otherwise there is
+ no way to know which key to attach this revocation
+ to. */
+
+ node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
+ if(!node)
+ {
+ rc=G10ERR_GENERAL;
+ log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
+ goto leave;
+ }
+
+ pkt = *node->pkt;
+ rc=build_packet(out,&pkt);
+ if( rc ) {
+ log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ init_packet( &pkt );
+ pkt.pkttype = PKT_SIGNATURE;
+ pkt.pkt.signature = sig;
+
+ rc = build_packet( out, &pkt );
+ if( rc ) {
+ log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ while(!selfsig)
+ {
+ KBNODE signode;
+
+ node=find_next_kbnode(node,PKT_USER_ID);
+ if(!node)
+ {
+ /* We're out of user IDs - none were
+ self-signed. */
+ if(uid)
+ break;
+ else
+ {
+ rc=G10ERR_GENERAL;
+ log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
+ goto leave;
+ }
+ }
+
+ if(node->pkt->pkt.user_id->attrib_data)
+ continue;
+
+ uid=node->pkt->pkt.user_id;
+ signode=node;
+
+ while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
+ {
+ if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
+ keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
+ IS_UID_SIG(signode->pkt->pkt.signature))
+ {
+ selfsig=signode->pkt->pkt.signature;
+ break;
+ }
+ }
+ }
+
+ pkt.pkttype = PKT_USER_ID;
+ pkt.pkt.user_id = uid;
+
+ rc = build_packet( out, &pkt );
+ if( rc ) {
+ log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ if(selfsig)
+ {
+ pkt.pkttype = PKT_SIGNATURE;
+ pkt.pkt.signature = selfsig;
+
+ rc = build_packet( out, &pkt );
+ if( rc ) {
+ log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+ }
+
+ /* and issue a usage notice */
+ tty_printf(_("Revocation certificate created.\n"));
+ break;
+ }
+ }
+
+ if(!any)
+ log_error(_("no revocation keys found for `%s'\n"),uname);
+
+ leave:
+ if( pk )
+ free_public_key( pk );
+ if( sk )
+ free_secret_key( sk );
+ if( sig )
+ free_seckey_enc( sig );
+
+ if( rc )
+ iobuf_cancel(out);
+ else
+ iobuf_close(out);
+ release_revocation_reason_info( reason );
+ return rc;
+}
+
+
+/****************
* Generate a revocation certificate for UNAME
*/
int
@@ -78,7 +327,6 @@ gen_revoke( const char *uname )
{
int rc = 0;
armor_filter_context_t afx;
- compress_filter_context_t zfx;
PACKET pkt;
PKT_secret_key *sk; /* used as pointer into a kbnode */
PKT_public_key *pk = NULL;
@@ -87,34 +335,40 @@ gen_revoke( const char *uname )
IOBUF out = NULL;
KBNODE keyblock = NULL;
KBNODE node;
+ KEYDB_HANDLE kdbhd;
struct revocation_reason_info *reason = NULL;
+ KEYDB_SEARCH_DESC desc;
if( opt.batch ) {
log_error(_("sorry, can't do this in batch mode\n"));
- return GPGERR_GENERAL;
+ return G10ERR_GENERAL;
}
-
memset( &afx, 0, sizeof afx);
- memset( &zfx, 0, sizeof zfx);
init_packet( &pkt );
+ /* search the userid:
+ * We don't want the whole getkey stuff here but the entire keyblock
+ */
+ kdbhd = keydb_new (1);
+ classify_user_id (uname, &desc);
+ rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
+ if (rc) {
+ log_error (_("secret key `%s' not found: %s\n"),
+ uname, g10_errstr (rc));
+ goto leave;
+ }
- /* search the userid */
- rc = find_secret_keyblock_byname( &keyblock, uname );
+ rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
- log_error(_("secret key for user `%s' not found: %s\n"),
- uname, gpg_errstr(rc) );
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
node = find_kbnode( keyblock, PKT_SECRET_KEY );
- if( !node ) { /* maybe better to use log_bug ? */
- log_error(_("Oops; secret key not found anymore!\n"));
- rc = GPGERR_GENERAL;
- goto leave;
- }
+ if( !node )
+ BUG ();
/* fixme: should make a function out of this stuff,
* it's used all over the source */
@@ -123,23 +377,25 @@ gen_revoke( const char *uname )
tty_printf("\nsec %4u%c/%08lX %s ",
nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
- sk_keyid[1], datestr_from_sk(sk) );
+ (ulong)sk_keyid[1], datestr_from_sk(sk) );
{
size_t n;
char *p = get_user_id( sk_keyid, &n );
tty_print_utf8_string( p, n );
- gcry_free(p);
+ m_free(p);
tty_printf("\n");
}
- pk = gcry_xcalloc( 1, sizeof *pk );
+ pk = m_alloc_clear( sizeof *pk );
+
+ /* FIXME: We should get the public key direct from the secret one */
rc = get_pubkey( pk, sk_keyid );
if( rc ) {
- log_error(_("no corresponding public key: %s\n"), gpg_errstr(rc) );
+ log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
goto leave;
}
if( cmp_public_secret_key( pk, sk ) ) {
log_error(_("public key does not match secret key!\n") );
- rc = GPGERR_GENERAL;
+ rc = G10ERR_GENERAL;
goto leave;
}
@@ -150,17 +406,19 @@ gen_revoke( const char *uname )
goto leave;
}
- /* get the reason for the revocation */
- reason = ask_revocation_reason( 1, 0, 1 );
- if( !reason ) { /* user decided to cancel */
+ if(sk->version>=4 || opt.force_v4_certs) {
+ /* get the reason for the revocation */
+ reason = ask_revocation_reason( 1, 0, 1 );
+ if( !reason ) { /* user decided to cancel */
rc = 0;
goto leave;
+ }
}
switch( is_secret_key_protected( sk ) ) {
case -1:
log_error(_("unknown protection algorithm\n"));
- rc = GPGERR_PUBKEY_ALGO;
+ rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf(_("NOTE: This key is not protected!\n"));
@@ -185,10 +443,10 @@ gen_revoke( const char *uname )
/* create it */
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
- revocation_reason_build_cb,
- reason );
+ opt.force_v4_certs?4:0, 0, 0,
+ revocation_reason_build_cb, reason );
if( rc ) {
- log_error(_("make_keysig_packet failed: %s\n"), gpg_errstr(rc));
+ log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
goto leave;
}
init_packet( &pkt );
@@ -197,7 +455,7 @@ gen_revoke( const char *uname )
rc = build_packet( out, &pkt );
if( rc ) {
- log_error(_("build_packet failed: %s\n"), gpg_errstr(rc) );
+ log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
goto leave;
}
@@ -217,6 +475,7 @@ gen_revoke( const char *uname )
if( sig )
free_seckey_enc( sig );
release_kbnode( keyblock );
+ keydb_release (kdbhd);
if( rc )
iobuf_cancel(out);
else
@@ -230,20 +489,22 @@ gen_revoke( const char *uname )
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint )
{
- int code;
+ int code=-1;
char *description = NULL;
struct revocation_reason_info *reason;
+ const char *text_0 = _("No reason specified");
const char *text_1 = _("Key has been compromised");
const char *text_2 = _("Key is superseded");
const char *text_3 = _("Key is no longer used");
- const char *text_4 = _("User ID is non longer valid");
+ const char *text_4 = _("User ID is no longer valid");
const char *code_text = NULL;
do {
- gcry_free(description);
+ m_free(description);
description = NULL;
tty_printf(_("Please select the reason for the revocation:\n"));
+ tty_printf( " 0 = %s\n", text_0 );
if( key_rev )
tty_printf(" 1 = %s\n", text_1 );
if( key_rev )
@@ -252,29 +513,31 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
tty_printf(" 3 = %s\n", text_3 );
if( cert_rev )
tty_printf(" 4 = %s\n", text_4 );
- tty_printf( " 0 = %s\n", _("Cancel") );
+ tty_printf( " Q = %s\n", _("Cancel") );
if( hint )
tty_printf(_("(Probably you want to select %d here)\n"), hint );
- for(code = 0; !code;) {
+ while(code==-1) {
int n;
char *answer = cpr_get("ask_revocation_reason.code",
_("Your decision? "));
trim_spaces( answer );
cpr_kill_prompt();
- if( *answer == 'q' || *answer == 'Q' )
- n = 0;
- else if( !isdigit( *answer ) )
- n = -1;
- else if( hint && !*answer )
+ if( *answer == 'q' || *answer == 'Q')
+ return NULL; /* cancel */
+ if( hint && !*answer )
n = hint;
+ else if(!isdigit( *answer ) )
+ n = -1;
else
n = atoi(answer);
- gcry_free(answer);
- if( !n )
- return NULL; /* cancel */
+ m_free(answer);
+ if( n == 0 ) {
+ code = 0x00; /* no particular reason */
+ code_text = text_0;
+ }
else if( key_rev && n == 1 ) {
- code = 0x02; /* key has been compromised */
+ code = 0x02; /* key has been compromised */
code_text = text_1;
}
else if( key_rev && n == 2 ) {
@@ -286,7 +549,7 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
code_text = text_3;
}
else if( cert_rev && n == 4 ) {
- code = 0x20; /* uid is non longer valid */
+ code = 0x20; /* uid is no longer valid */
code_text = text_4;
}
else
@@ -300,25 +563,25 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
trim_trailing_ws( answer, strlen(answer) );
cpr_kill_prompt();
if( !*answer ) {
- gcry_free(answer);
+ m_free(answer);
break;
}
{
char *p = make_printable_string( answer, strlen(answer), 0 );
- gcry_free(answer);
+ m_free(answer);
answer = p;
}
if( !description )
- description = gcry_xstrdup(answer);
+ description = m_strdup(answer);
else {
- char *p = gcry_xmalloc( strlen(description) + strlen(answer) + 2 );
+ char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
- gcry_free(description);
+ m_free(description);
description = p;
}
- gcry_free(answer);
+ m_free(answer);
}
tty_printf(_("Reason for revocation: %s\n"), code_text );
@@ -330,7 +593,7 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
} while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
_("Is this okay? ")) );
- reason = gcry_xmalloc( sizeof *reason );
+ reason = m_alloc( sizeof *reason );
reason->code = code;
reason->desc = description;
return reason;
@@ -340,8 +603,7 @@ void
release_revocation_reason_info( struct revocation_reason_info *reason )
{
if( reason ) {
- gcry_free( reason->desc );
- gcry_free( reason );
+ m_free( reason->desc );
+ m_free( reason );
}
}
-
diff --git a/g10/ringedit.c b/g10/ringedit.c
deleted file mode 100644
index 6d5b3e0e4..000000000
--- a/g10/ringedit.c
+++ /dev/null
@@ -1,1360 +0,0 @@
-/* ringedit.c - Function for key ring editing
- * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-/****************
- * This module supplies function for:
- *
- * - Search for a key block (pubkey and all other stuff) and return a
- * handle for it.
- *
- * - Lock/Unlock a key block
- *
- * - Read a key block into a tree
- *
- * - Update a key block
- *
- * - Insert a new key block
- *
- * - Delete a key block
- *
- */
-
-
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h> /* for truncate */
-#include <assert.h>
-
-#include <gcrypt.h>
-#include "util.h"
-#include "packet.h"
-#include "iobuf.h"
-#include "keydb.h"
-#include "host2net.h"
-#include "options.h"
-#include "main.h"
-#include "i18n.h"
-#include "kbx.h"
-
-
-
-
-struct resource_table_struct {
- int used;
- int secret; /* this is a secret keyring */
- char *fname;
- IOBUF iobuf;
- enum resource_type rt;
- DOTLOCK lockhd;
- int is_locked;
-};
-typedef struct resource_table_struct RESTBL;
-
-
-struct keyblock_pos_struct {
- int resno; /* resource number */
- enum resource_type rt;
- ulong offset; /* position information */
- unsigned count; /* length of the keyblock in packets */
- IOBUF fp; /* used by enum_keyblocks */
- int secret; /* working on a secret keyring */
- PACKET *pkt; /* ditto */
- int valid;
- ulong save_offset;
-};
-
-
-
-
-#define MAX_RESOURCES 10
-static RESTBL resource_table[MAX_RESOURCES];
-static int default_public_resource;
-static int default_secret_resource;
-
-static int keyring_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs );
-static int keyring_copy( KBPOS kbpos, int mode, KBNODE root );
-
-static int do_kbxf_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs );
-static int do_kbxf_copy( KBPOS kbpos, int mode, KBNODE root );
-
-
-static RESTBL *
-check_pos( KBPOS kbpos )
-{
- if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
- return NULL;
- if( !resource_table[kbpos->resno].used )
- return NULL;
- return resource_table + kbpos->resno;
-}
-
-
-/****************
- * Hmmm, how to avoid deadlock? They should not happen if everyone
- * locks the key resources in the same order; but who knows.
- * A solution is to use only one lock file in the gnupg homedir but
- * what will happen with key resources which normally don't belong
- * to the gpg homedir?
- */
-static void
-lock_rentry( RESTBL *rentry )
-{
- if( !rentry->lockhd ) {
- rentry->lockhd = create_dotlock( rentry->fname );
- if( !rentry->lockhd )
- log_fatal("can't allocate lock for `%s'\n", rentry->fname );
- rentry->is_locked = 0;
- }
- if( !rentry->is_locked ) {
- if( make_dotlock( rentry->lockhd, -1 ) )
- log_fatal("can't lock `%s'\n", rentry->fname );
- rentry->is_locked = 1;
- }
-}
-
-static void
-unlock_rentry( RESTBL *rentry )
-{
- if( opt.lock_once )
- return;
- if( !release_dotlock( rentry->lockhd ) )
- rentry->is_locked = 0;
-}
-
-
-/****************************************************************
- ****************** public functions ****************************
- ****************************************************************/
-
-/****************
- * Get the name of the keyrings, start with a sequence number pointing to a 0.
- */
-const char *
-enum_keyblock_resources( int *sequence, int secret )
-{
- int i = *sequence;
- const char *name = NULL;
-
- for(; i < MAX_RESOURCES; i++ )
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( resource_table[i].fname ) {
- name = resource_table[i].fname;
- break;
- }
- }
- *sequence = ++i;
- return name;
-}
-
-
-/****************
- * Register a resource (which currently may only be a keyring file).
- * The first keyring which is added by this function is
- * created if it does not exist.
- * Note: this function may be called before secure memory is
- * available.
- */
-int
-add_keyblock_resource( const char *url, int force, int secret )
-{
- static int any_secret, any_public;
- const char *resname = url;
- IOBUF iobuf = NULL;
- int i;
- char *filename = NULL;
- int rc = 0;
- enum resource_type rt = rt_UNKNOWN;
-
-
- /* Do we have an URL?
- * gnupg-kbxf:filename := this is a KBX file resource
- * gnupg-ring:filename := this is a plain keyring
- * filename := See what is is, but create as plain keyring.
- */
- if( strlen( resname ) > 11 ) {
- if( !strncmp( resname, "gnupg-ring:", 11 ) ) {
- rt = rt_RING;
- resname += 11;
- }
- else if( !strncmp( resname, "gnupg-kbxf:", 11 ) ) {
- rt = rt_KBXF;
- resname += 11;
- }
- #ifndef HAVE_DRIVE_LETTERS
- else if( strchr( resname, ':' ) ) {
- log_error("%s: invalid URL\n", url );
- rc = GPGERR_GENERAL;
- goto leave;
- }
- #endif
- }
-
- if( *resname != '/' ) { /* do tilde expansion etc */
- if( strchr(resname, '/') )
- filename = make_filename(resname, NULL);
- else
- filename = make_filename(opt.homedir, resname, NULL);
- }
- else
- filename = gcry_xstrdup( resname );
-
- if( !force )
- force = secret? !any_secret : !any_public;
-
- for(i=0; i < MAX_RESOURCES; i++ )
- if( !resource_table[i].used )
- break;
- if( i == MAX_RESOURCES ) {
- rc = GPGERR_RESOURCE_LIMIT;
- goto leave;
- }
-
- /* see whether we can determine the filetype */
- if( rt == rt_UNKNOWN ) {
- FILE *fp = fopen( filename, "rb" );
-
- if( fp ) {
- u32 magic;
-
- if( fread( &magic, 4, 1, fp) == 1 ) {
- char buf[8];
-
- rt = rt_RING;
- if( fread( buf, 8, 1, fp) == 1 ) {
- if( !memcmp( buf+4, "KBXf", 4 )
- && buf[0] == 1 && buf[1] == 1 ) {
- rt = rt_KBXF;
- }
- }
- }
- else /* maybe empty: assume ring */
- rt = rt_RING;
- fclose( fp );
- }
- else /* no file yet: create ring */
- rt = rt_RING;
- }
-
- switch( rt ) {
- case rt_UNKNOWN:
- log_error("%s: unknown resource type\n", url );
- rc = GPGERR_GENERAL;
- goto leave;
-
- case rt_RING:
- case rt_KBXF:
- iobuf = iobuf_open( filename );
- if( !iobuf && !force ) {
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- if( !iobuf ) {
- char *last_slash_in_filename;
-
- last_slash_in_filename = strrchr(filename, '/');
- *last_slash_in_filename = 0;
-
- if( access(filename, F_OK) ) {
- /* on the first time we try to create the default homedir and
- * in this case the process will be terminated, so that on the
- * next invocation it can read the options file in on startup
- */
- try_make_homedir( filename );
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- *last_slash_in_filename = '/';
-
- iobuf = iobuf_create( filename );
- if( !iobuf ) {
- log_error(_("%s: can't create keyring: %s\n"),
- filename, strerror(errno));
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
- else {
- #ifndef HAVE_DOSISH_SYSTEM
- if( secret ) {
- if( chmod( filename, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- filename, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
- if( !opt.quiet )
- log_info(_("%s: keyring created\n"), filename );
- }
- }
- #if HAVE_DOSISH_SYSTEM || 1
- iobuf_close( iobuf );
- iobuf = NULL;
- /* must close it again */
- #endif
- break;
-
-
- default:
- log_error("%s: unsupported resource type\n", url );
- rc = GPGERR_GENERAL;
- goto leave;
- }
-
- #ifndef HAVE_DOSISH_SYSTEM
- #if 0 /* fixme: check directory permissions and print a warning */
- if( secret ) {
- }
- #endif
- #endif
-
- /* fixme: avoid duplicate resources */
- resource_table[i].used = 1;
- resource_table[i].secret = !!secret;
- resource_table[i].fname = gcry_xstrdup(filename);
- resource_table[i].iobuf = iobuf;
- resource_table[i].rt = rt;
- if( secret )
- default_secret_resource = i;
- else
- default_public_resource = i;
-
- leave:
- if( rc )
- log_error("keyblock resource `%s': %s\n", filename, gpg_errstr(rc) );
- else if( secret )
- any_secret = 1;
- else
- any_public = 1;
- gcry_free( filename );
- return rc;
-}
-
-/****************
- * Return the resource name of the keyblock associated with KBPOS.
- */
-const char *
-keyblock_resource_name( KBPOS kbpos )
-{
- RESTBL *rentry;
-
- if( !(rentry = check_pos( kbpos )) || !rentry->fname )
- log_bug("no name for keyblock resource %d\n", kbpos->resno );
- return rentry->fname;
-}
-
-
-/****************
- * Get a keyblock handle KBPOS from a filename. This can be used
- * to get a handle for insert_keyblock for a new keyblock.
- * Using a filename of NULL returns the default resource
- */
-int
-get_keyblock_handle( const char *filename, int secret, KBPOS kbpos )
-{
- int i = 0;
-
- if( !filename )
- i = secret? default_secret_resource : default_public_resource;
-
- for(; i < MAX_RESOURCES; i++ ) {
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- /* fixme: dos needs case insensitive file compare */
- if( !filename || !strcmp( resource_table[i].fname, filename ) ) {
- memset( kbpos, 0, sizeof *kbpos );
- kbpos->resno = i;
- kbpos->rt = resource_table[i].rt;
- return 0;
- }
- }
- }
- return -1; /* not found */
-}
-
-
-/****************
- * Return the filename of the firstkeyblock resource which is intended
- * for write access. This will either be the default resource or in
- * case this is not writable one of the others. If no writable is found,
- * the default filename in the homedirectory will be returned.
- * Caller must free, will never return NULL.
- */
-char *
-get_writable_keyblock_file( int secret )
-{
- int i = secret? default_secret_resource : default_public_resource;
-
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
- return gcry_xstrdup( resource_table[i].fname );
- }
- }
- for(i=0; i < MAX_RESOURCES; i++ ) {
- if( resource_table[i].used && !resource_table[i].secret == !secret ) {
- if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
- return gcry_xstrdup( resource_table[i].fname );
- }
- }
- }
- /* Assume the home dir is always writable */
- return make_filename(opt.homedir, secret? "secring.gpg"
- : "pubring.gpg", NULL );
-}
-
-
-void
-ringedit_copy_kbpos ( KBPOS d, KBPOS s )
-{
- *d = *s;
-}
-
-
-/****************
- * Lock the keyblock; wait until it's available
- * This function may change the internal data in kbpos, in cases
- * when the keyblock to be locked has been modified.
- * fixme: remove this function and add an option to search()?
- */
-static int
-lock_keyblock( KBPOS kbpos )
-{
- if( !check_pos(kbpos) )
- return GPGERR_GENERAL;
- return 0;
-}
-
-/****************
- * Release a lock on a keyblock
- */
-static void
-unlock_keyblock( KBPOS kbpos )
-{
- if( !check_pos(kbpos) )
- BUG();
-}
-
-
-static int
-enum_keyrings_open_helper( KBPOS kbpos, int where )
-{
- int i = where;
- RESTBL *rentry;
-
- for(; i < MAX_RESOURCES; i++ )
- if( resource_table[i].used
- && !resource_table[i].secret == !kbpos->secret )
- break;
- if( i == MAX_RESOURCES )
- return -1; /* no resources */
- kbpos->resno = i;
- rentry = check_pos( kbpos );
- kbpos->rt = resource_table[i].rt;
- kbpos->valid = 0;
- switch( kbpos->rt ) {
- case rt_RING:
- case rt_KBXF:
- kbpos->fp = iobuf_open( rentry->fname );
- if ( !kbpos->fp ) {
- log_error("can't open `%s'\n", rentry->fname );
- return GPGERR_OPEN_FILE;
- }
- break;
-
- default: BUG();
- }
- kbpos->pkt = NULL;
- return 0;
-}
-
-
-/****************
- * This set of functions is used to scan over all keyrings.
- * The mode in enum_keyblocks_next() is used liek this:
- * Mode is: 1 = read
- * 11 = read but skip signature and comment packets.
- */
-int
-enum_keyblocks_begin( KBPOS *rkbpos, int use_secret )
-{
- int rc, i;
- KBPOS kbpos;
-
- *rkbpos = NULL;
-
- kbpos = gcry_xcalloc( 1, sizeof *kbpos );
- kbpos->fp = NULL;
- kbpos->rt = rt_UNKNOWN;
- if( !use_secret ) {
- kbpos->secret = 0;
- i = 0;
- }
- else {
- kbpos->secret = 1;
- i = 0;
- }
-
- rc = enum_keyrings_open_helper( kbpos, i );
- if ( rc ) {
- gcry_free( kbpos );
- return rc;
- }
- /* return the handle */
- *rkbpos = kbpos;
- return 0;
-}
-
-void
-enum_keyblocks_end( KBPOS kbpos )
-{
- if ( !kbpos )
- return;
- switch( kbpos->rt ) {
- case rt_RING:
- case rt_KBXF:
- if( kbpos->fp ) {
- iobuf_close( kbpos->fp );
- kbpos->fp = NULL;
- }
- break;
- case rt_UNKNOWN:
- /* this happens when we have no keyring at all */
- gcry_free( kbpos );
- return;
-
- default:
- BUG();
- }
- /* release pending packet */
- free_packet( kbpos->pkt );
- gcry_free( kbpos->pkt );
- gcry_free( kbpos );
-}
-
-int
-enum_keyblocks_next( KBPOS kbpos, int mode, KBNODE *ret_root )
-{
- int cont, rc = 0;
- RESTBL *rentry;
-
- if( mode != 1 && mode != 11 )
- return GPGERR_INV_ARG;
-
- do {
- cont = 0;
- switch( kbpos->rt ) {
- case rt_RING:
- if( !kbpos->fp )
- return GPGERR_GENERAL;
- rc = keyring_enum( kbpos, ret_root, mode == 11 );
- break;
- case rt_KBXF:
- if( !kbpos->fp )
- return GPGERR_GENERAL;
- rc = do_kbxf_enum( kbpos, ret_root, mode == 11 );
- break;
- default: BUG();
- }
-
- if( rc == -1 ) {
- RESTBL *rentry;
- int i;
-
- assert( !kbpos->pkt );
- rentry = check_pos( kbpos );
- assert(rentry);
- i = kbpos->resno+1;
- /* first close */
- if( kbpos->fp ) {
- iobuf_close( kbpos->fp );
- kbpos->fp = NULL;
- }
- free_packet( kbpos->pkt );
- gcry_free( kbpos->pkt );
- kbpos->pkt = NULL;
- /* and then open the next one */
- rc = enum_keyrings_open_helper( kbpos, i );
- if ( !rc )
- cont = 1;
- /* hmm, that is not really correct: if we got an error kbpos
- * might be not well anymore */
- }
- } while(cont);
-
- return rc;
-}
-
-
-
-
-/****************
- * Insert the keyblock described by ROOT into the keyring described
- * by KBPOS. This actually appends the data to the keyfile.
- */
-int
-insert_keyblock( KBNODE root )
-{
- int rc;
-#if 0
- if( !check_pos(kbpos) )
- return GPGERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- rc = keyring_copy( kbpos, 1, root );
- break;
- case rt_KBXF:
- rc = do_kbxf_copy( kbpos, 1, root );
- break;
- default: BUG();
- }
-#endif
- return rc;
-}
-
-/****************
- * Delete the keyblock described by KBPOS.
- * The current code simply changes the keyblock in the keyring
- * to packet of type 0 with the correct length. To help detect errors,
- * zero bytes are written.
- */
-int
-delete_keyblock( KBNODE keyblock )
-{
- int rc;
- #if 0
- if( !check_pos(kbpos) )
- return GPGERR_GENERAL;
-
- switch( kbpos->rt ) {
- case rt_RING:
- rc = keyring_copy( kbpos, 2, NULL );
- break;
- case rt_KBXF:
- rc = do_kbxf_copy( kbpos, 2, NULL );
- break;
- default: BUG();
- }
- #endif
- return rc;
-}
-
-
-/****************
- * Update the keyblock in the ring (or whatever resource) one in ROOT.
- */
-int
-update_keyblock( KBNODE root )
-{
- int rc;
- struct keyblock_pos_struct kbpos;
-
- /* We need to get the file position of original keyblock first */
- if ( root->pkt->pkttype == PKT_PUBLIC_KEY )
- rc = find_kblocation_bypk( &kbpos, root->pkt->pkt.public_key );
- else if ( root->pkt->pkttype == PKT_SECRET_KEY )
- rc = find_kblocation_bysk( &kbpos, root->pkt->pkt.secret_key );
- else
- BUG();
-
- if ( rc )
- return rc;
-
- if( !check_pos(&kbpos) )
- return GPGERR_GENERAL;
-
- switch( kbpos.rt ) {
- case rt_RING:
- rc = keyring_copy( &kbpos, 3, root );
- break;
- case rt_KBXF:
- rc = do_kbxf_copy( &kbpos, 3, root );
- break;
- default: BUG();
- }
-
- return rc;
-}
-
-
-
-/****************************************************************
- ********** Functions which operates on regular keyrings ********
- ****************************************************************/
-
-static int
-keyring_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs )
-{
- PACKET *pkt;
- int rc;
- RESTBL *rentry;
- KBNODE root = NULL;
- ulong offset, first_offset=0;
-
- if( !(rentry=check_pos(kbpos)) )
- return GPGERR_GENERAL;
-
- if( kbpos->pkt ) {
- root = new_kbnode( kbpos->pkt );
- first_offset = kbpos->save_offset;
- kbpos->pkt = NULL;
- }
- kbpos->valid = 0;
-
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- while( (rc=parse_packet(kbpos->fp, pkt, &offset )) != -1 ) {
- if( rc ) { /* ignore errors */
- if( rc != GPGERR_UNKNOWN_PACKET ) {
- log_error("keyring_enum: read error: %s\n", gpg_errstr(rc) );
- rc = GPGERR_INV_KEYRING;
- goto ready;
- }
- free_packet( pkt );
- init_packet( pkt );
- continue;
- }
- /* make a linked list of all packets */
- switch( pkt->pkttype ) {
- case PKT_COMPRESSED:
- log_error("skipped compressed packet in keyring\n" );
- free_packet(pkt);
- init_packet(pkt);
- break;
-
- case PKT_PUBLIC_KEY:
- case PKT_SECRET_KEY:
- if( root ) { /* save this packet */
- kbpos->pkt = pkt;
- kbpos->save_offset = offset;
- pkt = NULL;
- goto ready;
- }
- root = new_kbnode( pkt );
- first_offset = offset;
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- break;
-
- default:
- /* skip pakets at the beginning of a keyring, until we find
- * a start packet; issue a warning if it is not a comment */
- if( !root && pkt->pkttype != PKT_COMMENT
- && pkt->pkttype != PKT_OLD_COMMENT ) {
- break;
- }
- if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
- ||pkt->pkttype == PKT_COMMENT
- ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
- init_packet(pkt);
- break;
- }
- add_kbnode( root, new_kbnode( pkt ) );
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- break;
- }
- }
- ready:
- if( rc == -1 && root )
- rc = 0;
-
- if( rc )
- release_kbnode( root );
- else {
- if ( root ) {
- kbpos->offset = first_offset;
- kbpos->valid = 1;
- }
- *ret_root = root;
- }
- free_packet( pkt );
- gcry_free( pkt );
-
- return rc;
-}
-
-
-/****************
- * Perform insert/delete/update operation.
- * mode 1 = insert
- * 2 = delete
- * 3 = update
- */
-static int
-keyring_copy( KBPOS kbpos, int mode, KBNODE root )
-{
- RESTBL *rentry;
- IOBUF fp, newfp;
- int rc=0;
- char *bakfname = NULL;
- char *tmpfname = NULL;
-#warning We need to lock the keyring while we are editing it.
- /* rethink this whole module */
-
- if( !(rentry = check_pos( kbpos )) )
- return GPGERR_GENERAL;
-
- if( opt.dry_run )
- return 0;
-
- lock_rentry( rentry );
-
- /* open the source file */
- if( kbpos->fp ) {
- /* BUG(); not allowed with such a handle */
- log_debug("keyring_copy: closing fp %p\n", kbpos->fp );
- iobuf_close (kbpos->fp);
- kbpos->fp = NULL;
- kbpos->valid = 0;
- }
- fp = iobuf_open( rentry->fname );
- if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
- KBNODE kbctx, node;
-
- /* insert: create a new file */
- newfp = iobuf_create( rentry->fname );
- if( !newfp ) {
- log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
- unlock_rentry( rentry );
- return GPGERR_OPEN_FILE;
- }
- else if( !opt.quiet )
- log_info(_("%s: keyring created\n"), rentry->fname );
-
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- iobuf_cancel(newfp);
- unlock_rentry( rentry );
- return GPGERR_WRITE_FILE;
- }
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
- unlock_rentry( rentry );
- return GPGERR_CLOSE_FILE;
- }
- if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- rentry->fname, strerror(errno) );
- unlock_rentry( rentry );
- return GPGERR_WRITE_FILE;
- }
- return 0;
- }
- if( !fp ) {
- log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- /* create the new file */
- #ifdef USE_ONLY_8DOT3
- /* Here is another Windoze bug?:
- * you cant rename("pubring.gpg.tmp", "pubring.gpg");
- * but rename("pubring.gpg.tmp", "pubring.aaa");
- * works. So we replace .gpg by .bak or .tmp
- */
- if( strlen(rentry->fname) > 4
- && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
- strcpy(bakfname,rentry->fname);
- strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
- strcpy(tmpfname,rentry->fname);
- strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
- }
- else { /* file does not end with gpg; hmmm */
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(bakfname,rentry->fname),".bak");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
- }
- #else
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 2 );
- strcpy(stpcpy(bakfname,rentry->fname),"~");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
- #endif
- newfp = iobuf_create( tmpfname );
- if( !newfp ) {
- log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
- iobuf_close(fp);
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- if( mode == 1 ) { /* insert */
- /* copy everything to the new file */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy first part to the new file */
- rc = copy_some_packets( fp, newfp, kbpos->offset );
- if( rc ) { /* should never get EOF here */
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- /* skip this keyblock */
- assert( kbpos->count );
- rc = skip_some_packets( fp, kbpos->count );
- if( rc ) {
- log_error("%s: skipping %u packets failed: %s\n",
- rentry->fname, kbpos->count, gpg_errstr(rc));
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- }
-
- if( mode == 1 || mode == 3 ) { /* insert or update */
- KBNODE kbctx, node;
-
- /* append the new data */
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- rc = GPGERR_WRITE_FILE;
- goto leave;
- }
- }
- kbpos->valid = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy the rest */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- /* close both files */
- if( iobuf_close(fp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
- rc = GPGERR_CLOSE_FILE;
- goto leave;
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
- rc = GPGERR_CLOSE_FILE;
- goto leave;
- }
- /* if the new file is a secring, restrict the permissions */
- #ifndef HAVE_DOSISH_SYSTEM
- if( rentry->secret ) {
- if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- tmpfname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
-
- /* rename and make backup file */
- if( !rentry->secret ) { /* but not for secret keyrings */
- #ifdef HAVE_DOSISH_SYSTEM
- remove( bakfname );
- #endif
- if( rename( rentry->fname, bakfname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- rentry->fname, bakfname, strerror(errno) );
- rc = GPGERR_RENAME_FILE;
- goto leave;
- }
- }
- #ifdef HAVE_DOSISH_SYSTEM
- remove( rentry->fname );
- #endif
- if( rename( tmpfname, rentry->fname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- tmpfname, rentry->fname,strerror(errno) );
- rc = GPGERR_RENAME_FILE;
- if( rentry->secret ) {
- log_info(_(
- "WARNING: 2 files with confidential information exists.\n"));
- log_info(_("%s is the unchanged one\n"), rentry->fname );
- log_info(_("%s is the new one\n"), tmpfname );
- log_info(_("Please fix this possible security flaw\n"));
- }
- goto leave;
- }
-
- leave:
- unlock_rentry( rentry );
- gcry_free(bakfname);
- gcry_free(tmpfname);
- return rc;
-}
-
-
-/****************************************************************
- ********** Functions which operate on KBX files ****************
- ****************************************************************/
-
-static int
-do_kbxf_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs )
-{
- PACKET *pkt;
- int rc;
- RESTBL *rentry;
- KBNODE root = NULL;
-
- if( !(rentry=check_pos(kbpos)) )
- return GPGERR_GENERAL;
-
- if( kbpos->pkt ) {
- root = new_kbnode( kbpos->pkt );
- kbpos->pkt = NULL;
- }
-
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- while( (rc=parse_packet(kbpos->fp, pkt, NULL)) != -1 ) {
- if( rc ) { /* ignore errors */
- if( rc != GPGERR_UNKNOWN_PACKET ) {
- log_error("do_kbxf_enum: read error: %s\n", gpg_errstr(rc) );
- rc = GPGERR_INV_KEYRING;
- goto ready;
- }
- free_packet( pkt );
- init_packet( pkt );
- continue;
- }
- /* make a linked list of all packets */
- switch( pkt->pkttype ) {
- case PKT_COMPRESSED:
- log_error("skipped compressed packet in keyring\n" );
- free_packet(pkt);
- init_packet(pkt);
- break;
-
- case PKT_PUBLIC_KEY:
- case PKT_SECRET_KEY:
- if( root ) { /* store this packet */
- kbpos->pkt = pkt;
- pkt = NULL;
- goto ready;
- }
- root = new_kbnode( pkt );
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- break;
-
- default:
- /* skip pakets at the beginning of a keyring, until we find
- * a start packet; issue a warning if it is not a comment */
- if( !root && pkt->pkttype != PKT_COMMENT
- && pkt->pkttype != PKT_OLD_COMMENT ) {
- break;
- }
- if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
- ||pkt->pkttype == PKT_COMMENT
- ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
- init_packet(pkt);
- break;
- }
- add_kbnode( root, new_kbnode( pkt ) );
- pkt = gcry_xmalloc( sizeof *pkt );
- init_packet(pkt);
- break;
- }
- }
- ready:
- if( rc == -1 && root )
- rc = 0;
-
- if( rc )
- release_kbnode( root );
- else
- *ret_root = root;
- free_packet( pkt );
- gcry_free( pkt );
-
- return rc;
-}
-
-
-/****************
- * Perform insert/delete/update operation.
- * mode 1 = insert
- * 2 = delete
- * 3 = update
- */
-static int
-do_kbxf_copy( KBPOS kbpos, int mode, KBNODE root )
-{
- RESTBL *rentry;
- IOBUF fp, newfp;
- int rc=0;
- char *bakfname = NULL;
- char *tmpfname = NULL;
-
- if( !(rentry = check_pos( kbpos )) )
- return GPGERR_GENERAL;
- if( kbpos->fp )
- BUG(); /* not allowed with such a handle */
-
- if( opt.dry_run )
- return 0;
-
- lock_rentry( rentry );
-
- /* open the source file */
- fp = iobuf_open( rentry->fname );
- if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
- KBNODE kbctx, node;
-
- /* insert: create a new file */
- newfp = iobuf_create( rentry->fname );
- if( !newfp ) {
- log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
- unlock_rentry( rentry );
- return GPGERR_OPEN_FILE;
- }
- else if( !opt.quiet )
- log_info(_("%s: keyring created\n"), rentry->fname );
-
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- iobuf_cancel(newfp);
- unlock_rentry( rentry );
- return GPGERR_WRITE_FILE;
- }
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
- unlock_rentry( rentry );
- return GPGERR_CLOSE_FILE;
- }
- if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- rentry->fname, strerror(errno) );
- unlock_rentry( rentry );
- return GPGERR_WRITE_FILE;
- }
- return 0;
- }
- if( !fp ) {
- log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- /* create the new file */
- #ifdef USE_ONLY_8DOT3
- /* Here is another Windoze bug?:
- * you cant rename("pubring.gpg.tmp", "pubring.gpg");
- * but rename("pubring.gpg.tmp", "pubring.aaa");
- * works. So we replace .gpg by .bak or .tmp
- */
- if( strlen(rentry->fname) > 4
- && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
- strcpy(bakfname,rentry->fname);
- strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
- strcpy(tmpfname,rentry->fname);
- strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
- }
- else { /* file does not end with gpg; hmmm */
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(bakfname,rentry->fname),".bak");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
- }
- #else
- bakfname = gcry_xmalloc( strlen( rentry->fname ) + 2 );
- strcpy(stpcpy(bakfname,rentry->fname),"~");
- tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
- strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
- #endif
- newfp = iobuf_create( tmpfname );
- if( !newfp ) {
- log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
- iobuf_close(fp);
- rc = GPGERR_OPEN_FILE;
- goto leave;
- }
-
- if( mode == 1 ) { /* insert */
- /* copy everything to the new file */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy first part to the new file */
- rc = copy_some_packets( fp, newfp, kbpos->offset );
- if( rc ) { /* should never get EOF here */
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- /* skip this keyblock */
- assert( kbpos->count );
- rc = skip_some_packets( fp, kbpos->count );
- if( rc ) {
- log_error("%s: skipping %u packets failed: %s\n",
- rentry->fname, kbpos->count, gpg_errstr(rc));
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- }
-
- if( mode == 1 || mode == 3 ) { /* insert or update */
- KBNODE kbctx, node;
-
- /* append the new data */
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- rc = GPGERR_WRITE_FILE;
- goto leave;
- }
- }
- kbpos->valid = 0;
- }
-
- if( mode == 2 || mode == 3 ) { /* delete or update */
- /* copy the rest */
- rc = copy_all_packets( fp, newfp );
- if( rc != -1 ) {
- log_error("%s: copy to %s failed: %s\n",
- rentry->fname, tmpfname, gpg_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- goto leave;
- }
- rc = 0;
- }
-
- /* close both files */
- if( iobuf_close(fp) ) {
- log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
- rc = GPGERR_CLOSE_FILE;
- goto leave;
- }
- if( iobuf_close(newfp) ) {
- log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
- rc = GPGERR_CLOSE_FILE;
- goto leave;
- }
- /* if the new file is a secring, restrict the permissions */
- #ifndef HAVE_DOSISH_SYSTEM
- if( rentry->secret ) {
- if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- tmpfname, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
-
- /* rename and make backup file */
- if( !rentry->secret ) { /* but not for secret keyrings */
- #ifdef HAVE_DOSISH_SYSTEM
- remove( bakfname );
- #endif
- if( rename( rentry->fname, bakfname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- rentry->fname, bakfname, strerror(errno) );
- rc = GPGERR_RENAME_FILE;
- goto leave;
- }
- }
- #ifdef HAVE_DOSISH_SYSTEM
- remove( rentry->fname );
- #endif
- if( rename( tmpfname, rentry->fname ) ) {
- log_error("%s: rename to %s failed: %s\n",
- tmpfname, rentry->fname,strerror(errno) );
- rc = GPGERR_RENAME_FILE;
- if( rentry->secret ) {
- log_info(_(
- "WARNING: 2 files with confidential information exists.\n"));
- log_info(_("%s is the unchanged one\n"), rentry->fname );
- log_info(_("%s is the new one\n"), tmpfname );
- log_info(_("Please fix this possible security flaw\n"));
- }
- goto leave;
- }
-
- leave:
- unlock_rentry( rentry );
- gcry_free(bakfname);
- gcry_free(tmpfname);
- return rc;
-}
-
-
-
-
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
index 2adb9ef4c..01f4c7b2f 100644
--- a/g10/seckey-cert.c
+++ b/g10/seckey-cert.c
@@ -1,5 +1,5 @@
/* seckey-cert.c - secret key certificate packet handling
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,58 +23,22 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
+#include "memory.h"
#include "packet.h"
+#include "mpi.h"
#include "keydb.h"
+#include "cipher.h"
#include "main.h"
#include "options.h"
#include "i18n.h"
#include "status.h"
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
-static int
-pk_check_secret_key( int algo, MPI *skey )
-{
- GCRY_SEXP s_skey;
- int rc;
-
- /* make a sexp from skey */
- if( algo == GCRY_PK_DSA ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4] );
- }
- else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3] );
- }
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4], skey[5] );
- }
- else
- return GPGERR_PUBKEY_ALGO;
-
- if ( rc )
- BUG ();
-
- rc = gcry_pk_testkey( s_skey );
- gcry_sexp_release( s_skey );
- return rc;
-}
-
-
static int
-do_check( PKT_secret_key *sk )
+do_check( PKT_secret_key *sk, const char *tryagain_text )
{
+ byte *buffer;
u16 csum=0;
int i, res;
unsigned nbytes;
@@ -82,19 +46,20 @@ do_check( PKT_secret_key *sk )
if( sk->is_protected ) { /* remove the protection */
DEK *dek = NULL;
u32 keyid[4]; /* 4! because we need two of them */
- GCRY_CIPHER_HD cipher_hd=NULL;
+ CIPHER_HANDLE cipher_hd=NULL;
PKT_secret_key *save_sk;
if( sk->protect.s2k.mode == 1001 ) {
log_info(_("secret key parts are not available\n"));
- return GPGERR_GENERAL;
+ return G10ERR_GENERAL;
}
- if( sk->protect.algo == GCRY_CIPHER_NONE )
+ if( sk->protect.algo == CIPHER_ALGO_NONE )
BUG();
- if( openpgp_cipher_test_algo( sk->protect.algo ) ) {
- log_info(_("protection algorithm %d is not supported\n"),
- sk->protect.algo );
- return GPGERR_CIPHER_ALGO;
+ if( check_cipher_algo( sk->protect.algo ) ) {
+ log_info(_("protection algorithm %d%s is not supported\n"),
+ sk->protect.algo,sk->protect.algo==1?" (IDEA)":"" );
+ idea_cipher_warn(0);
+ return G10ERR_CIPHER_ALGO;
}
keyid_from_sk( sk, keyid );
keyid[2] = keyid[3] = 0;
@@ -103,110 +68,115 @@ do_check( PKT_secret_key *sk )
keyid[3] = sk->main_keyid[1];
}
dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
- &sk->protect.s2k, 0 );
- /* Hmmm: Do we use sync mode here even for Twofish? */
- if( !(cipher_hd = gcry_cipher_open( sk->protect.algo,
- GCRY_CIPHER_MODE_CFB,
- GCRY_CIPHER_SECURE
- | (sk->protect.algo >= 100 ?
- 0 : GCRY_CIPHER_ENABLE_SYNC) ) )
- ) {
- BUG();
- }
-
- if( gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
- log_fatal("set key failed: %s\n", gcry_strerror(-1) );
- gcry_free(dek);
+ &sk->protect.s2k, 0, tryagain_text );
+ cipher_hd = cipher_open( sk->protect.algo,
+ CIPHER_MODE_AUTO_CFB, 1);
+ cipher_setkey( cipher_hd, dek->key, dek->keylen );
+ m_free(dek);
save_sk = copy_secret_key( NULL, sk );
- if( gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen ))
- log_fatal("set IV failed: %s\n", gcry_strerror(-1) );
+ cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
csum = 0;
if( sk->version >= 4 ) {
- size_t ndata;
- unsigned int ndatabits;
+ int ndata;
byte *p, *data;
u16 csumc = 0;
i = pubkey_get_npkey(sk->pubkey_algo);
- assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
- p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
- ndata = (ndatabits+7)/8;
+ assert( mpi_is_opaque( sk->skey[i] ) );
+ p = mpi_get_opaque( sk->skey[i], &ndata );
if ( ndata > 1 )
csumc = p[ndata-2] << 8 | p[ndata-1];
- data = gcry_xmalloc_secure( ndata );
- gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
- mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
+ data = m_alloc_secure( ndata );
+ cipher_decrypt( cipher_hd, data, p, ndata );
+ mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
p = data;
- if( ndata < 2 ) {
- log_error("not enough bytes for checksum\n");
- sk->csum = 0;
- csum = 1;
- }
- else {
- csum = checksum( data, ndata-2);
- sk->csum = data[ndata-2] << 8 | data[ndata-1];
- if ( sk->csum != csum ) {
- /* This is a PGP 7.0.0 workaround */
- sk->csum = csumc; /* take the encrypted one */
+ if (sk->protect.sha1chk) {
+ /* This is the new SHA1 checksum method to detect
+ tampering with the key as used by the Klima/Rosa
+ attack */
+ sk->csum = 0;
+ csum = 1;
+ if( ndata < 20 )
+ log_error("not enough bytes for SHA-1 checksum\n");
+ else {
+ MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
+ if (!h)
+ BUG(); /* algo not available */
+ md_write (h, data, ndata - 20);
+ md_final (h);
+ if (!memcmp (md_read (h, DIGEST_ALGO_SHA1),
+ data + ndata - 20, 20) ) {
+ /* digest does match. We have to keep the old
+ style checksum in sk->csum, so that the
+ test used for unprotected keys does work.
+ This test gets used when we are adding new
+ keys. */
+ sk->csum = csum = checksum (data, ndata-20);
+ }
+ md_close (h);
}
- }
- /* must check it here otherwise the mpi_read_xx would fail
- * because the length may have an arbitrary value */
- if( sk->csum == csum ) {
- for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
- nbytes = ndata;
- assert( gcry_is_secure( p ) );
- res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP,
- p, &nbytes);
- if( res )
- log_bug("gcry_mpi_scan failed in do_check: rc=%d\n", res);
-
- ndata -= nbytes;
- p += nbytes;
- }
- }
- gcry_free(data);
+ }
+ else {
+ if( ndata < 2 ) {
+ log_error("not enough bytes for checksum\n");
+ sk->csum = 0;
+ csum = 1;
+ }
+ else {
+ csum = checksum( data, ndata-2);
+ sk->csum = data[ndata-2] << 8 | data[ndata-1];
+ if ( sk->csum != csum ) {
+ /* This is a PGP 7.0.0 workaround */
+ sk->csum = csumc; /* take the encrypted one */
+ }
+ }
+ }
+
+ /* must check it here otherwise the mpi_read_xx would fail
+ because the length may have an arbitrary value */
+ if( sk->csum == csum ) {
+ for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
+ nbytes = ndata;
+ sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
+ ndata -= nbytes;
+ p += nbytes;
+ }
+ /* Note: at this point ndata should be 2 for a simple
+ checksum or 20 for the sha1 digest */
+ }
+ m_free(data);
}
else {
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
- size_t ndata;
- unsigned int ndatabits;
- byte *p, *data;
-
- assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
- p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
- ndata = (ndatabits+7)/8;
- data = gcry_xmalloc_secure( ndata );
- gcry_cipher_sync( cipher_hd );
- gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
- mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
-
- res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG,
- data, &ndata );
- if( res )
- log_bug("gcry_mpi_scan failed in do_check: rc=%d\n", res);
-
+ buffer = mpi_get_secure_buffer( sk->skey[i], &nbytes, NULL );
+ cipher_sync( cipher_hd );
+ assert( mpi_is_protected(sk->skey[i]) );
+ cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
+ mpi_set_buffer( sk->skey[i], buffer, nbytes, 0 );
+ mpi_clear_protect_flag( sk->skey[i] );
csum += checksum_mpi( sk->skey[i] );
- gcry_free( data );
+ m_free( buffer );
+ }
+ if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
+ csum = sk->csum;
}
}
- gcry_cipher_close( cipher_hd );
+ cipher_close( cipher_hd );
/* now let's see whether we have used the right passphrase */
if( csum != sk->csum ) {
copy_secret_key( sk, save_sk );
passphrase_clear_cache ( keyid, sk->pubkey_algo );
free_secret_key( save_sk );
- return GPGERR_BAD_PASS;
+ return G10ERR_BAD_PASS;
}
- /* the checksum may be correct in some cases,
- * so we also check the key itself */
- res = pk_check_secret_key( sk->pubkey_algo, sk->skey );
+ /* the checksum may fail, so we also check the key itself */
+ res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey );
if( res ) {
copy_secret_key( sk, save_sk );
passphrase_clear_cache ( keyid, sk->pubkey_algo );
free_secret_key( save_sk );
- return GPGERR_BAD_PASS;
+ return G10ERR_BAD_PASS;
}
free_secret_key( save_sk );
sk->is_protected = 0;
@@ -215,11 +185,10 @@ do_check( PKT_secret_key *sk )
csum = 0;
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
- assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
csum += checksum_mpi( sk->skey[i] );
}
if( csum != sk->csum )
- return GPGERR_CHECKSUM;
+ return G10ERR_CHECKSUM;
}
return 0;
@@ -234,17 +203,20 @@ do_check( PKT_secret_key *sk )
int
check_secret_key( PKT_secret_key *sk, int n )
{
- int rc = GPGERR_BAD_PASS;
+ int rc = G10ERR_BAD_PASS;
int i;
if( n < 1 )
- n = opt.batch? 1 : 3; /* use the default value */
-
- for(i=0; i < n && rc == GPGERR_BAD_PASS; i++ ) {
- if( i )
- log_info(_("Invalid passphrase; please try again ...\n"));
- rc = do_check( sk );
- if( rc == GPGERR_BAD_PASS && is_status_enabled() ) {
+ n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */
+
+ for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) {
+ const char *tryagain = NULL;
+ if (i) {
+ tryagain = _("Invalid passphrase; please try again");
+ log_info (_("%s ...\n"), tryagain);
+ }
+ rc = do_check( sk, tryagain );
+ if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
u32 kid[2];
char buf[50];
@@ -289,114 +261,103 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
return 0;
if( !sk->is_protected ) { /* okay, apply the protection */
- GCRY_CIPHER_HD cipher_hd=NULL;
+ CIPHER_HANDLE cipher_hd=NULL;
- if( openpgp_cipher_test_algo( sk->protect.algo ) )
- rc = GPGERR_CIPHER_ALGO; /* unsupport protection algorithm */
+ if( check_cipher_algo( sk->protect.algo ) )
+ rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else {
print_cipher_algo_note( sk->protect.algo );
- if( !(cipher_hd = gcry_cipher_open( sk->protect.algo,
- GCRY_CIPHER_MODE_CFB,
- GCRY_CIPHER_SECURE
- | (sk->protect.algo >= 100 ?
- 0 : GCRY_CIPHER_ENABLE_SYNC) ))
- ) {
- BUG();
- }
- rc = gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen );
- if( rc == GCRYERR_WEAK_KEY ) {
+ cipher_hd = cipher_open( sk->protect.algo,
+ CIPHER_MODE_AUTO_CFB, 1 );
+ if( cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
log_info(_("WARNING: Weak key detected"
" - please change passphrase again.\n"));
- rc = 0;
- }
- else if( rc )
- BUG();
-
- /* set the IV length */
- { int blocksize = gcry_cipher_get_algo_blklen( sk->protect.algo );
- if( blocksize != 8 && blocksize != 16 )
- log_fatal("unsupported blocksize %d\n", blocksize );
- sk->protect.ivlen = blocksize;
- assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
- }
- gcry_randomize(sk->protect.iv, sk->protect.ivlen,
- GCRY_STRONG_RANDOM);
- gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
-
- /* FIXME: replace set/get buffer */
+ sk->protect.ivlen = cipher_get_blocksize( sk->protect.algo );
+ assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
+ if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
+ BUG(); /* yes, we are very careful */
+ randomize_buffer(sk->protect.iv, sk->protect.ivlen, 1);
+ cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
if( sk->version >= 4 ) {
- byte *bufarr[GNUPG_MAX_NSKEY];
- unsigned narr[GNUPG_MAX_NSKEY];
- unsigned nbits[GNUPG_MAX_NSKEY];
+ byte *bufarr[PUBKEY_MAX_NSKEY];
+ unsigned narr[PUBKEY_MAX_NSKEY];
+ unsigned nbits[PUBKEY_MAX_NSKEY];
int ndata=0;
byte *p, *data;
for(j=0, i = pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
- assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
-
- if( gcry_mpi_aprint( GCRYMPI_FMT_USG, (void**)bufarr+j,
- narr+j, sk->skey[i]))
- BUG();
-
- nbits[j] = gcry_mpi_get_nbits( sk->skey[i] );
+ assert( !mpi_is_opaque( sk->skey[i] ) );
+ bufarr[j] = mpi_get_buffer( sk->skey[i], &narr[j], NULL );
+ nbits[j] = mpi_get_nbits( sk->skey[i] );
ndata += narr[j] + 2;
}
- for( ; j < GNUPG_MAX_NSKEY; j++ )
+ for( ; j < PUBKEY_MAX_NSKEY; j++ )
bufarr[j] = NULL;
- ndata += 2; /* for checksum */
+ ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */
- data = gcry_xmalloc_secure( ndata );
+ data = m_alloc_secure( ndata );
p = data;
- for(j=0; j < GNUPG_MAX_NSKEY && bufarr[j]; j++ ) {
+ for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) {
p[0] = nbits[j] >> 8 ;
p[1] = nbits[j];
p += 2;
memcpy(p, bufarr[j], narr[j] );
p += narr[j];
- gcry_free(bufarr[j]);
+ m_free(bufarr[j]);
}
- csum = checksum( data, ndata-2);
- sk->csum = csum;
- *p++ = csum >> 8;
- *p++ = csum;
- assert( p == data+ndata );
- gcry_cipher_encrypt( cipher_hd, data, ndata, NULL, 0 );
+
+ if (opt.simple_sk_checksum) {
+ log_info (_("generating the deprecated 16-bit checksum"
+ " for secret key protection\n"));
+ csum = checksum( data, ndata-2);
+ sk->csum = csum;
+ *p++ = csum >> 8;
+ *p++ = csum;
+ sk->protect.sha1chk = 0;
+ }
+ else {
+ MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
+ if (!h)
+ BUG(); /* algo not available */
+ md_write (h, data, ndata - 20);
+ md_final (h);
+ memcpy (p, md_read (h, DIGEST_ALGO_SHA1), 20);
+ p += 20;
+ md_close (h);
+ sk->csum = csum = 0;
+ sk->protect.sha1chk = 1;
+ }
+ assert( p == data+ndata );
+
+ cipher_encrypt( cipher_hd, data, data, ndata );
for(i = pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
- mpi_release( sk->skey[i] );
+ mpi_free( sk->skey[i] );
sk->skey[i] = NULL;
}
i = pubkey_get_npkey(sk->pubkey_algo);
- sk->skey[i] = gcry_mpi_set_opaque(NULL, data, ndata*8 );
+ sk->skey[i] = mpi_set_opaque(NULL, data, ndata );
}
else {
/* NOTE: we always recalculate the checksum because there
* are some test releases which calculated it wrong */
- /* FIXME: Replace this code -- Hmmm: why */
csum = 0;
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
- csum += checksum_mpi( sk->skey[i] );
-
- if( gcry_mpi_aprint( GCRYMPI_FMT_USG,
- &buffer, &nbytes, sk->skey[i] ) )
- BUG();
-
- gcry_cipher_sync( cipher_hd );
- assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
- gcry_cipher_encrypt( cipher_hd, buffer, nbytes, NULL, 0 );
- gcry_mpi_release( sk->skey[i] );
- if( gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG,
- buffer,&nbytes ) )
- BUG();
-
- gcry_free( buffer );
+ csum += checksum_mpi_counted_nbits( sk->skey[i] );
+ buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL );
+ cipher_sync( cipher_hd );
+ assert( !mpi_is_protected(sk->skey[i]) );
+ cipher_encrypt( cipher_hd, buffer, buffer, nbytes );
+ mpi_set_buffer( sk->skey[i], buffer, nbytes, 0 );
+ mpi_set_protect_flag( sk->skey[i] );
+ m_free( buffer );
}
sk->csum = csum;
}
sk->is_protected = 1;
- gcry_cipher_close( cipher_hd );
+ cipher_close( cipher_hd );
}
}
return rc;
diff --git a/g10/seskey.c b/g10/seskey.c
index aa2a1511c..fc912eeb5 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -1,5 +1,5 @@
/* seskey.c - make sesssion keys etc.
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,9 +23,9 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
+#include "cipher.h"
+#include "mpi.h"
#include "main.h"
#include "i18n.h"
@@ -36,31 +36,22 @@
void
make_session_key( DEK *dek )
{
- GCRY_CIPHER_HD chd;
+ CIPHER_HANDLE chd;
int i, rc;
- dek->keylen = gcry_cipher_get_algo_keylen( dek->algo );
-
- if( !(chd = gcry_cipher_open( dek->algo, GCRY_CIPHER_MODE_CFB,
- GCRY_CIPHER_SECURE
- | (dek->algo >= 100 ?
- 0 : GCRY_CIPHER_ENABLE_SYNC) ))
- ) {
- BUG();
- }
+ dek->keylen = cipher_get_keylen( dek->algo ) / 8;
- gcry_randomize( dek->key, dek->keylen, GCRY_STRONG_RANDOM );
+ chd = cipher_open( dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
+ randomize_buffer( dek->key, dek->keylen, 1 );
for(i=0; i < 16; i++ ) {
- rc = gcry_cipher_setkey( chd, dek->key, dek->keylen );
+ rc = cipher_setkey( chd, dek->key, dek->keylen );
if( !rc ) {
- gcry_cipher_close( chd );
+ cipher_close( chd );
return;
}
- if( rc != GCRYERR_WEAK_KEY )
- BUG();
log_info(_("weak key created - retrying\n") );
/* Renew the session key until we get a non-weak key. */
- gcry_randomize( dek->key, dek->keylen, GCRY_STRONG_RANDOM );
+ randomize_buffer( dek->key, dek->keylen, 1 );
}
log_fatal(_(
"cannot avoid weak key for symmetric cipher; tried %d times!\n"),
@@ -108,13 +99,13 @@ encode_session_key( DEK *dek, unsigned nbits )
for( p = dek->key, i=0; i < dek->keylen; i++ )
csum += *p++;
- frame = gcry_xmalloc_secure( nframe );
+ frame = m_alloc_secure( nframe );
n = 0;
frame[n++] = 0;
frame[n++] = 2;
i = nframe - 6 - dek->keylen;
assert( i > 0 );
- p = gcry_random_bytes_secure( i, GCRY_STRONG_RANDOM );
+ p = get_random_bits( i*8, 1, 1 );
/* replace zero bytes by new values */
for(;;) {
int j, k;
@@ -127,14 +118,14 @@ encode_session_key( DEK *dek, unsigned nbits )
if( !k )
break; /* okay: no zero bytes */
k += k/128; /* better get some more */
- pp = gcry_random_bytes_secure( k, GCRY_STRONG_RANDOM);
+ pp = get_random_bits( k*8, 1, 1);
for(j=0; j < i && k ; j++ )
if( !p[j] )
p[j] = pp[--k];
- gcry_free(pp);
+ m_free(pp);
}
memcpy( frame+n, p, i );
- gcry_free(p);
+ m_free(p);
n += i;
frame[n++] = 0;
frame[n++] = dek->algo;
@@ -142,16 +133,15 @@ encode_session_key( DEK *dek, unsigned nbits )
frame[n++] = csum >>8;
frame[n++] = csum;
assert( n == nframe );
- if( gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, &nframe ) )
- BUG();
- gcry_free(frame);
-
+ a = mpi_alloc_secure( (nframe+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
+ mpi_set_buffer( a, frame, nframe, 0 );
+ m_free(frame);
return a;
}
static MPI
-do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
+do_encode_md( MD_HANDLE md, int algo, size_t len, unsigned nbits,
const byte *asn, size_t asnlen, int v3compathack )
{
int nframe = (nbits+7) / 8;
@@ -165,12 +155,11 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
/* We encode the MD in this way:
*
- * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
+ * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
*
* PAD consists of FF bytes.
*/
- frame = gcry_md_is_secure(md)? gcry_xmalloc_secure( nframe )
- : gcry_xmalloc( nframe );
+ frame = md_is_secure(md)? m_alloc_secure( nframe ) : m_alloc( nframe );
n = 0;
frame[n++] = 0;
frame[n++] = v3compathack? algo : 1; /* block type */
@@ -179,11 +168,13 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
memset( frame+n, 0xff, i ); n += i;
frame[n++] = 0;
memcpy( frame+n, asn, asnlen ); n += asnlen;
- memcpy( frame+n, gcry_md_read(md, algo), len ); n += len;
+ memcpy( frame+n, md_read(md, algo), len ); n += len;
assert( n == nframe );
- if( gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, &nframe ) )
- BUG();
- gcry_free(frame);
+ a = md_is_secure(md)?
+ mpi_alloc_secure( (nframe+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB )
+ : mpi_alloc( (nframe+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
+ mpi_set_buffer( a, frame, nframe, 0 );
+ m_free(frame);
return a;
}
@@ -192,36 +183,35 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits,
* Encode a message digest into an MPI.
* v3compathack is used to work around a bug in old GnuPG versions
* which did put the algo identifier inseatd of the block type 1 into
- * the encoded value. setting this vare force the old behaviour.
+ * the encoded value. Setting this flag forces the old behaviour.
*/
MPI
-encode_md_value( int pubkey_algo, GCRY_MD_HD md, int hash_algo,
+encode_md_value( int pubkey_algo, MD_HANDLE md, int hash_algo,
unsigned nbits, int v3compathack )
{
- int algo = hash_algo? hash_algo : gcry_md_get_algo(md);
+ int algo = hash_algo? hash_algo : md_get_algo(md);
+ const byte *asn;
+ size_t asnlen, mdlen;
MPI frame;
- if( pubkey_algo == GCRY_PK_DSA ) {
- size_t n = gcry_md_get_algo_dlen(hash_algo);
- if( gcry_mpi_scan( &frame, GCRYMPI_FMT_USG,
- gcry_md_read(md, hash_algo), &n ) )
- BUG();
+ if( pubkey_algo == PUBKEY_ALGO_DSA ) {
+ mdlen = md_digest_length (hash_algo);
+ if (mdlen != 20) {
+ log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
+ return NULL;
+ }
+
+ frame = md_is_secure(md)? mpi_alloc_secure((md_digest_length(hash_algo)
+ +BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB )
+ : mpi_alloc((md_digest_length(hash_algo)
+ +BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB );
+ mpi_set_buffer( frame, md_read(md, hash_algo),
+ md_digest_length(hash_algo), 0 );
}
else {
- byte *asn;
- size_t asnlen;
-
- if( gcry_md_algo_info( algo, GCRYCTL_GET_ASNOID, NULL, &asnlen ) )
- log_fatal("can't get OID of algo %d: %s\n",
- algo, gcry_strerror(-1));
- asn = gcry_xmalloc( asnlen );
- if( gcry_md_algo_info( algo, GCRYCTL_GET_ASNOID, asn, &asnlen ) )
- BUG();
- frame = do_encode_md( md, algo, gcry_md_get_algo_dlen( algo ),
- nbits, asn, asnlen, v3compathack );
- gcry_free( asn );
+ asn = md_asn_oid( algo, &asnlen, &mdlen );
+ frame = do_encode_md( md, algo, mdlen, nbits, asn, asnlen, v3compathack);
}
return frame;
}
-
diff --git a/g10/sig-check.c b/g10/sig-check.c
index a3946a1e0..c9c19aad4 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -1,5 +1,5 @@
/* sig-check.c - Check a signature
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -23,11 +23,12 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
-
-#include <gcrypt.h>
#include "util.h"
#include "packet.h"
+#include "memory.h"
+#include "mpi.h"
#include "keydb.h"
+#include "cipher.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
@@ -35,108 +36,35 @@
struct cmp_help_context_s {
PKT_signature *sig;
- GCRY_MD_HD md;
+ MD_HANDLE md;
};
-
-static int do_signature_check( PKT_signature *sig, GCRY_MD_HD digest,
- u32 *r_expiredate, int *r_expired );
static int do_check( PKT_public_key *pk, PKT_signature *sig,
- GCRY_MD_HD digest, int *r_expired );
-
-
-
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
-static int
-pk_verify( int algo, MPI hash, MPI *data, MPI *pkey,
- int (*cmp)(void *, MPI), void *opaque )
-{
- GCRY_SEXP s_sig, s_hash, s_pkey;
- int rc;
-
- /* forget about cmp and opaque - we never used it */
-
- /* make a sexp from pkey */
- if( algo == GCRY_PK_DSA ) {
- rc = gcry_sexp_build ( &s_pkey, NULL,
- "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2], pkey[3] );
- }
- else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_pkey, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2] );
- }
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &s_pkey, NULL,
- "(public-key(rsa(n%m)(e%m)))",
- pkey[0], pkey[1] );
- }
- else
- return GPGERR_PUBKEY_ALGO;
-
- if ( rc )
- BUG ();
-
- /* put hash into a S-Exp s_hash */
- if ( gcry_sexp_build( &s_hash, NULL, "%m", hash ) )
- BUG ();
-
- /* put data into a S-Exp s_sig */
- if( algo == GCRY_PK_DSA ) {
- rc = gcry_sexp_build ( &s_sig, NULL,
- "(sig-val(dsa(r%m)(s%m)))", data[0], data[1] );
- }
- else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_sig, NULL,
- "(sig-val(elg(r%m)(s%m)))", data[0], data[1] );
- }
- else if( algo == GCRY_PK_RSA ) {
- rc = gcry_sexp_build ( &s_sig, NULL,
- "(sig-val(rsa(s%m)))", data[0] );
- }
- else
- BUG();
-
- if ( rc )
- BUG ();
-
-
- rc = gcry_pk_verify( s_sig, s_hash, s_pkey );
- gcry_sexp_release( s_sig );
- gcry_sexp_release( s_hash );
- gcry_sexp_release( s_pkey );
- return rc;
-}
-
-
+ MD_HANDLE digest, int *r_expired );
/****************
* Check the signature which is contained in SIG.
- * The GCRY_MD_HD should be currently open, so that this function
+ * The MD_HANDLE should be currently open, so that this function
* is able to append some data, before finalizing the digest.
*/
int
-signature_check( PKT_signature *sig, GCRY_MD_HD digest )
+signature_check( PKT_signature *sig, MD_HANDLE digest )
{
u32 dummy;
int dum2;
- return do_signature_check( sig, digest, &dummy, &dum2 );
+ return signature_check2( sig, digest, &dummy, &dum2 );
}
-static int
-do_signature_check( PKT_signature *sig, GCRY_MD_HD digest,
- u32 *r_expiredate, int *r_expired )
+int
+signature_check2( PKT_signature *sig, MD_HANDLE digest,
+ u32 *r_expiredate, int *r_expired )
{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc=0;
*r_expiredate = 0;
if( get_pubkey( pk, sig->keyid ) )
- rc = GPGERR_NO_PUBKEY;
+ rc = G10ERR_NO_PUBKEY;
else {
*r_expiredate = pk->expiredate;
rc = do_check( pk, sig, digest, r_expired );
@@ -150,40 +78,38 @@ do_signature_check( PKT_signature *sig, GCRY_MD_HD digest,
* this sig-id we could have also used the hash of the document
* and the timestamp, but the drawback of this is, that it is
* not possible to sign more than one identical document within
- * one second. Some remote bacth processing applications might
+ * one second. Some remote batch processing applications might
* like this feature here */
- GCRY_MD_HD md;
+ MD_HANDLE md;
u32 a = sig->timestamp;
int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
byte *p, *buffer;
- if( !(md = gcry_md_open( GCRY_MD_RMD160, 0)) )
- BUG();
- gcry_md_putc( digest, sig->pubkey_algo );
- gcry_md_putc( digest, sig->digest_algo );
- gcry_md_putc( digest, (a >> 24) & 0xff );
- gcry_md_putc( digest, (a >> 16) & 0xff );
- gcry_md_putc( digest, (a >> 8) & 0xff );
- gcry_md_putc( digest, a & 0xff );
+ md = md_open( DIGEST_ALGO_RMD160, 0);
+ md_putc( digest, sig->pubkey_algo );
+ md_putc( digest, sig->digest_algo );
+ md_putc( digest, (a >> 24) & 0xff );
+ md_putc( digest, (a >> 16) & 0xff );
+ md_putc( digest, (a >> 8) & 0xff );
+ md_putc( digest, a & 0xff );
for(i=0; i < nsig; i++ ) {
- size_t n = gcry_mpi_get_nbits( sig->data[i]);
-
- gcry_md_putc( md, n>>8);
- gcry_md_putc( md, n );
- if( gcry_mpi_aprint( GCRYMPI_FMT_USG, &p, &n, sig->data[i] ) )
- BUG();
- gcry_md_write( md, p, n );
- gcry_free(p);
+ unsigned n = mpi_get_nbits( sig->data[i]);
+
+ md_putc( md, n>>8);
+ md_putc( md, n );
+ p = mpi_get_buffer( sig->data[i], &n, NULL );
+ md_write( md, p, n );
+ m_free(p);
}
- gcry_md_final( md );
- p = make_radix64_string( gcry_md_read( md, 0 ), 20 );
- buffer = gcry_xmalloc( strlen(p) + 60 );
+ md_final( md );
+ p = make_radix64_string( md_read( md, 0 ), 20 );
+ buffer = m_alloc( strlen(p) + 60 );
sprintf( buffer, "%s %s %lu",
p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
write_status_text( STATUS_SIG_ID, buffer );
- gcry_free(buffer);
- gcry_free(p);
- gcry_md_close(md);
+ m_free(buffer);
+ m_free(p);
+ md_close(md);
}
return rc;
@@ -203,7 +129,7 @@ cmp_help( void *opaque, MPI result )
size_t mdlen, asnlen;
struct cmp_help_context_s *ctx = opaque;
PKT_signature *sig = ctx->sig;
- GCRY_MD_HD digest = ctx->md;
+ MD_HANDLE digest = ctx->md;
old_enc = 0;
for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
@@ -226,7 +152,7 @@ cmp_help( void *opaque, MPI result )
}
if( old_enc ) {
log_error("old encoding scheme is not supported\n");
- return GPGERR_GENERAL;
+ return G10ERR_GENERAL;
}
if( (rc=check_digest_algo(sig->digest_algo)) )
@@ -238,25 +164,25 @@ cmp_help( void *opaque, MPI result )
if( asn[j] != c )
break;
if( j != -1 || mpi_getbyte(result, i) )
- return GPGERR_BAD_PUBKEY; /* ASN is wrong */
+ return G10ERR_BAD_PUBKEY; /* ASN is wrong */
for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
if( c != 0xff )
break;
i++;
if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
/* Padding or leading bytes in signature is wrong */
- return GPGERR_BAD_PUBKEY;
+ return G10ERR_BAD_PUBKEY;
}
if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
|| mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
/* Wrong key used to check the signature */
- return GPGERR_BAD_PUBKEY;
+ return G10ERR_BAD_PUBKEY;
}
dp = md_read( digest, sig->digest_algo );
for(i=mdlen-1; i >= 0; i--, dp++ ) {
if( mpi_getbyte( result, i ) != *dp )
- return GPGERR_BAD_SIGN;
+ return G10ERR_BAD_SIGN;
}
return 0;
#else
@@ -266,7 +192,7 @@ cmp_help( void *opaque, MPI result )
static int
-do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest,
+do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
int *r_expired )
{
MPI result = NULL;
@@ -275,10 +201,10 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest,
u32 cur_time;
*r_expired = 0;
- if( pk->version == 4 && pk->pubkey_algo == GCRY_PK_ELG_E ) {
+ if( pk->version == 4 && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
log_info(_("this is a PGP generated "
- "ElGamal key which is NOT secure for signatures!\n"));
- return GPGERR_PUBKEY_ALGO;
+ "ElGamal key which is NOT secure for signatures!\n"));
+ return G10ERR_PUBKEY_ALGO;
}
if( pk->timestamp > sig->timestamp ) {
@@ -288,7 +214,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest,
: _("public key is %lu seconds newer than the signature\n"),
d );
if( !opt.ignore_time_conflict )
- return GPGERR_TIME_CONFLICT; /* pubkey newer than signature */
+ return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */
}
cur_time = make_timestamp();
@@ -299,44 +225,55 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest,
: _("key has been created %lu seconds "
"in future (time warp or clock problem)\n"), d );
if( !opt.ignore_time_conflict )
- return GPGERR_TIME_CONFLICT;
+ return G10ERR_TIME_CONFLICT;
}
if( pk->expiredate && pk->expiredate < cur_time ) {
- log_info(_("NOTE: signature key expired %s\n"),
- asctimestamp( pk->expiredate ) );
+ char buf[11];
+ if (opt.verbose) {
+ u32 tmp_kid[2];
+
+ keyid_from_pk( pk, tmp_kid );
+ log_info(_("NOTE: signature key %08lX expired %s\n"),
+ (ulong)tmp_kid[1], asctimestamp( pk->expiredate ) );
+ }
+ /* SIGEXPIRED is deprecated. Use KEYEXPIRED. */
+ sprintf(buf,"%lu",(ulong)pk->expiredate);
+ write_status_text(STATUS_KEYEXPIRED,buf);
write_status(STATUS_SIGEXPIRED);
*r_expired = 1;
}
- if( (rc=openpgp_md_test_algo(sig->digest_algo)) )
+ if( (rc=check_digest_algo(sig->digest_algo)) )
return rc;
- if( (rc=openpgp_pk_test_algo(sig->pubkey_algo, 0)) )
+ if( (rc=check_pubkey_algo(sig->pubkey_algo)) )
return rc;
/* make sure the digest algo is enabled (in case of a detached signature)*/
- gcry_md_enable( digest, sig->digest_algo );
+ md_enable( digest, sig->digest_algo );
/* complete the digest */
if( sig->version >= 4 )
- gcry_md_putc( digest, sig->version );
- gcry_md_putc( digest, sig->sig_class );
+ md_putc( digest, sig->version );
+ md_putc( digest, sig->sig_class );
if( sig->version < 4 ) {
u32 a = sig->timestamp;
- gcry_md_putc( digest, (a >> 24) & 0xff );
- gcry_md_putc( digest, (a >> 16) & 0xff );
- gcry_md_putc( digest, (a >> 8) & 0xff );
- gcry_md_putc( digest, a & 0xff );
+ md_putc( digest, (a >> 24) & 0xff );
+ md_putc( digest, (a >> 16) & 0xff );
+ md_putc( digest, (a >> 8) & 0xff );
+ md_putc( digest, a & 0xff );
}
else {
byte buf[6];
size_t n;
- gcry_md_putc( digest, sig->pubkey_algo );
- gcry_md_putc( digest, sig->digest_algo );
- if( sig->hashed_data ) {
- n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
- gcry_md_write( digest, sig->hashed_data, n+2 );
+ md_putc( digest, sig->pubkey_algo );
+ md_putc( digest, sig->digest_algo );
+ if( sig->hashed ) {
+ n = sig->hashed->len;
+ md_putc (digest, (n >> 8) );
+ md_putc (digest, n );
+ md_write (digest, sig->hashed->data, n);
n += 6;
}
else
@@ -348,57 +285,61 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest,
buf[3] = n >> 16;
buf[4] = n >> 8;
buf[5] = n;
- gcry_md_write( digest, buf, 6 );
+ md_write( digest, buf, 6 );
}
- gcry_md_final( digest );
+ md_final( digest );
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
- gcry_mpi_get_nbits(pk->pkey[0]), 0);
+ mpi_get_nbits(pk->pkey[0]), 0 );
+ if (!result)
+ return G10ERR_GENERAL;
ctx.sig = sig;
ctx.md = digest;
- rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
+ rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
cmp_help, &ctx );
- mpi_release( result );
+ mpi_free( result );
if( (opt.emulate_bugs & EMUBUG_MDENCODE)
- && rc == GPGERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) {
+ && rc == G10ERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) {
/* In this case we try again because old GnuPG versions didn't encode
* the hash right. There is no problem with DSA however */
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
- gcry_mpi_get_nbits(pk->pkey[0]), (sig->version < 5) );
- ctx.sig = sig;
- ctx.md = digest;
- rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
- cmp_help, &ctx );
+ mpi_get_nbits(pk->pkey[0]), (sig->version < 5) );
+ if (!result)
+ rc = G10ERR_GENERAL;
+ else {
+ ctx.sig = sig;
+ ctx.md = digest;
+ rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
+ cmp_help, &ctx );
+ }
}
if( !rc && sig->flags.unknown_critical ) {
log_info(_("assuming bad signature due to an unknown critical bit\n"));
- rc = GPGERR_BAD_SIGN;
+ rc = G10ERR_BAD_SIGN;
}
- sig->flags.checked = 1;
- sig->flags.valid = !rc;
return rc;
}
static void
-hash_uid_node( KBNODE unode, GCRY_MD_HD md, PKT_signature *sig )
+hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
{
PKT_user_id *uid = unode->pkt->pkt.user_id;
assert( unode->pkt->pkttype == PKT_USER_ID );
- if( uid->photo ) {
+ if( uid->attrib_data ) {
if( sig->version >=4 ) {
byte buf[5];
- buf[0] = 0xd1; /* packet of type 17 */
- buf[1] = uid->photolen >> 24; /* always use 4 length bytes */
- buf[2] = uid->photolen >> 16;
- buf[3] = uid->photolen >> 8;
- buf[4] = uid->photolen;
- gcry_md_write( md, buf, 5 );
+ buf[0] = 0xd1; /* packet of type 17 */
+ buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->attrib_len >> 16;
+ buf[3] = uid->attrib_len >> 8;
+ buf[4] = uid->attrib_len;
+ md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->photo, uid->photolen );
+ md_write( md, uid->attrib_data, uid->attrib_len );
}
else {
if( sig->version >=4 ) {
@@ -408,9 +349,26 @@ hash_uid_node( KBNODE unode, GCRY_MD_HD md, PKT_signature *sig )
buf[2] = uid->len >> 16;
buf[3] = uid->len >> 8;
buf[4] = uid->len;
- gcry_md_write( md, buf, 5 );
+ md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->name, uid->len );
+ md_write( md, uid->name, uid->len );
+ }
+}
+
+static void
+cache_sig_result ( PKT_signature *sig, int result )
+{
+ if ( !result ) {
+ sig->flags.checked = 1;
+ sig->flags.valid = 1;
+ }
+ else if ( result == G10ERR_BAD_SIGN ) {
+ sig->flags.checked = 1;
+ sig->flags.valid = 0;
+ }
+ else {
+ sig->flags.checked = 0;
+ sig->flags.valid = 0;
}
}
@@ -431,7 +389,7 @@ int
check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
u32 *r_expiredate, int *r_expired )
{
- GCRY_MD_HD md;
+ MD_HANDLE md;
PKT_public_key *pk;
PKT_signature *sig;
int algo;
@@ -448,47 +406,49 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
- #if 0
- if( sig->flags.checked ) {
- log_debug("check_key_signature: already checked: %s\n",
- sig->flags.valid? "good":"bad" );
- if ( sig->flags.valid )
- return 0; /* shortcut already checked signatures */
- /* FIXME: We should also do this with bad signatures but here we
- * have to distinguish between several reasons; e.g. for a missing
- * public key. the key may now be available.
- * For now we simply don't shortcut bad signatures
- */
+ /* check whether we have cached the result of a previous signature check.*/
+ if ( !opt.no_sig_cache ) {
+ if (sig->flags.checked) { /*cached status available*/
+ if( is_selfsig ) {
+ u32 keyid[2];
+
+ keyid_from_pk( pk, keyid );
+ if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
+ *is_selfsig = 1;
+ }
+ return sig->flags.valid? 0 : G10ERR_BAD_SIGN;
+ }
}
- #endif
- if( (rc=openpgp_md_test_algo(algo)) )
+ if( (rc=check_digest_algo(algo)) )
return rc;
- if( sig->sig_class == 0x20 ) {
- if( !(md = gcry_md_open( algo, 0 )) )
- BUG();
+ if( sig->sig_class == 0x20 ) { /* key revocation */
+ md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
- gcry_md_close(md);
+ cache_sig_result ( sig, rc );
+ md_close(md);
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
if( snode ) {
- if( !(md = gcry_md_open( algo, 0 )) )
- BUG();
+ md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
- gcry_md_close(md);
+ cache_sig_result ( sig, rc );
+ md_close(md);
}
else {
- log_error("no subkey for subkey revocation packet\n");
- rc = GPGERR_SIG_CLASS;
+ if (!opt.quiet)
+ log_info ("key %08lX: no subkey for subkey revocation packet\n",
+ (ulong)keyid_from_pk (pk, NULL));
+ rc = G10ERR_SIG_CLASS;
}
}
- else if( sig->sig_class == 0x18 ) {
+ else if( sig->sig_class == 0x18 ) { /* key binding */
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
if( snode ) {
@@ -499,27 +459,35 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
*is_selfsig = 1;
}
- if( !(md = gcry_md_open( algo, 0 )) )
- BUG();
+ md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
- gcry_md_close(md);
+ cache_sig_result ( sig, rc );
+ md_close(md);
}
else {
- log_error("no subkey for key signature packet\n");
- rc = GPGERR_SIG_CLASS;
+ if (!opt.quiet)
+ log_info ("key %08lX: no subkey for subkey binding packet\n",
+ (ulong)keyid_from_pk (pk, NULL));
+ rc = G10ERR_SIG_CLASS;
}
}
- else {
+ else if( sig->sig_class == 0x1f ) { /* direct key signature */
+ md = md_open( algo, 0 );
+ hash_public_key( md, pk );
+ rc = do_check( pk, sig, md, r_expired );
+ cache_sig_result ( sig, rc );
+ md_close(md);
+ }
+ else { /* all other classes */
KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
if( unode ) {
u32 keyid[2];
keyid_from_pk( pk, keyid );
- if( !(md = gcry_md_open( algo, 0 )) )
- BUG();
+ md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_uid_node( unode, md, sig );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
@@ -528,13 +496,17 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
rc = do_check( pk, sig, md, r_expired );
}
else {
- rc = do_signature_check( sig, md, r_expiredate, r_expired );
+ rc = signature_check2( sig, md, r_expiredate, r_expired );
}
- gcry_md_close(md);
+ cache_sig_result ( sig, rc );
+ md_close(md);
}
else {
- log_error("no user ID for key signature packet\n");
- rc = GPGERR_SIG_CLASS;
+ if (!opt.quiet)
+ log_info ("key %08lX: no user ID for key signature packet "
+ "of class %02x\n",
+ (ulong)keyid_from_pk (pk, NULL), sig->sig_class );
+ rc = G10ERR_SIG_CLASS;
}
}
diff --git a/g10/sign.c b/g10/sign.c
index bdc5b8afe..6a8ce2991 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1,5 +1,5 @@
/* sign.c - sign data
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,13 +24,14 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <unistd.h> /* need sleep() */
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "filter.h"
@@ -40,125 +41,212 @@
#include "i18n.h"
-#define ENABLE_BETTER_PGP2_COMPAT 1
-
#ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n"
+ void __stdcall Sleep(ulong);
+ #define sleep(a) Sleep((a)*1000)
#else
#define LF "\n"
#endif
+static int recipient_digest_algo=0;
+
/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
+ * Create a notation. It is assumed that the stings in STRLIST
+ * are already checked to contain only printable data and have a valid
+ * NAME=VALUE format.
*/
-static int
-pk_sign( int algo, MPI *data, MPI hash, MPI *skey )
+static void
+mk_notation_and_policy( PKT_signature *sig,
+ PKT_public_key *pk, PKT_secret_key *sk )
{
- GCRY_SEXP s_sig, s_hash, s_skey, list;
- int rc;
+ const char *string;
+ char *s=NULL;
+ byte *buf;
+ unsigned n1, n2;
+ STRLIST nd=NULL,pu=NULL;
+ struct expando_args args;
- /* make a sexp from skey */
- if( algo == GCRY_PK_DSA ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3], skey[4] );
- }
- else if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) {
- rc = gcry_sexp_build ( &s_skey, NULL,
- "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
- skey[0], skey[1], skey[2], skey[3] );
- }
- else
- return GPGERR_PUBKEY_ALGO;
+ memset(&args,0,sizeof(args));
+ args.pk=pk;
+ args.sk=sk;
- if ( rc )
- BUG ();
+ /* notation data */
+ if(IS_SIG(sig) && opt.sig_notation_data)
+ {
+ if(sig->version<4)
+ log_info("can't put notation data into v3 signatures\n");
+ else
+ nd=opt.sig_notation_data;
+ }
+ else if( IS_CERT(sig) && opt.cert_notation_data )
+ {
+ if(sig->version<4)
+ log_info("can't put notation data into v3 key signatures\n");
+ else
+ nd=opt.cert_notation_data;
+ }
+
+ for( ; nd; nd = nd->next ) {
+ char *expanded;
+
+ string = nd->d;
+ s = strchr( string, '=' );
+ if( !s )
+ BUG(); /* we have already parsed this */
+ n1 = s - string;
+ s++;
+
+ expanded=pct_expando(s,&args);
+ if(!expanded)
+ {
+ log_error(_("WARNING: unable to %%-expand notation "
+ "(too large). Using unexpanded.\n"));
+ expanded=m_strdup(s);
+ }
+
+ n2 = strlen(expanded);
+ buf = m_alloc( 8 + n1 + n2 );
+ buf[0] = 0x80; /* human readable */
+ buf[1] = buf[2] = buf[3] = 0;
+ buf[4] = n1 >> 8;
+ buf[5] = n1;
+ buf[6] = n2 >> 8;
+ buf[7] = n2;
+ memcpy(buf+8, string, n1 );
+ memcpy(buf+8+n1, expanded, n2 );
+ build_sig_subpkt( sig, SIGSUBPKT_NOTATION
+ | ((nd->flags & 1)? SIGSUBPKT_FLAG_CRITICAL:0),
+ buf, 8+n1+n2 );
+ m_free(expanded);
+ m_free(buf);
+ }
- /* put hash into a S-Exp s_hash */
- if ( gcry_sexp_build( &s_hash, NULL, "%m", hash ) )
- BUG ();
+ if(opt.show_notation)
+ show_notation(sig,0);
- rc = gcry_pk_sign( &s_sig, s_hash, s_skey );
- gcry_sexp_release( s_hash );
- gcry_sexp_release( s_skey );
+ /* set policy URL */
+ if( IS_SIG(sig) && opt.sig_policy_url )
+ {
+ if(sig->version<4)
+ log_info("can't put a policy URL into v3 signatures\n");
+ else
+ pu=opt.sig_policy_url;
+ }
+ else if( IS_CERT(sig) && opt.cert_policy_url )
+ {
+ if(sig->version<4)
+ log_info("can't put a policy URL into v3 key signatures\n");
+ else
+ pu=opt.cert_policy_url;
+ }
+
+ for(;pu;pu=pu->next)
+ {
+ string = pu->d;
+
+ s=pct_expando(string,&args);
+ if(!s)
+ {
+ log_error(_("WARNING: unable to %%-expand policy url "
+ "(too large). Using unexpanded.\n"));
+ s=m_strdup(string);
+ }
+
+ build_sig_subpkt(sig,SIGSUBPKT_POLICY|
+ ((pu->flags & 1)?SIGSUBPKT_FLAG_CRITICAL:0),
+ s,strlen(s));
+
+ m_free(s);
+ }
+
+ if(opt.show_policy_url)
+ show_policy_url(sig,0);
+}
- if( rc )
- ;
- else {
- list = gcry_sexp_find_token( s_sig, "r" , 0 );
- assert( list );
- data[0] = gcry_sexp_nth_mpi( list, 1, 0 );
- assert( data[0] );
- gcry_sexp_release (list);
- list = gcry_sexp_find_token( s_sig, "s" , 0 );
- assert( list );
- data[1] = gcry_sexp_nth_mpi( list, 1, 0 );
- assert( data[1] );
- gcry_sexp_release (list);
+/*
+ * Helper to hash a user ID packet.
+ */
+static void
+hash_uid (MD_HANDLE md, int sigversion, const PKT_user_id *uid)
+{
+ if ( sigversion >= 4 ) {
+ byte buf[5];
+
+ if(uid->attrib_data) {
+ buf[0] = 0xd1; /* indicates an attribute packet */
+ buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->attrib_len >> 16;
+ buf[3] = uid->attrib_len >> 8;
+ buf[4] = uid->attrib_len;
+ }
+ else {
+ buf[0] = 0xb4; /* indicates a userid packet */
+ buf[1] = uid->len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->len >> 16;
+ buf[3] = uid->len >> 8;
+ buf[4] = uid->len;
+ }
+ md_write( md, buf, 5 );
}
-
- gcry_sexp_release( s_sig );
- return rc;
+ if(uid->attrib_data)
+ md_write (md, uid->attrib_data, uid->attrib_len );
+ else
+ md_write (md, uid->name, uid->len );
}
-/****************
- * Create a notation. It is assumed that the stings in STRLIST
- * are already checked to contain only printable data and have a valid
- * NAME=VALUE format.
+
+/*
+ * Helper to hash some parts from the signature
*/
static void
-mk_notation_and_policy( PKT_signature *sig )
+hash_sigversion_to_magic (MD_HANDLE md, const PKT_signature *sig)
{
- const char *string, *s;
- byte *buf;
- unsigned n1, n2;
-
- /* notation data */
- if( opt.notation_data && sig->version < 4 )
- log_info("can't put notation data into v3 signatures\n");
- else if( opt.notation_data ) {
- STRLIST nd = opt.notation_data;
-
- for( ; nd; nd = nd->next ) {
- string = nd->d;
- s = strchr( string, '=' );
- if( !s )
- BUG(); /* we have already parsed this */
- n1 = s - string;
- s++;
- n2 = strlen(s);
- buf = gcry_xmalloc( 8 + n1 + n2 );
- buf[0] = 0x80; /* human readable */
- buf[1] = buf[2] = buf[3] = 0;
- buf[4] = n1 >> 8;
- buf[5] = n1;
- buf[6] = n2 >> 8;
- buf[7] = n2;
- memcpy(buf+8, string, n1 );
- memcpy(buf+8+n1, s, n2 );
- build_sig_subpkt( sig, SIGSUBPKT_NOTATION
- | ((nd->flags & 1)? SIGSUBPKT_FLAG_CRITICAL:0),
- buf, 8+n1+n2 );
- }
+ if (sig->version >= 4)
+ md_putc (md, sig->version);
+ md_putc (md, sig->sig_class);
+ if (sig->version < 4) {
+ u32 a = sig->timestamp;
+ md_putc (md, (a >> 24) & 0xff );
+ md_putc (md, (a >> 16) & 0xff );
+ md_putc (md, (a >> 8) & 0xff );
+ md_putc (md, a & 0xff );
}
-
- /* set policy URL */
- if( (s=opt.set_policy_url) ) {
- if( *s == '!' )
- build_sig_subpkt( sig, SIGSUBPKT_POLICY | SIGSUBPKT_FLAG_CRITICAL,
- s+1, strlen(s+1) );
- else
- build_sig_subpkt( sig, SIGSUBPKT_POLICY, s, strlen(s) );
+ else {
+ byte buf[6];
+ size_t n;
+
+ md_putc (md, sig->pubkey_algo);
+ md_putc (md, sig->digest_algo);
+ if (sig->hashed) {
+ n = sig->hashed->len;
+ md_putc (md, (n >> 8) );
+ md_putc (md, n );
+ md_write (md, sig->hashed->data, n );
+ n += 6;
+ }
+ else {
+ md_putc (md, 0); /* always hash the length of the subpacket*/
+ md_putc (md, 0);
+ n = 6;
+ }
+ /* add some magic */
+ buf[0] = sig->version;
+ buf[1] = 0xff;
+ buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
+ buf[3] = n >> 16;
+ buf[4] = n >> 8;
+ buf[5] = n;
+ md_write (md, buf, 6);
}
}
static int
do_sign( PKT_secret_key *sk, PKT_signature *sig,
- GCRY_MD_HD md, int digest_algo )
+ MD_HANDLE md, int digest_algo )
{
MPI frame;
byte *dp;
@@ -171,32 +259,59 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
: _("key has been created %lu seconds "
"in future (time warp or clock problem)\n"), d );
if( !opt.ignore_time_conflict )
- return GPGERR_TIME_CONFLICT;
+ return G10ERR_TIME_CONFLICT;
}
print_pubkey_algo_note(sk->pubkey_algo);
if( !digest_algo )
- digest_algo = gcry_md_get_algo(md);
+ digest_algo = md_get_algo(md);
print_digest_algo_note( digest_algo );
- dp = gcry_md_read( md, digest_algo );
+ dp = md_read( md, digest_algo );
sig->digest_algo = digest_algo;
sig->digest_start[0] = dp[0];
sig->digest_start[1] = dp[1];
frame = encode_md_value( sk->pubkey_algo, md,
- digest_algo, gcry_mpi_get_nbits(sk->skey[0]), 0 );
- rc = pk_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
- mpi_release(frame);
+ digest_algo, mpi_get_nbits(sk->skey[0]), 0 );
+ if (!frame)
+ return G10ERR_GENERAL;
+ rc = pubkey_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
+ mpi_free(frame);
+ if (!rc && !opt.no_sig_create_check) {
+ /* check that the signature verification worked and nothing is
+ * fooling us e.g. by a bug in the signature create
+ * code or by deliberately introduced faults. */
+ PKT_public_key *pk = m_alloc_clear (sizeof *pk);
+
+ if( get_pubkey( pk, sig->keyid ) )
+ rc = G10ERR_NO_PUBKEY;
+ else {
+ frame = encode_md_value (pk->pubkey_algo, md,
+ sig->digest_algo,
+ mpi_get_nbits(pk->pkey[0]), 0);
+ if (!frame)
+ rc = G10ERR_GENERAL;
+ else
+ rc = pubkey_verify (pk->pubkey_algo, frame,
+ sig->data, pk->pkey,
+ NULL, NULL );
+ mpi_free (frame);
+ }
+ if (rc)
+ log_error (_("checking created signature failed: %s\n"),
+ g10_errstr (rc));
+ free_public_key (pk);
+ }
if( rc )
- log_error(_("signing failed: %s\n"), gpg_errstr(rc) );
+ log_error(_("signing failed: %s\n"), g10_errstr(rc) );
else {
if( opt.verbose ) {
char *ustr = get_user_id_string( sig->keyid );
log_info(_("%s signature from: %s\n"),
- gcry_pk_algo_name(sk->pubkey_algo), ustr );
- gcry_free(ustr);
+ pubkey_algo_to_string(sk->pubkey_algo), ustr );
+ m_free(ustr);
}
}
return rc;
@@ -205,16 +320,12 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
int
-complete_sig( PKT_signature *sig, PKT_secret_key *sk, GCRY_MD_HD md )
+complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md )
{
int rc=0;
if( !(rc=check_secret_key( sk, 0 )) )
rc = do_sign( sk, sig, md, 0 );
-
- /* fixme: should we check whether the signature is okay?
- * maybe by using an option */
-
return rc;
}
@@ -223,10 +334,12 @@ hash_for(int pubkey_algo, int packet_version )
{
if( opt.def_digest_algo )
return opt.def_digest_algo;
- if( pubkey_algo == GCRY_PK_DSA )
- return GCRY_MD_SHA1;
- if( pubkey_algo == GCRY_PK_RSA && packet_version < 4 )
- return GCRY_MD_MD5;
+ if( recipient_digest_algo )
+ return recipient_digest_algo;
+ if( pubkey_algo == PUBKEY_ALGO_DSA )
+ return DIGEST_ALGO_SHA1;
+ if( pubkey_algo == PUBKEY_ALGO_RSA && packet_version < 4 )
+ return DIGEST_ALGO_MD5;
return DEFAULT_DIGEST_ALGO;
}
@@ -239,7 +352,7 @@ only_old_style( SK_LIST sk_list )
/* if there are only old style capable key we use the old sytle */
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
PKT_secret_key *sk = sk_rover->sk;
- if( sk->pubkey_algo == GCRY_PK_RSA && sk->version < 4 )
+ if( sk->pubkey_algo == PUBKEY_ALGO_RSA && sk->version < 4 )
old_style = 1;
else
return 0;
@@ -267,94 +380,210 @@ print_status_sig_created ( PKT_secret_key *sk, PKT_signature *sig, int what )
write_status_text( STATUS_SIG_CREATED, buf );
}
+
+/*
+ * Loop over the secret certificates in SK_LIST and build the one pass
+ * signature packets. OpenPGP says that the data should be bracket by
+ * the onepass-sig and signature-packet; so we build these onepass
+ * packet here in reverse order
+ */
static int
-write_one_signature( IOBUF out, PKT_secret_key *sk, int old_style,
- const char *outfile,
- GCRY_MD_HD datamd,
- int sig_class,
- int status_char )
+write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
{
- PKT_signature *sig;
- GCRY_MD_HD md;
- int rc;
+ int skcount;
+ SK_LIST sk_rover;
- /* build the signature packet */
- /* fixme: this code is partly duplicated in make_keysig_packet */
- sig = gcry_xcalloc( 1, sizeof *sig );
- sig->version = old_style || opt.force_v3_sigs ? 3 : sk->version;
- keyid_from_sk( sk, sig->keyid );
- sig->digest_algo = hash_for(sk->pubkey_algo, sk->version);
- sig->pubkey_algo = sk->pubkey_algo;
- sig->timestamp = make_timestamp();
- sig->sig_class = sig_class;
+ for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next)
+ skcount++;
- md = gcry_md_copy( datamd );
- if( !md )
- BUG();
- if( sig->version >= 4 ) {
- build_sig_subpkt_from_sig( sig );
- gcry_md_putc( md, sig->version );
- }
-
- mk_notation_and_policy( sig );
-
- gcry_md_putc( md, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- gcry_md_putc( md, (a >> 24) & 0xff );
- gcry_md_putc( md, (a >> 16) & 0xff );
- gcry_md_putc( md, (a >> 8) & 0xff );
- gcry_md_putc( md, a & 0xff );
- }
- else {
- byte buf[6];
- size_t n;
+ for (; skcount; skcount--) {
+ PKT_secret_key *sk;
+ PKT_onepass_sig *ops;
+ PACKET pkt;
+ int i, rc;
- gcry_md_putc( md, sig->pubkey_algo );
- gcry_md_putc( md, sig->digest_algo );
- if( sig->hashed_data ) {
- n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
- gcry_md_write( md, sig->hashed_data, n+2 );
- n += 6;
+ for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
+ if (++i == skcount)
+ break;
}
- else {
- gcry_md_putc( md, 0 );/* always hash the length of the subpacket*/
- gcry_md_putc( md, 0 );
- n = 6;
+
+ sk = sk_rover->sk;
+ ops = m_alloc_clear (sizeof *ops);
+ ops->sig_class = sigclass;
+ ops->digest_algo = hash_for (sk->pubkey_algo, sk->version);
+ ops->pubkey_algo = sk->pubkey_algo;
+ keyid_from_sk (sk, ops->keyid);
+ ops->last = (skcount == 1);
+
+ init_packet(&pkt);
+ pkt.pkttype = PKT_ONEPASS_SIG;
+ pkt.pkt.onepass_sig = ops;
+ rc = build_packet (out, &pkt);
+ free_packet (&pkt);
+ if (rc) {
+ log_error ("build onepass_sig packet failed: %s\n",
+ g10_errstr(rc));
+ return rc;
}
- /* add some magic */
- buf[0] = sig->version;
- buf[1] = 0xff;
- buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
- buf[3] = n >> 16;
- buf[4] = n >> 8;
- buf[5] = n;
- gcry_md_write( md, buf, 6 );
}
- gcry_md_final( md );
- rc = do_sign( sk, sig, md, hash_for(sig->pubkey_algo, sk->version) );
- gcry_md_close( md );
- /* Hmmm: Do we release sig in case of rc != 0? */
-
- if( !rc ) { /* and write it */
- PACKET pkt;
+ return 0;
+}
- init_packet(&pkt);
- pkt.pkttype = PKT_SIGNATURE;
- pkt.pkt.signature = sig;
- rc = build_packet( out, &pkt );
- if( !rc && is_status_enabled() ) {
- print_status_sig_created ( sk, sig, status_char );
+/*
+ * Helper to write the plaintext (literal data) packet
+ */
+static int
+write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
+{
+ PKT_plaintext *pt = NULL;
+ u32 filesize;
+ int rc = 0;
+
+ if (!opt.no_literal) {
+ if (fname || opt.set_filename) {
+ char *s = make_basename (opt.set_filename? opt.set_filename
+ : fname);
+ pt = m_alloc (sizeof *pt + strlen(s) - 1);
+ pt->namelen = strlen (s);
+ memcpy (pt->name, s, pt->namelen);
+ m_free (s);
+ }
+ else { /* no filename */
+ pt = m_alloc (sizeof *pt - 1);
+ pt->namelen = 0;
}
- free_packet( &pkt );
- if( rc )
- log_error("build signature packet failed: %s\n", gpg_errstr(rc) );
}
+ /* try to calculate the length of the data */
+ if (fname) {
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info (_("WARNING: `%s' is an empty file\n"), fname);
+
+ /* we can't yet encode the length of very large files,
+ * so we switch to partial length encoding in this case */
+ if (filesize >= IOBUF_FILELENGTH_LIMIT)
+ filesize = 0;
+
+ /* because the text_filter modifies the length of the
+ * data, it is not possible to know the used length
+ * without a double read of the file - to avoid that
+ * we simple use partial length packets.
+ */
+ if ( ptmode == 't' )
+ filesize = 0;
+ }
+ else {
+ filesize = opt.set_filesize? opt.set_filesize : 0; /* stdin */
+ }
+
+ if (!opt.no_literal) {
+ PACKET pkt;
+
+ pt->timestamp = make_timestamp ();
+ pt->mode = ptmode;
+ pt->len = filesize;
+ pt->new_ctb = !pt->len && !opt.rfc1991;
+ pt->buf = inp;
+ init_packet(&pkt);
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
+ if( (rc = build_packet (out, &pkt)) )
+ log_error ("build_packet(PLAINTEXT) failed: %s\n",
+ g10_errstr(rc) );
+ pt->buf = NULL;
+ }
+ else {
+ byte copy_buffer[4096];
+ int bytes_copied;
+
+ while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
+ if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
+ rc = G10ERR_WRITE_FILE;
+ log_error ("copying input to output failed: %s\n",
+ g10_errstr(rc));
+ break;
+ }
+ memset(copy_buffer, 0, 4096); /* burn buffer */
+ }
+ /* fixme: it seems that we never freed pt/pkt */
+
return rc;
}
+/*
+ * Write the signatures from the SK_LIST to OUT. HASH must be a non-finalized
+ * hash which will not be changes here.
+ */
+static int
+write_signature_packets (SK_LIST sk_list, IOBUF out, MD_HANDLE hash,
+ int sigclass, u32 timestamp, u32 duration,
+ int status_letter)
+{
+ SK_LIST sk_rover;
+
+ /* loop over the secret certificates */
+ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) {
+ PKT_secret_key *sk;
+ PKT_signature *sig;
+ MD_HANDLE md;
+ int rc;
+
+ sk = sk_rover->sk;
+
+ /* build the signature packet */
+ sig = m_alloc_clear (sizeof *sig);
+ if(opt.force_v3_sigs || opt.rfc1991)
+ sig->version=3;
+ else if(duration || opt.sig_policy_url || opt.sig_notation_data)
+ sig->version=4;
+ else
+ sig->version=sk->version;
+ keyid_from_sk (sk, sig->keyid);
+ sig->digest_algo = hash_for (sk->pubkey_algo, sk->version);
+ sig->pubkey_algo = sk->pubkey_algo;
+ if(timestamp)
+ sig->timestamp = timestamp;
+ else
+ sig->timestamp = make_timestamp();
+ if(duration)
+ sig->expiredate = sig->timestamp+duration;
+ sig->sig_class = sigclass;
+
+ md = md_copy (hash);
+
+ if (sig->version >= 4)
+ build_sig_subpkt_from_sig (sig);
+ mk_notation_and_policy (sig, NULL, sk);
+
+ hash_sigversion_to_magic (md, sig);
+ md_final (md);
+
+ rc = do_sign( sk, sig, md, hash_for (sig->pubkey_algo, sk->version) );
+ md_close (md);
+
+ if( !rc ) { /* and write it */
+ PACKET pkt;
+
+ init_packet(&pkt);
+ pkt.pkttype = PKT_SIGNATURE;
+ pkt.pkt.signature = sig;
+ rc = build_packet (out, &pkt);
+ if (!rc && is_status_enabled()) {
+ print_status_sig_created ( sk, sig, status_letter);
+ }
+ free_packet (&pkt);
+ if (rc)
+ log_error ("build signature packet failed: %s\n",
+ g10_errstr(rc) );
+ }
+ if( rc )
+ return rc;;
+ }
+
+ return 0;
+}
/****************
* Sign the files whose names are in FILENAME.
@@ -362,7 +591,7 @@ write_one_signature( IOBUF out, PKT_secret_key *sk, int old_style,
* make a detached signature. If FILENAMES->d is NULL read from stdin
* and ignore the detached mode. Sign the file with all secret keys
* which can be taken from LOCUSR, if this is NULL, use the default one
- * If ENCRYPT is true, use REMUSER (or ask if it is NULL) to encrypt the
+ * If ENCRYPTFLAG is true, use REMUSER (or ask if it is NULL) to encrypt the
* signed data for these users.
* If OUTFILE is not NULL; this file is used for output and the function
* does not ask for overwrite permission; output is then always
@@ -370,7 +599,7 @@ write_one_signature( IOBUF out, PKT_secret_key *sk, int old_style,
*/
int
sign_file( STRLIST filenames, int detached, STRLIST locusr,
- int encrypt, STRLIST remusr, const char *outfile )
+ int encryptflag, STRLIST remusr, const char *outfile )
{
const char *fname;
armor_filter_context_t afx;
@@ -380,16 +609,12 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
encrypt_filter_context_t efx;
IOBUF inp = NULL, out = NULL;
PACKET pkt;
- PKT_plaintext *pt = NULL;
- u32 filesize;
int rc = 0;
PK_LIST pk_list = NULL;
SK_LIST sk_list = NULL;
SK_LIST sk_rover = NULL;
int multifile = 0;
- int old_style = opt.rfc1991;
- int compr_algo = -1; /* unknown */
-
+ u32 timestamp=0,duration=0;
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
@@ -405,20 +630,25 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
else
fname = NULL;
- if( fname && filenames->next && (!detached || encrypt) )
+ if( fname && filenames->next && (!detached || encryptflag) )
log_bug("multiple files can only be detached signed");
- if( (rc=build_sk_list( locusr, &sk_list, 1, GCRY_PK_USAGE_SIGN )) )
+ if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+ duration=ask_expire_interval(1);
+
+ if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
goto leave;
- if( !old_style )
- old_style = only_old_style( sk_list );
- if( encrypt ) {
- if( (rc=build_pk_list( remusr, &pk_list, GCRY_PK_USAGE_ENCR )) )
- goto leave;
- if( !old_style )
- compr_algo = select_algo_from_prefs( pk_list, PREFTYPE_COMPR );
- }
+ if(opt.pgp2 && !only_old_style(sk_list))
+ {
+ log_info(_("you can only detach-sign with PGP 2.x style keys "
+ "while in --pgp2 mode\n"));
+ log_info(_("this message may not be usable by PGP 2.x\n"));
+ opt.pgp2=0;
+ }
+
+ if(encryptflag && (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC )))
+ goto leave;
/* prepare iobufs */
if( multifile ) /* have list of filenames */
@@ -426,14 +656,14 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
else if( !(inp = iobuf_open(fname)) ) {
log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
if( outfile ) {
if( !(out = iobuf_create( outfile )) ) {
log_error(_("can't create %s: %s\n"), outfile, strerror(errno) );
- rc = GPGERR_CREATE_FILE;
+ rc = G10ERR_CREATE_FILE;
goto leave;
}
else if( opt.verbose )
@@ -445,92 +675,108 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
/* prepare to calculate the MD over the input */
if( opt.textmode && !outfile )
iobuf_push_filter( inp, text_filter, &tfx );
- if( !(mfx.md = gcry_md_open(0, 0)))
- BUG();
+ mfx.md = md_open(0, 0);
+
+ /* If we're encrypting and signing, it is reasonable to pick the
+ hash algorithm to use out of the recepient key prefs. */
+ if(pk_list)
+ {
+ if(opt.def_digest_algo)
+ {
+ if(!opt.expert &&
+ select_algo_from_prefs(pk_list,PREFTYPE_HASH,
+ opt.def_digest_algo,
+ NULL)!=opt.def_digest_algo)
+ log_info(_("forcing digest algorithm %s (%d) "
+ "violates recipient preferences\n"),
+ digest_algo_to_string(opt.def_digest_algo),
+ opt.def_digest_algo);
+ }
+ else
+ {
+ int hashlen=0,algo;
+
+ /* Of course, if the recipient asks for something
+ unreasonable (like a non-160-bit hash for DSA, for
+ example), then don't do it. Check all sk's - if any
+ are DSA, then the hash must be 160-bit. In the future
+ this can be more complex with different hashes for each
+ sk, but so long as there is only one signing algorithm
+ with hash restrictions, this is ok. -dms */
+
+ for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
+ if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA)
+ hashlen=20;
+
+ if((algo=
+ select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,&hashlen))>0)
+ recipient_digest_algo=algo;
+ }
+ }
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
PKT_secret_key *sk = sk_rover->sk;
- gcry_md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version ));
+ md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version ));
}
if( !multifile )
iobuf_push_filter( inp, md_filter, &mfx );
- if( detached && !encrypt && !opt.rfc1991 )
+ if( detached && !encryptflag && !opt.rfc1991 )
afx.what = 2;
if( opt.armor && !outfile )
iobuf_push_filter( out, armor_filter, &afx );
- #ifdef ENABLE_COMMENT_PACKETS
- else {
- write_comment( out, "#created by GNUPG v" VERSION " ("
- PRINTABLE_OS_NAME ")");
- if( opt.comment_string )
- write_comment( out, opt.comment_string );
- }
- #endif
- if( encrypt ) {
+
+ if( encryptflag ) {
efx.pk_list = pk_list;
/* fixme: set efx.cfx.datalen if known */
iobuf_push_filter( out, encrypt_filter, &efx );
}
- /* Select a compress algorithm */
- if( opt.compress && !outfile && ( !detached || opt.compress_sigs) ) {
- if( !compr_algo )
- ; /* don't use compression */
- else {
- if( old_style
- || compr_algo == 1
- || (compr_algo == -1 && !encrypt) )
- zfx.algo = 1; /* use the non optional algorithm */
+ if( opt.compress && !outfile && ( !detached || opt.compress_sigs) )
+ {
+ int compr_algo=opt.def_compress_algo;
+
+ /* If not forced by user */
+ if(compr_algo==-1)
+ {
+ /* If we're not encrypting, then select_algo_from_prefs
+ will fail and we'll end up with the default. If we are
+ encrypting, select_algo_from_prefs cannot fail since
+ there is an assumed preference for uncompressed data.
+ Still, if it did fail, we'll also end up with the
+ default. */
+
+ if((compr_algo=
+ select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
+ compr_algo=DEFAULT_COMPRESS_ALGO;
+ }
+ else if(!opt.expert &&
+ select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
+ compr_algo,NULL)!=compr_algo)
+ log_info(_("forcing compression algorithm %s (%d) "
+ "violates recipient preferences\n"),
+ compress_algo_to_string(compr_algo),compr_algo);
+
+ /* algo 0 means no compression */
+ if( compr_algo )
+ {
+ zfx.algo = compr_algo;
iobuf_push_filter( out, compress_filter, &zfx );
- }
- }
-
- /* Build one-pass signature packets when needed */
- if( !detached && !old_style ) {
- int skcount=0;
- /* loop over the secret certificates and build headers
- * The specs now say that the data should be bracket by
- * the onepass-sig and signature-packet; so we must build it
- * here in reverse order */
- for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
- skcount++;
- for( ; skcount; skcount-- ) {
- PKT_secret_key *sk;
- PKT_onepass_sig *ops;
- int i = 0;
-
- for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
- if( ++i == skcount )
- break;
-
- sk = sk_rover->sk;
- ops = gcry_xcalloc( 1, sizeof *ops );
- ops->sig_class = opt.textmode && !outfile ? 0x01 : 0x00;
- ops->digest_algo = hash_for(sk->pubkey_algo, sk->version);
- ops->pubkey_algo = sk->pubkey_algo;
- keyid_from_sk( sk, ops->keyid );
- ops->last = skcount == 1;
-
- init_packet(&pkt);
- pkt.pkttype = PKT_ONEPASS_SIG;
- pkt.pkt.onepass_sig = ops;
- rc = build_packet( out, &pkt );
- free_packet( &pkt );
- if( rc ) {
- log_error("build onepass_sig packet failed: %s\n",
- gpg_errstr(rc));
- goto leave;
- }
- }
+ }
+ }
+
+ /* Write the one-pass signature packets if needed */
+ if (!detached && !opt.rfc1991) {
+ rc = write_onepass_sig_packets (sk_list, out,
+ opt.textmode && !outfile ? 0x01:0x00);
+ if (rc)
+ goto leave;
}
/* setup the inner packet */
if( detached ) {
- /* this is pretty much the same for old and new PGP. So no
- * need to cope with different packet ordering */
if( multifile ) {
STRLIST sl;
@@ -542,7 +788,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
if( !(inp = iobuf_open(sl->d)) ) {
log_error(_("can't open %s: %s\n"),
sl->d, strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
if( opt.verbose )
@@ -562,92 +808,35 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
}
}
else {
- /* get the filename to be stored into the literal datapacket */
- if (!opt.no_literal) {
- if( fname || opt.set_filename ) {
- char *s = make_basename( opt.set_filename ?
- opt.set_filename : fname );
- pt = gcry_xmalloc( sizeof *pt + strlen(s) - 1 );
- pt->namelen = strlen(s);
- memcpy(pt->name, s, pt->namelen );
- gcry_free(s);
- }
- else { /* no filename */
- pt = gcry_xmalloc( sizeof *pt - 1 );
- pt->namelen = 0;
- }
- }
-
- if( fname ) {
- if( !(filesize = iobuf_get_filelength(inp)) )
- log_info(_("WARNING: `%s' is an empty file\n"), fname );
- /* we can't yet encode the length of very large files,
- * so we switch to partial length encoding in this case */
- if ( filesize >= IOBUF_FILELENGTH_LIMIT )
- filesize = 0;
-
- /* Because the text_filter modifies the length of the
- * data, it is not possible to know the used length
- * without a double read of the file - to avoid that
- * we simple use partial length packets.
- */
- if( opt.textmode && !outfile )
- filesize = 0;
- }
- else
- filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
-
- if (!opt.no_literal) {
- pt->timestamp = make_timestamp();
- pt->mode = opt.textmode && !outfile ? 't':'b';
- pt->len = filesize;
- pt->new_ctb = !pt->len && !opt.rfc1991;
- pt->buf = inp;
- pkt.pkttype = PKT_PLAINTEXT;
- pkt.pkt.plaintext = pt;
- /*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
- if( (rc = build_packet( out, &pkt )) )
- log_error("build_packet(PLAINTEXT) failed: %s\n",
- gpg_errstr(rc) );
- pt->buf = NULL;
- }
- else {
- byte copy_buffer[4096];
- int bytes_copied;
- while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
- if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
- rc = GPGERR_WRITE_FILE;
- log_error("copying input to output failed: %s\n",
- gpg_errstr(rc));
- break;
- }
- memset(copy_buffer, 0, 4096); /* burn buffer */
- }
+ rc = write_plaintext_packet (out, inp, fname,
+ opt.textmode && !outfile ? 't':'b');
}
/* catch errors from above */
if (rc)
goto leave;
- /* write all the signature packets */
- for( sk_rover = sk_list; sk_rover && !rc ; sk_rover = sk_rover->next ) {
- rc = write_one_signature( out, sk_rover->sk,
- old_style, outfile, mfx.md,
+ /* write the signatures */
+ rc = write_signature_packets (sk_list, out, mfx.md,
opt.textmode && !outfile? 0x01 : 0x00,
- detached ? 'D':'S' );
- }
+ timestamp, duration, detached ? 'D':'S');
+ if( rc )
+ goto leave;
leave:
if( rc )
iobuf_cancel(out);
- else
+ else {
iobuf_close(out);
+ if (encryptflag)
+ write_status( STATUS_END_ENCRYPTION );
+ }
iobuf_close(inp);
- gcry_md_close( mfx.md );
+ md_close( mfx.md );
release_sk_list( sk_list );
release_pk_list( pk_list );
- /* FIXME: Did we release the efx.cfx.dek ? */
+ recipient_digest_algo=0;
return rc;
}
@@ -660,7 +849,7 @@ int
clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
{
armor_filter_context_t afx;
- GCRY_MD_HD textmd = NULL;
+ MD_HANDLE textmd = NULL;
IOBUF inp = NULL, out = NULL;
PACKET pkt;
int rc = 0;
@@ -668,27 +857,40 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
SK_LIST sk_rover = NULL;
int old_style = opt.rfc1991;
int only_md5 = 0;
+ u32 timestamp=0,duration=0;
memset( &afx, 0, sizeof afx);
init_packet( &pkt );
- if( (rc=build_sk_list( locusr, &sk_list, 1, GCRY_PK_USAGE_SIGN )) )
+ if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+ duration=ask_expire_interval(1);
+
+ if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
goto leave;
- if( !old_style )
+
+ if( !old_style && !duration )
old_style = only_old_style( sk_list );
+ if(!old_style && opt.pgp2)
+ {
+ log_info(_("you can only clearsign with PGP 2.x style keys "
+ "while in --pgp2 mode\n"));
+ log_info(_("this message may not be usable by PGP 2.x\n"));
+ opt.pgp2=0;
+ }
+
/* prepare iobufs */
if( !(inp = iobuf_open(fname)) ) {
log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
- rc = GPGERR_OPEN_FILE;
+ rc = G10ERR_OPEN_FILE;
goto leave;
}
if( outfile ) {
if( !(out = iobuf_create( outfile )) ) {
log_error(_("can't create %s: %s\n"), outfile, strerror(errno) );
- rc = GPGERR_CREATE_FILE;
+ rc = G10ERR_CREATE_FILE;
goto leave;
}
else if( opt.verbose )
@@ -701,7 +903,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
PKT_secret_key *sk = sk_rover->sk;
- if( hash_for(sk->pubkey_algo, sk->version) == GCRY_MD_MD5 )
+ if( hash_for(sk->pubkey_algo, sk->version) == DIGEST_ALGO_MD5 )
only_md5 = 1;
else {
only_md5 = 0;
@@ -709,9 +911,8 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
}
}
- if( old_style && only_md5 )
- iobuf_writestr(out, "\n" );
- else {
+ if( !(old_style && only_md5) ) {
+ const char *s;
int any = 0;
byte hashs_seen[256];
@@ -722,33 +923,32 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
int i = hash_for(sk->pubkey_algo, sk->version);
if( !hashs_seen[ i & 0xff ] ) {
- if( !openpgp_md_test_algo( i ) ) {
+ s = digest_algo_to_string( i );
+ if( s ) {
hashs_seen[ i & 0xff ] = 1;
if( any )
iobuf_put(out, ',' );
- iobuf_writestr(out, gcry_md_algo_name( i ) );
+ iobuf_writestr(out, s );
any = 1;
}
}
}
assert(any);
- iobuf_writestr(out, "\n" );
- if( opt.not_dash_escaped )
- iobuf_writestr( out,
- "NotDashEscaped: You need GnuPG to verify this message\n" );
- iobuf_writestr(out, "\n" );
+ iobuf_writestr(out, LF );
}
+ if( opt.not_dash_escaped )
+ iobuf_writestr( out,
+ "NotDashEscaped: You need GnuPG to verify this message" LF );
+ iobuf_writestr(out, LF );
- textmd = gcry_md_open(0, 0);
- if( !textmd )
- BUG();
+ textmd = md_open(0, 0);
for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
PKT_secret_key *sk = sk_rover->sk;
- gcry_md_enable(textmd, hash_for(sk->pubkey_algo, sk->version));
+ md_enable(textmd, hash_for(sk->pubkey_algo, sk->version));
}
if ( DBG_HASHING )
- gcry_md_start_debug( textmd, "clearsign" );
+ md_start_debug( textmd, "clearsign" );
copy_clearsig_text( out, inp, textmd,
!opt.not_dash_escaped, opt.escape_from, old_style );
/* fixme: check for read errors */
@@ -757,13 +957,11 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
afx.what = 2;
iobuf_push_filter( out, armor_filter, &afx );
- /* write all the signature packets */
- for( sk_rover = sk_list; sk_rover && !rc ; sk_rover = sk_rover->next ) {
- rc = write_one_signature( out, sk_rover->sk,
- old_style, outfile, textmd,
- 0x01,
- 'C' );
- }
+ /* write the signatures */
+ rc = write_signature_packets (sk_list, out, textmd, 0x01,
+ timestamp, duration, 'C');
+ if( rc )
+ goto leave;
leave:
if( rc )
@@ -771,68 +969,249 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
else
iobuf_close(out);
iobuf_close(inp);
- gcry_md_close( textmd );
+ md_close( textmd );
release_sk_list( sk_list );
return rc;
}
+/*
+ * Sign and conventionally encrypt the given file.
+ * FIXME: Far too much code is duplicated - revamp the whole file.
+ */
+int
+sign_symencrypt_file (const char *fname, STRLIST locusr)
+{
+ armor_filter_context_t afx;
+ compress_filter_context_t zfx;
+ md_filter_context_t mfx;
+ text_filter_context_t tfx;
+ cipher_filter_context_t cfx;
+ IOBUF inp = NULL, out = NULL;
+ PACKET pkt;
+ STRING2KEY *s2k = NULL;
+ int rc = 0;
+ SK_LIST sk_list = NULL;
+ SK_LIST sk_rover = NULL;
+ int algo;
+ u32 timestamp=0,duration=0;
+
+ memset( &afx, 0, sizeof afx);
+ memset( &zfx, 0, sizeof zfx);
+ memset( &mfx, 0, sizeof mfx);
+ memset( &tfx, 0, sizeof tfx);
+ memset( &cfx, 0, sizeof cfx);
+ init_packet( &pkt );
+
+ if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+ duration=ask_expire_interval(1);
+
+ rc = build_sk_list (locusr, &sk_list, 1, PUBKEY_USAGE_SIG);
+ if (rc)
+ goto leave;
+
+ /* prepare iobufs */
+ inp = iobuf_open(fname);
+ if( !inp ) {
+ log_error("can't open %s: %s\n", fname? fname: "[stdin]",
+ strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+
+ /* prepare key */
+ s2k = m_alloc_clear( sizeof *s2k );
+ s2k->mode = opt.rfc1991? 0:opt.s2k_mode;
+ s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo
+ : opt.s2k_digest_algo;
+
+ algo = opt.def_cipher_algo ? opt.def_cipher_algo : opt.s2k_cipher_algo;
+ if (!opt.quiet || !opt.batch)
+ log_info (_("%s encryption will be used\n"),
+ cipher_algo_to_string(algo) );
+ cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL );
+
+ if (!cfx.dek || !cfx.dek->keylen) {
+ rc = G10ERR_PASSPHRASE;
+ log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
+ goto leave;
+ }
+
+ /* now create the outfile */
+ rc = open_outfile (fname, opt.armor? 1:0, &out);
+ if (rc)
+ goto leave;
+
+ /* prepare to calculate the MD over the input */
+ if (opt.textmode)
+ iobuf_push_filter (inp, text_filter, &tfx);
+ mfx.md = md_open(0, 0);
+
+ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) {
+ PKT_secret_key *sk = sk_rover->sk;
+ md_enable (mfx.md, hash_for (sk->pubkey_algo, sk->version ));
+ }
+
+ iobuf_push_filter (inp, md_filter, &mfx);
+
+ /* Push armor output filter */
+ if (opt.armor)
+ iobuf_push_filter (out, armor_filter, &afx);
+
+ /* Write the symmetric key packet */
+ /*(current filters: armor)*/
+ if (!opt.rfc1991) {
+ PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc );
+ enc->version = 4;
+ enc->cipher_algo = cfx.dek->algo;
+ enc->s2k = *s2k;
+ pkt.pkttype = PKT_SYMKEY_ENC;
+ pkt.pkt.symkey_enc = enc;
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
+ m_free(enc);
+ }
+
+ /* Push the encryption filter */
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* Push the Zip filter */
+ if (opt.compress)
+ {
+ int compr_algo=opt.def_compress_algo;
+
+ /* Default */
+ if(compr_algo==-1)
+ compr_algo=DEFAULT_COMPRESS_ALGO;
+
+ if (compr_algo)
+ {
+ zfx.algo = compr_algo;
+ iobuf_push_filter( out, compress_filter, &zfx );
+ }
+ }
+
+ /* Write the one-pass signature packets */
+ /*(current filters: zip - encrypt - armor)*/
+ if (!opt.rfc1991) {
+ rc = write_onepass_sig_packets (sk_list, out,
+ opt.textmode? 0x01:0x00);
+ if (rc)
+ goto leave;
+ }
+
+ /* Pipe data through all filters; i.e. write the signed stuff */
+ /*(current filters: zip - encrypt - armor)*/
+ rc = write_plaintext_packet (out, inp, fname, opt.textmode ? 't':'b');
+ if (rc)
+ goto leave;
+
+ /* Write the signatures */
+ /*(current filters: zip - encrypt - armor)*/
+ rc = write_signature_packets (sk_list, out, mfx.md,
+ opt.textmode? 0x01 : 0x00,
+ timestamp, duration, 'S');
+ if( rc )
+ goto leave;
+
+
+ leave:
+ if( rc )
+ iobuf_cancel(out);
+ else {
+ iobuf_close(out);
+ write_status( STATUS_END_ENCRYPTION );
+ }
+ iobuf_close(inp);
+ release_sk_list( sk_list );
+ md_close( mfx.md );
+ m_free(cfx.dek);
+ m_free(s2k);
+ return rc;
+}
+
/****************
- * Create a signature packet for the given public key certificate
- * and the user id and return it in ret_sig. User signature class SIGCLASS
- * user-id is not used (and may be NULL if sigclass is 0x20)
- * If digest_algo is 0 the function selects an appropriate one.
- */
+ * Create a signature packet for the given public key certificate and
+ * the user id and return it in ret_sig. User signature class SIGCLASS
+ * user-id is not used (and may be NULL if sigclass is 0x20) If
+ * DIGEST_ALGO is 0 the function selects an appropriate one.
+ * SIGVERSION gives the minimal required signature packet version;
+ * this is needed so that special properties like local sign are not
+ * applied (actually: dropped) when a v3 key is used. TIMESTAMP is
+ * the timestamp to use for the signature. 0 means "now" */
int
make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_secret_key *sk,
int sigclass, int digest_algo,
+ int sigversion, u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *), void *opaque
)
{
PKT_signature *sig;
int rc=0;
- GCRY_MD_HD md;
+ MD_HANDLE md;
- assert( (sigclass >= 0x10 && sigclass <= 0x13)
+ assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
|| sigclass == 0x20 || sigclass == 0x18
|| sigclass == 0x30 || sigclass == 0x28 );
- if( !digest_algo ) {
- switch( sk->pubkey_algo ) {
- case GCRY_PK_DSA: digest_algo = GCRY_MD_SHA1; break;
- case GCRY_PK_RSA_S:
- case GCRY_PK_RSA: digest_algo = GCRY_MD_MD5; break;
- default: digest_algo = GCRY_MD_RMD160; break;
- }
- }
- if( !(md = gcry_md_open( digest_algo, 0 )))
- BUG();
+
+ if (opt.force_v4_certs)
+ sigversion = 4;
+
+ if (sigversion < sk->version)
+ sigversion = sk->version;
+
+ /* If you are making a signature on a v4 key using your v3 key, it
+ doesn't make sense to generate a v3 sig. After all, no v3-only
+ PGP implementation could understand the v4 key in the first
+ place. */
+ if (sigversion < pk->version)
+ sigversion = pk->version;
+
+ if( !digest_algo )
+ {
+ /* Basically, this means use SHA1 always unless it's a v3 RSA
+ key making a v3 cert (use MD5), or the user specified
+ something (use whatever they said). They still must use a
+ 160-bit hash with DSA, or the signature will fail. Note
+ that this still allows the caller of make_keysig_packet to
+ override the user setting if it must. */
+
+ if(opt.cert_digest_algo)
+ digest_algo=opt.cert_digest_algo;
+ else if((sk->pubkey_algo==PUBKEY_ALGO_RSA ||
+ sk->pubkey_algo==PUBKEY_ALGO_RSA_S) &&
+ pk->version<4 && sigversion < 4)
+ digest_algo = DIGEST_ALGO_MD5;
+ else
+ digest_algo = DIGEST_ALGO_SHA1;
+ }
+
+ md = md_open( digest_algo, 0 );
/* hash the public key certificate and the user id */
hash_public_key( md, pk );
if( sigclass == 0x18 || sigclass == 0x28 ) { /* subkey binding/revocation*/
hash_public_key( md, subpk );
}
- else if( sigclass != 0x20 ) {
- if( sk->version >=4 ) {
- byte buf[5];
- buf[0] = 0xb4; /* indicates a userid packet */
- buf[1] = uid->len >> 24; /* always use 4 length bytes */
- buf[2] = uid->len >> 16;
- buf[3] = uid->len >> 8;
- buf[4] = uid->len;
- gcry_md_write( md, buf, 5 );
- }
- gcry_md_write( md, uid->name, uid->len );
+ else if( sigclass != 0x1F && sigclass != 0x20 ) {
+ hash_uid (md, sigversion, uid);
}
/* and make the signature packet */
- sig = gcry_xcalloc( 1, sizeof *sig );
- sig->version = sk->version;
+ sig = m_alloc_clear( sizeof *sig );
+ sig->version = sigversion;
+ sig->flags.exportable=1;
+ sig->flags.revocable=1;
keyid_from_sk( sk, sig->keyid );
sig->pubkey_algo = sk->pubkey_algo;
sig->digest_algo = digest_algo;
- sig->timestamp = make_timestamp();
+ if(timestamp)
+ sig->timestamp=timestamp;
+ else
+ sig->timestamp=make_timestamp();
+ if(duration)
+ sig->expiredate=sig->timestamp+duration;
sig->sig_class = sigclass;
if( sig->version >= 4 )
build_sig_subpkt_from_sig( sig );
@@ -841,49 +1220,14 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
rc = (*mksubpkt)( sig, opaque );
if( !rc ) {
- mk_notation_and_policy( sig );
- if( sig->version >= 4 )
- gcry_md_putc( md, sig->version );
- gcry_md_putc( md, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- gcry_md_putc( md, (a >> 24) & 0xff );
- gcry_md_putc( md, (a >> 16) & 0xff );
- gcry_md_putc( md, (a >> 8) & 0xff );
- gcry_md_putc( md, a & 0xff );
- }
- else {
- byte buf[6];
- size_t n;
-
- gcry_md_putc( md, sig->pubkey_algo );
- gcry_md_putc( md, sig->digest_algo );
- if( sig->hashed_data ) {
- n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
- gcry_md_write( md, sig->hashed_data, n+2 );
- n += 6;
- }
- else {
- gcry_md_putc( md, 0 ); /* always hash the length of the subpacket*/
- gcry_md_putc( md, 0 );
- n = 6;
- }
- /* add some magic */
- buf[0] = sig->version;
- buf[1] = 0xff;
- buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
- buf[3] = n >> 16;
- buf[4] = n >> 8;
- buf[5] = n;
- gcry_md_write( md, buf, 6 );
-
- }
- gcry_md_final(md);
+ mk_notation_and_policy( sig, pk, sk );
+ hash_sigversion_to_magic (md, sig);
+ md_final(md);
rc = complete_sig( sig, sk, md );
}
- gcry_md_close( md );
+ md_close( md );
if( rc )
free_seckey_enc( sig );
else
@@ -892,3 +1236,63 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
}
+
+/****************
+ * Create a new signature packet based on an existing one.
+ * Only user ID signatures are supported for now.
+ * TODO: Merge this with make_keysig_packet.
+ */
+int
+update_keysig_packet( PKT_signature **ret_sig,
+ PKT_signature *orig_sig,
+ PKT_public_key *pk,
+ PKT_user_id *uid,
+ PKT_secret_key *sk,
+ int (*mksubpkt)(PKT_signature *, void *),
+ void *opaque
+ )
+{
+ PKT_signature *sig;
+ int rc=0;
+ MD_HANDLE md;
+
+ if (!orig_sig || !pk || !uid || !sk)
+ return G10ERR_GENERAL;
+ if (orig_sig->sig_class < 0x10 || orig_sig->sig_class > 0x13 )
+ return G10ERR_GENERAL;
+
+ md = md_open( orig_sig->digest_algo, 0 );
+
+ /* hash the public key certificate and the user id */
+ hash_public_key( md, pk );
+ hash_uid (md, orig_sig->version, uid);
+
+ /* create a new signature packet */
+ sig = copy_signature (NULL, orig_sig);
+ if ( sig->version >= 4 && mksubpkt)
+ rc = (*mksubpkt)(sig, opaque);
+
+ /* we increase the timestamp by one second so that a future import
+ of this key will replace the existing one. We also make sure that
+ we don't create a timestamp in the future */
+ sig->timestamp++;
+ while (sig->timestamp >= make_timestamp())
+ sleep (1);
+ /* put the updated timestamp back into the data */
+ if( sig->version >= 4 )
+ build_sig_subpkt_from_sig( sig );
+
+ if (!rc) {
+ hash_sigversion_to_magic (md, sig);
+ md_final(md);
+
+ rc = complete_sig( sig, sk, md );
+ }
+
+ md_close (md);
+ if( rc )
+ free_seckey_enc (sig);
+ else
+ *ret_sig = sig;
+ return rc;
+}
diff --git a/g10/signal.c b/g10/signal.c
index f61b0a8f8..0517ba648 100644
--- a/g10/signal.c
+++ b/g10/signal.c
@@ -1,5 +1,5 @@
/* signal.c - signal handling
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -27,9 +27,9 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "options.h"
#include "errors.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "ttyio.h"
@@ -38,6 +38,36 @@
static volatile int caught_fatal_sig = 0;
static volatile int caught_sigusr1 = 0;
+static void
+init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
+{
+ #ifndef HAVE_DOSISH_SYSTEM
+ #ifdef HAVE_SIGACTION
+ struct sigaction oact, nact;
+
+ if (check_ign) {
+ /* we don't want to change an IGN handler */
+ sigaction (sig, NULL, &oact );
+ if (oact.sa_handler == SIG_IGN )
+ return;
+ }
+
+ nact.sa_handler = handler;
+ sigemptyset (&nact.sa_mask);
+ nact.sa_flags = 0;
+ sigaction ( sig, &nact, NULL);
+ #else
+ RETSIGTYPE (*ohandler)(int);
+
+ ohandler = signal (sig, handler);
+ if (check_ign && ohandler == SIG_IGN) {
+ /* Change it back if it was already set to IGN */
+ signal (sig, SIG_IGN);
+ }
+ #endif
+ #endif /*!HAVE_DOSISH_SYSTEM*/
+}
+
static const char *
get_signal_name( int signum )
{
@@ -58,23 +88,20 @@ got_fatal_signal( int sig )
raise( sig );
caught_fatal_sig = 1;
- gcry_control( GCRYCTL_TERM_SECMEM );
+ secmem_term();
/* better don't transtale these messages */
write(2, "\n", 1 );
s = log_get_name(); if( s ) write(2, s, strlen(s) );
write(2, ": ", 2 );
s = get_signal_name(sig); write(2, s, strlen(s) );
- write(2, " caught ... exiting\n", 21 );
-
- #ifndef HAVE_DOSISH_SYSTEM
- { /* reset action to default action and raise signal again */
- struct sigaction nact;
- nact.sa_handler = SIG_DFL;
- sigemptyset( &nact.sa_mask );
- nact.sa_flags = 0;
- sigaction( sig, &nact, NULL);
- }
- #endif
+ write(2, " caught ... exiting\n", 20 );
+
+ /* reset action to default action and raise signal again */
+ init_one_signal (sig, SIG_DFL, 0);
+ remove_lockfiles ();
+#ifdef __riscos__
+ close_fds ();
+#endif /* __riscos__ */
raise( sig );
}
@@ -85,37 +112,18 @@ got_usr_signal( int sig )
caught_sigusr1 = 1;
}
-#ifndef HAVE_DOSISH_SYSTEM
-static void
-do_sigaction( int sig, struct sigaction *nact )
-{
- struct sigaction oact;
-
- sigaction( sig, NULL, &oact );
- if( oact.sa_handler != SIG_IGN )
- sigaction( sig, nact, NULL);
-}
-#endif
void
init_signals()
{
#ifndef HAVE_DOSISH_SYSTEM
- struct sigaction nact;
-
- nact.sa_handler = got_fatal_signal;
- sigemptyset( &nact.sa_mask );
- nact.sa_flags = 0;
-
- do_sigaction( SIGINT, &nact );
- do_sigaction( SIGHUP, &nact );
- do_sigaction( SIGTERM, &nact );
- do_sigaction( SIGQUIT, &nact );
- do_sigaction( SIGSEGV, &nact );
- nact.sa_handler = got_usr_signal;
- sigaction( SIGUSR1, &nact, NULL );
- nact.sa_handler = SIG_IGN;
- sigaction( SIGPIPE, &nact, NULL );
+ init_one_signal (SIGINT, got_fatal_signal, 1 );
+ init_one_signal (SIGHUP, got_fatal_signal, 1 );
+ init_one_signal (SIGTERM, got_fatal_signal, 1 );
+ init_one_signal (SIGQUIT, got_fatal_signal, 1 );
+ init_one_signal (SIGSEGV, got_fatal_signal, 1 );
+ init_one_signal (SIGUSR1, got_usr_signal, 0 );
+ init_one_signal (SIGPIPE, SIG_IGN, 0 );
#endif
}
@@ -124,6 +132,7 @@ void
pause_on_sigusr( int which )
{
#ifndef HAVE_DOSISH_SYSTEM
+ #ifdef HAVE_SIGPROCMASK
sigset_t mask, oldmask;
assert( which == 1 );
@@ -135,6 +144,14 @@ pause_on_sigusr( int which )
sigsuspend( &oldmask );
caught_sigusr1 = 0;
sigprocmask( SIG_UNBLOCK, &mask, NULL );
+ #else
+ assert (which == 1);
+ sighold (SIGUSR1);
+ while (!caught_sigusr1)
+ sigpause(SIGUSR1);
+ caught_sigusr1 = 0;
+ sigrelse(SIGUSR1); ????
+ #endif /*!HAVE_SIGPROCMASK*/
#endif
}
@@ -142,12 +159,13 @@ pause_on_sigusr( int which )
static void
do_block( int block )
{
- #ifndef HAVE_DOSISH_SYSTEM
+ #ifndef HAVE_DOSISH_SYSTEM
static int is_blocked;
+ #ifdef HAVE_SIGPROCMASK
static sigset_t oldmask;
if( block ) {
- sigset_t newmask;
+ sigset_t newmask;
if( is_blocked )
log_bug("signals are already blocked\n");
@@ -161,7 +179,28 @@ do_block( int block )
sigprocmask( SIG_SETMASK, &oldmask, NULL );
is_blocked = 0;
}
- #endif /*HAVE_DOSISH_SYSTEM*/
+ #else /*!HAVE_SIGPROCMASK*/
+ static void (*disposition[MAXSIG])();
+ int sig;
+
+ if( block ) {
+ if( is_blocked )
+ log_bug("signals are already blocked\n");
+ for (sig=1; sig < MAXSIG; sig++) {
+ disposition[sig] = sigset (sig, SIG_HOLD);
+ }
+ is_blocked = 1;
+ }
+ else {
+ if( !is_blocked )
+ log_bug("signals are not blocked\n");
+ for (sig=1; sig < MAXSIG; sig++) {
+ sigset (sig, disposition[sig]);
+ }
+ is_blocked = 0;
+ }
+ #endif /*!HAVE_SIGPROCMASK*/
+ #endif /*HAVE_DOSISH_SYSTEM*/
}
@@ -176,4 +215,3 @@ unblock_all_signals()
{
do_block(0);
}
-
diff --git a/g10/skclist.c b/g10/skclist.c
index bc325cd58..1f7a3919a 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -1,5 +1,5 @@
/* skclist.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,14 +25,14 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
#include "i18n.h"
-#include "main.h"
+#include "cipher.h"
void
@@ -43,14 +43,66 @@ release_sk_list( SK_LIST sk_list )
for( ; sk_list; sk_list = sk_rover ) {
sk_rover = sk_list->next;
free_secret_key( sk_list->sk );
- gcry_free( sk_list );
+ m_free( sk_list );
}
}
+/* Check that we are only using keys which don't have
+ * the string "(insecure!)" or "not secure" or "do not use"
+ * in one of the user ids
+ */
+static int
+is_insecure( PKT_secret_key *sk )
+{
+ u32 keyid[2];
+ KBNODE node = NULL, u;
+ int insecure = 0;
+
+ keyid_from_sk( sk, keyid );
+ node = get_pubkeyblock( keyid );
+ for ( u = node; u; u = u->next ) {
+ if ( u->pkt->pkttype == PKT_USER_ID ) {
+ PKT_user_id *id = u->pkt->pkt.user_id;
+ if ( id->attrib_data )
+ continue; /* skip attribute packets */
+ if ( strstr( id->name, "(insecure!)" )
+ || strstr( id->name, "not secure" )
+ || strstr( id->name, "do not use" ) ) {
+ insecure = 1;
+ break;
+ }
+ }
+ }
+ release_kbnode( node );
+
+ return insecure;
+}
+
+static int
+key_present_in_sk_list(SK_LIST sk_list, PKT_secret_key *sk)
+{
+ for (; sk_list; sk_list = sk_list->next) {
+ if ( !cmp_secret_keys(sk_list->sk, sk) )
+ return 0;
+ }
+ return -1;
+}
+
+static int
+is_duplicated_entry (STRLIST list, STRLIST item)
+{
+ for(; list && list != item; list = list->next) {
+ if ( !strcmp (list->d, item->d) )
+ return 1;
+ }
+ return 0;
+}
+
+
int
-build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
- unsigned int use )
+build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
+ int unlock, unsigned int use )
{
SK_LIST sk_list = NULL;
int rc;
@@ -58,24 +110,28 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
if( !locusr ) { /* use the default one */
PKT_secret_key *sk;
- sk = gcry_xcalloc( 1, sizeof *sk );
+ sk = m_alloc_clear( sizeof *sk );
sk->req_usage = use;
- if( (rc = get_seckey_byname( NULL, sk, NULL, unlock, NULL )) ) {
+ if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
free_secret_key( sk ); sk = NULL;
- log_error("no default secret key: %s\n", gpg_errstr(rc) );
+ log_error("no default secret key: %s\n", g10_errstr(rc) );
}
- else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo,
- sk->pubkey_usage)) ) {
+ else if( !(rc=check_pubkey_algo2(sk->pubkey_algo, use)) ) {
SK_LIST r;
-
- if( sk->version == 4 && (sk->pubkey_usage & GCRY_PK_USAGE_SIGN )
- && sk->pubkey_algo == GCRY_PK_ELG_E ) {
+
+ if( sk->version == 4 && (use & PUBKEY_USAGE_SIG)
+ && sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
log_info("this is a PGP generated "
"ElGamal key which is NOT secure for signatures!\n");
free_secret_key( sk ); sk = NULL;
}
+ else if( random_is_faked() && !is_insecure( sk ) ) {
+ log_info(_("key is not flagged as insecure - "
+ "can't use it with the faked RNG!\n"));
+ free_secret_key( sk ); sk = NULL;
+ }
else {
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->sk = sk; sk = NULL;
r->next = sk_list;
r->mark = 0;
@@ -84,31 +140,54 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
}
else {
free_secret_key( sk ); sk = NULL;
- log_error("invalid default secret key: %s\n", gpg_errstr(rc) );
+ log_error("invalid default secret key: %s\n", g10_errstr(rc) );
}
}
else {
+ STRLIST locusr_orig = locusr;
for(; locusr; locusr = locusr->next ) {
PKT_secret_key *sk;
-
- sk = gcry_xcalloc( 1, sizeof *sk );
+
+ rc = 0;
+ /* Do an early check agains duplicated entries. However this
+ * won't catch all duplicates because the user IDs may be
+ * specified in different ways.
+ */
+ if ( is_duplicated_entry ( locusr_orig, locusr ) ) {
+ log_error(_("skipped `%s': duplicated\n"), locusr->d );
+ continue;
+ }
+ sk = m_alloc_clear( sizeof *sk );
sk->req_usage = use;
- if( (rc = get_seckey_byname( NULL, sk, locusr->d, unlock, NULL))) {
+ if( (rc = get_seckey_byname( sk, locusr->d, 0 )) ) {
free_secret_key( sk ); sk = NULL;
- log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) );
+ log_error(_("skipped `%s': %s\n"), locusr->d, g10_errstr(rc) );
}
- else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo,
- sk->pubkey_usage)) ) {
+ else if ( key_present_in_sk_list(sk_list, sk) == 0) {
+ free_secret_key(sk); sk = NULL;
+ log_info(_("skipped: secret key already present\n"));
+ }
+ else if ( unlock && (rc = check_secret_key( sk, 0 )) ) {
+ free_secret_key( sk ); sk = NULL;
+ log_error(_("skipped `%s': %s\n"), locusr->d, g10_errstr(rc) );
+ }
+ else if( !(rc=check_pubkey_algo2(sk->pubkey_algo, use)) ) {
SK_LIST r;
- if( sk->version == 4 && (sk->pubkey_usage & GCRY_PK_USAGE_SIGN)
- && sk->pubkey_algo == GCRY_PK_ELG_E ) {
+
+ if( sk->version == 4 && (use & PUBKEY_USAGE_SIG)
+ && sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
log_info(_("skipped `%s': this is a PGP generated "
"ElGamal key which is not secure for signatures!\n"),
locusr->d );
free_secret_key( sk ); sk = NULL;
}
+ else if( random_is_faked() && !is_insecure( sk ) ) {
+ log_info(_("key is not flagged as insecure - "
+ "can't use it with the faked RNG!\n"));
+ free_secret_key( sk ); sk = NULL;
+ }
else {
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->sk = sk; sk = NULL;
r->next = sk_list;
r->mark = 0;
@@ -117,7 +196,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
}
else {
free_secret_key( sk ); sk = NULL;
- log_error("skipped `%s': %s\n", locusr->d, gpg_errstr(rc) );
+ log_error("skipped `%s': %s\n", locusr->d, g10_errstr(rc) );
}
}
}
@@ -125,7 +204,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
if( !rc && !sk_list ) {
log_error("no valid signators\n");
- rc = GPGERR_NO_USER_ID;
+ rc = G10ERR_NO_USER_ID;
}
if( rc )
diff --git a/g10/status.c b/g10/status.c
index d336ae3b0..e0b126b78 100644
--- a/g10/status.c
+++ b/g10/status.c
@@ -1,5 +1,5 @@
/* status.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,11 +24,13 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <signal.h>
#ifdef USE_SHM_COPROCESSING
#ifdef USE_CAPABILITIES
#include <sys/capability.h>
#endif
#ifdef HAVE_SYS_IPC_H
+ #include <sys/types.h>
#include <sys/ipc.h>
#endif
#ifdef HAVE_SYS_SHM_H
@@ -38,16 +40,20 @@
#include <sys/mman.h>
#endif
#endif
-
-#include <gcrypt.h>
#include "util.h"
#include "status.h"
#include "ttyio.h"
#include "options.h"
#include "main.h"
#include "i18n.h"
+#include "cipher.h" /* for progress functions */
+
+#define CONTROL_D ('D' - 'A' + 1)
+
+
+
+static FILE *statusfp;
-static int fd = -1;
#ifdef USE_SHM_COPROCESSING
static int shm_id = -1;
static volatile char *shm_area;
@@ -68,26 +74,118 @@ progress_cb ( void *ctx, int c )
write_status_text ( STATUS_PROGRESS, buf );
}
+static const char *
+get_status_string ( int no )
+{
+ const char *s;
+
+ switch( no ) {
+ case STATUS_ENTER : s = "ENTER"; break;
+ case STATUS_LEAVE : s = "LEAVE"; break;
+ case STATUS_ABORT : s = "ABORT"; break;
+ case STATUS_GOODSIG: s = "GOODSIG"; break;
+ case STATUS_KEYEXPIRED: s = "KEYEXPIRED"; break;
+ case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
+ case STATUS_BADSIG : s = "BADSIG"; break;
+ case STATUS_ERRSIG : s = "ERRSIG"; break;
+ case STATUS_BADARMOR : s = "BADARMOR"; break;
+ case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
+ case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
+ case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
+ case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
+ case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
+ case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
+ case STATUS_GET_BOOL : s = "GET_BOOL"; break;
+ case STATUS_GET_LINE : s = "GET_LINE"; break;
+ case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
+ case STATUS_GOT_IT : s = "GOT_IT"; break;
+ case STATUS_SHM_INFO : s = "SHM_INFO"; break;
+ case STATUS_SHM_GET : s = "SHM_GET"; break;
+ case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
+ case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
+ case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
+ case STATUS_VALIDSIG : s = "VALIDSIG"; break;
+ case STATUS_SIG_ID : s = "SIG_ID"; break;
+ case STATUS_ENC_TO : s = "ENC_TO"; break;
+ case STATUS_NODATA : s = "NODATA"; break;
+ case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
+ case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
+ case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
+ case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
+ case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
+ case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
+ case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
+ case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
+ case STATUS_GOODMDC : s = "GOODMDC"; break;
+ case STATUS_BADMDC : s = "BADMDC"; break;
+ case STATUS_ERRMDC : s = "ERRMDC"; break;
+ case STATUS_IMPORTED : s = "IMPORTED"; break;
+ case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
+ case STATUS_FILE_START : s = "FILE_START"; break;
+ case STATUS_FILE_DONE : s = "FILE_DONE"; break;
+ case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
+ case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
+ case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
+ case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
+ case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
+ case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
+ case STATUS_PROGRESS : s = "PROGRESS"; break;
+ case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
+ case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
+ case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
+ case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
+ case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
+ case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
+ case STATUS_END_STREAM : s = "END_STREAM"; break;
+ case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
+ case STATUS_USERID_HINT : s = "USERID_HINT"; break;
+ case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
+ case STATUS_INV_RECP : s = "INV_RECP"; break;
+ case STATUS_NO_RECP : s = "NO_RECP"; break;
+ case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
+ case STATUS_SIGEXPIRED : s = "SIGEXPIRED deprecated-use-keyexpired-instead"; break;
+ case STATUS_EXPSIG : s = "EXPSIG"; break;
+ case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
+ case STATUS_ATTRIBUTE : s = "ATTRIBUTE"; break;
+ default: s = "?"; break;
+ }
+ return s;
+}
void
-set_status_fd ( int newfd )
+set_status_fd ( int fd )
{
- fd = newfd;
- if ( fd != -1 ) {
- #warning fixme - progress functions
- /* Has to be fixed in libgcrypt */
- #if 0
- register_primegen_progress ( progress_cb, "primegen" );
- register_pk_dsa_progress ( progress_cb, "pk_dsa" );
- register_pk_elg_progress ( progress_cb, "pk_elg" );
- #endif
+ static int last_fd = -1;
+
+ if ( fd != -1 && last_fd == fd )
+ return;
+
+ if ( statusfp && statusfp != stdout && statusfp != stderr )
+ fclose (statusfp);
+ statusfp = NULL;
+ if ( fd == -1 )
+ return;
+
+ if( fd == 1 )
+ statusfp = stdout;
+ else if( fd == 2 )
+ statusfp = stderr;
+ else
+ statusfp = fdopen( fd, "w" );
+ if( !statusfp ) {
+ log_fatal("can't open fd %d for status output: %s\n",
+ fd, strerror(errno));
}
+ last_fd = fd;
+ register_primegen_progress ( progress_cb, "primegen" );
+ register_pk_dsa_progress ( progress_cb, "pk_dsa" );
+ register_pk_elg_progress ( progress_cb, "pk_elg" );
}
int
is_status_enabled()
{
- return fd != -1;
+ return !!statusfp;
}
void
@@ -99,77 +197,97 @@ write_status ( int no )
void
write_status_text ( int no, const char *text)
{
- const char *s;
-
- if( fd == -1 )
+ if( !statusfp )
return; /* not enabled */
- switch( no ) {
- case STATUS_ENTER : s = "ENTER\n"; break;
- case STATUS_LEAVE : s = "LEAVE\n"; break;
- case STATUS_ABORT : s = "ABORT\n"; break;
- case STATUS_GOODSIG: s = "GOODSIG\n"; break;
- case STATUS_SIGEXPIRED: s = "SIGEXPIRED\n"; break;
- case STATUS_KEYREVOKED: s = "KEYREVOKED\n"; break;
- case STATUS_BADSIG : s = "BADSIG\n"; break;
- case STATUS_ERRSIG : s = "ERRSIG\n"; break;
- case STATUS_BADARMOR : s = "BADARMOR\n"; break;
- case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA\n"; break;
- case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED\n"; break;
- case STATUS_TRUST_NEVER : s = "TRUST_NEVER\n"; break;
- case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL\n"; break;
- case STATUS_TRUST_FULLY : s = "TRUST_FULLY\n"; break;
- case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE\n"; break;
- case STATUS_GET_BOOL : s = "GET_BOOL\n"; break;
- case STATUS_GET_LINE : s = "GET_LINE\n"; break;
- case STATUS_GET_HIDDEN : s = "GET_HIDDEN\n"; break;
- case STATUS_GOT_IT : s = "GOT_IT\n"; break;
- case STATUS_SHM_INFO : s = "SHM_INFO\n"; break;
- case STATUS_SHM_GET : s = "SHM_GET\n"; break;
- case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL\n"; break;
- case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN\n"; break;
- case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE\n"; break;
- case STATUS_VALIDSIG : s = "VALIDSIG\n"; break;
- case STATUS_SIG_ID : s = "SIG_ID\n"; break;
- case STATUS_ENC_TO : s = "ENC_TO\n"; break;
- case STATUS_NODATA : s = "NODATA\n"; break;
- case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE\n"; break;
- case STATUS_NO_PUBKEY : s = "NO_PUBKEY\n"; break;
- case STATUS_NO_SECKEY : s = "NO_SECKEY\n"; break;
- case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM\n"; break;
- case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED\n"; break;
- case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY\n"; break;
- case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE\n"; break;
- case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE\n"; break;
- case STATUS_GOODMDC : s = "GOODMDC\n"; break;
- case STATUS_BADMDC : s = "BADMDC\n"; break;
- case STATUS_ERRMDC : s = "ERRMDC\n"; break;
- case STATUS_IMPORTED : s = "IMPORTED\n"; break;
- case STATUS_IMPORT_RES : s = "IMPORT_RES\n"; break;
- case STATUS_FILE_START : s = "FILE_START\n"; break;
- case STATUS_FILE_DONE : s = "FILE_DONE\n"; break;
- case STATUS_FILE_ERROR : s = "FILE_ERROR\n"; break;
- case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION\n"; break;
- case STATUS_END_DECRYPTION : s = "END_DECRYPTION\n"; break;
- case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION\n"; break;
- case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION\n"; break;
- case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM\n"; break;
- case STATUS_PROGRESS : s = "PROGRESS\n"; break;
- case STATUS_SIG_CREATED : s = "SIG_CREATED\n"; break;
- default: s = "?\n"; break;
+ fputs ( "[GNUPG:] ", statusfp );
+ fputs ( get_status_string (no), statusfp );
+ if( text ) {
+ putc ( ' ', statusfp );
+ for (; *text; text++) {
+ if (*text == '\n')
+ fputs ( "\\n", statusfp );
+ else if (*text == '\r')
+ fputs ( "\\r", statusfp );
+ else
+ putc ( *(const byte *)text, statusfp );
+ }
}
+ putc ('\n',statusfp);
+ fflush (statusfp);
+}
- write( fd, "[GNUPG:] ", 9 );
- if( text ) {
- write( fd, s, strlen(s)-1 );
- write( fd, " ", 1 );
- write( fd, text, strlen(text) );
- write( fd, "\n", 1 );
+
+/*
+ * Write a status line with a buffer using %XX escapes. If WRAP is >
+ * 0 wrap the line after this length. If STRING is not NULL it will
+ * be prepended to the buffer, no escaping is done for string.
+ * A wrap of -1 forces spaces not to be encoded as %20.
+ */
+void
+write_status_text_and_buffer ( int no, const char *string,
+ const char *buffer, size_t len, int wrap )
+{
+ const char *s, *text;
+ int esc, first;
+ int lower_limit = ' ';
+ size_t n, count, dowrap;
+
+ if( !statusfp )
+ return; /* not enabled */
+
+ if (wrap == -1) {
+ lower_limit--;
+ wrap = 0;
}
- else
- write( fd, s, strlen(s) );
+
+ text = get_status_string (no);
+ count = dowrap = first = 1;
+ do {
+ if (dowrap) {
+ fprintf (statusfp, "[GNUPG:] %s ", text );
+ count = dowrap = 0;
+ if (first && string) {
+ fputs (string, statusfp);
+ count += strlen (string);
+ }
+ first = 0;
+ }
+ for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
+ if ( *s == '%' || *(const byte*)s <= lower_limit
+ || *(const byte*)s == 127 )
+ esc = 1;
+ if ( wrap && ++count > wrap ) {
+ dowrap=1;
+ break;
+ }
+ }
+ if (esc) {
+ s--; n++;
+ }
+ if (s != buffer)
+ fwrite (buffer, s-buffer, 1, statusfp );
+ if ( esc ) {
+ fprintf (statusfp, "%%%02X", *(const byte*)s );
+ s++; n--;
+ }
+ buffer = s;
+ len = n;
+ if ( dowrap && len )
+ putc ( '\n', statusfp );
+ } while ( len );
+
+ putc ('\n',statusfp);
+ fflush (statusfp);
}
+void
+write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
+{
+ write_status_text_and_buffer (no, NULL, buffer, len, wrap);
+}
+
+
#ifdef USE_SHM_COPROCESSING
@@ -333,7 +451,7 @@ do_shm_get( const char *keyword, int hidden, int bool )
if( bool )
return p[0]? "" : NULL;
- string = hidden? gcry_xmalloc_secure( n+1 ) : gcry_xmalloc( n+1 );
+ string = hidden? m_alloc_secure( n+1 ) : m_alloc( n+1 );
memcpy(string, p, n );
string[n] = 0; /* make sure it is a string */
if( hidden ) /* invalidate the memory */
@@ -344,6 +462,32 @@ do_shm_get( const char *keyword, int hidden, int bool )
#endif /* USE_SHM_COPROCESSING */
+static int
+myread(int fd, void *buf, size_t count)
+{
+ int rc;
+ do {
+ rc = read( fd, buf, count );
+ } while ( rc == -1 && errno == EINTR );
+ if ( !rc && count ) {
+ static int eof_emmited=0;
+ if ( eof_emmited < 3 ) {
+ *(char*)buf = CONTROL_D;
+ rc = 1;
+ eof_emmited++;
+ }
+ else { /* Ctrl-D not caught - do something reasonable */
+ #ifdef HAVE_DOSISH_SYSTEM
+ raise (SIGINT); /* nothing to hangup under DOS */
+ #else
+ raise (SIGHUP); /* no more input data */
+ #endif
+ }
+ }
+ return rc;
+}
+
+
/****************
* Request a string from the client over the command-fd
@@ -362,15 +506,21 @@ do_get_from_fd( const char *keyword, int hidden, int bool )
if( i >= len-1 ) {
char *save = string;
len += 100;
- string = hidden? gcry_xmalloc_secure ( len ) : gcry_malloc ( len );
+ string = hidden? m_alloc_secure ( len ) : m_alloc ( len );
if( save )
memcpy(string, save, i );
else
i=0;
}
/* Hmmm: why not use our read_line function here */
- if( read( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
- break;
+ if( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
+ break;
+ else if ( string[i] == CONTROL_D ) {
+ /* found ETX - cancel the line and return a sole ETX */
+ string[0] = CONTROL_D;
+ i=1;
+ break;
+ }
}
string[i] = 0;
@@ -397,6 +547,23 @@ cpr_enabled()
}
char *
+cpr_get_no_help( const char *keyword, const char *prompt )
+{
+ char *p;
+
+ if( opt.command_fd != -1 )
+ return do_get_from_fd ( keyword, 0, 0 );
+ #ifdef USE_SHM_COPROCESSING
+ if( opt.shm_coprocess )
+ return do_shm_get( keyword, 0, 0 );
+ #endif
+ for(;;) {
+ p = tty_get( prompt );
+ return p;
+ }
+}
+
+char *
cpr_get( const char *keyword, const char *prompt )
{
char *p;
@@ -410,7 +577,7 @@ cpr_get( const char *keyword, const char *prompt )
for(;;) {
p = tty_get( prompt );
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
- gcry_free(p);
+ m_free(p);
display_online_help( keyword );
}
else
@@ -418,6 +585,7 @@ cpr_get( const char *keyword, const char *prompt )
}
}
+
char *
cpr_get_utf8( const char *keyword, const char *prompt )
{
@@ -425,7 +593,7 @@ cpr_get_utf8( const char *keyword, const char *prompt )
p = cpr_get( keyword, prompt );
if( p ) {
char *utf8 = native_to_utf8( p );
- gcry_free( p );
+ m_free( p );
p = utf8;
}
return p;
@@ -445,7 +613,7 @@ cpr_get_hidden( const char *keyword, const char *prompt )
for(;;) {
p = tty_get_hidden( prompt );
if( *p == '?' && !p[1] ) {
- gcry_free(p);
+ m_free(p);
display_online_help( keyword );
}
else
@@ -482,13 +650,13 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt )
p = tty_get( prompt );
trim_spaces(p); /* it is okay to do this here */
if( *p == '?' && !p[1] ) {
- gcry_free(p);
+ m_free(p);
display_online_help( keyword );
}
else {
tty_kill_prompt();
yes = answer_is_yes(p);
- gcry_free(p);
+ m_free(p);
return yes;
}
}
@@ -510,13 +678,13 @@ cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
p = tty_get( prompt );
trim_spaces(p); /* it is okay to do this here */
if( *p == '?' && !p[1] ) {
- gcry_free(p);
+ m_free(p);
display_online_help( keyword );
}
else {
tty_kill_prompt();
yes = answer_is_yes_no_quit(p);
- gcry_free(p);
+ m_free(p);
return yes;
}
}
diff --git a/g10/status.h b/g10/status.h
index f9cce5b6b..86e232719 100644
--- a/g10/status.h
+++ b/g10/status.h
@@ -1,5 +1,5 @@
/* status.h
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_STATUS_H
-#define GPG_STATUS_H
+#ifndef G10_STATUS_H
+#define G10_STATUS_H
#define STATUS_ENTER 1
@@ -33,7 +33,7 @@
#define STATUS_BADARMOR 7
#define STATUS_RSA_OR_IDEA 8
-#define STATUS_SIGEXPIRED 9
+#define STATUS_KEYEXPIRED 9
#define STATUS_KEYREVOKED 10
#define STATUS_TRUST_UNDEFINED 11
@@ -81,12 +81,32 @@
#define STATUS_GOT_IT 49
#define STATUS_PROGRESS 50
#define STATUS_SIG_CREATED 51
+#define STATUS_SESSION_KEY 52
+#define STATUS_NOTATION_NAME 53
+#define STATUS_NOTATION_DATA 54
+#define STATUS_POLICY_URL 55
+#define STATUS_BEGIN_STREAM 56
+#define STATUS_END_STREAM 57
+#define STATUS_KEY_CREATED 58
+#define STATUS_USERID_HINT 59
+#define STATUS_UNEXPECTED 60
+#define STATUS_INV_RECP 61
+#define STATUS_NO_RECP 62
+#define STATUS_ALREADY_SIGNED 63
+#define STATUS_SIGEXPIRED 64
+#define STATUS_EXPSIG 65
+#define STATUS_EXPKEYSIG 66
+#define STATUS_ATTRIBUTE 67
/*-- status.c --*/
void set_status_fd ( int fd );
int is_status_enabled ( void );
void write_status ( int no );
void write_status_text ( int no, const char *text );
+void write_status_buffer ( int no,
+ const char *buffer, size_t len, int wrap );
+void write_status_text_and_buffer ( int no, const char *text,
+ const char *buffer, size_t len, int wrap );
#ifdef USE_SHM_COPROCESSING
void init_shm_coprocessing ( ulong requested_shm_size, int lock_mem );
@@ -94,6 +114,7 @@ void write_status_text ( int no, const char *text );
int cpr_enabled(void);
char *cpr_get( const char *keyword, const char *prompt );
+char *cpr_get_no_help( const char *keyword, const char *prompt );
char *cpr_get_utf8( const char *keyword, const char *prompt );
char *cpr_get_hidden( const char *keyword, const char *prompt );
void cpr_kill_prompt(void);
@@ -101,4 +122,4 @@ int cpr_get_answer_is_yes( const char *keyword, const char *prompt );
int cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt );
-#endif /*GPG_STATUS_H*/
+#endif /*G10_STATUS_H*/
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index 6729d4e56..cd46f1f5a 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -1,5 +1,5 @@
/* tdbdump.c
- * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -33,7 +33,7 @@
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "trustdb.h"
#include "options.h"
@@ -46,22 +46,7 @@
#define HEXTOBIN(x) ( (x) >= '0' && (x) <= '9' ? ((x)-'0') : \
(x) >= 'A' && (x) <= 'F' ? ((x)-'A'+10) : ((x)-'a'+10))
-/****************
- * Read a record but die if it does not exist
- * fixme: duplicate: remove it
- */
-#if 0
-static void
-read_record( ulong recno, TRUSTREC *rec, int rectype )
-{
- int rc = tdbio_read_record( recno, rec, rectype );
- if( !rc )
- return;
- log_error(_("trust record %lu, req type %d: read failed: %s\n"),
- recno, rectype, gpg_errstr(rc) );
- tdbio_invalid();
-}
-#endif
+
/****************
* Wirte a record but die on error
*/
@@ -72,263 +57,13 @@ write_record( TRUSTREC *rec )
if( !rc )
return;
log_error(_("trust record %lu, type %d: write failed: %s\n"),
- rec->recnum, rec->rectype, gpg_errstr(rc) );
+ rec->recnum, rec->rectype, g10_errstr(rc) );
tdbio_invalid();
}
/****************
- * sync the db
- */
-static void
-do_sync(void)
-{
- int rc = tdbio_sync();
- if( !rc )
- return;
- log_error(_("trustdb: sync failed: %s\n"), gpg_errstr(rc) );
- gpg_exit(2);
-}
-
-#if 0
-static int
-print_sigflags( FILE *fp, unsigned flags )
-{
- if( flags & SIGF_CHECKED ) {
- fprintf(fp,"%c%c%c",
- (flags & SIGF_VALID) ? 'V':'-',
- (flags & SIGF_EXPIRED) ? 'E':'-',
- (flags & SIGF_REVOKED) ? 'R':'-');
- }
- else if( flags & SIGF_NOPUBKEY)
- fputs("?--", fp);
- else
- fputs("---", fp);
- return 3;
-}
-#endif
-
-
-/****************
- * Walk through the signatures of a public key.
- * The caller must provide a context structure, with all fields set
- * to zero, but the local_id field set to the requested key;
- * This function does not change this field. On return the context
- * is filled with the local-id of the signature and the signature flag.
- * No fields should be changed (clearing all fields and setting
- * pubkeyid is okay to continue with an other pubkey)
- * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
- * FIXME: Do we really need this large and complicated function?
- */
-#if 0
-static int
-walk_sigrecs( SIGREC_CONTEXT *c )
-{
- TRUSTREC *r;
- ulong rnum;
-
- if( c->ctl.eof )
- return -1;
- r = &c->ctl.rec;
- if( !c->ctl.init_done ) {
- c->ctl.init_done = 1;
- read_record( c->lid, r, 0 );
- if( r->rectype != RECTYPE_DIR ) {
- c->ctl.eof = 1;
- return -1; /* return eof */
- }
- c->ctl.nextuid = r->r.dir.uidlist;
- /* force a read */
- c->ctl.index = SIGS_PER_RECORD;
- r->r.sig.next = 0;
- }
-
- /* need a loop to skip over deleted sigs */
- do {
- if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
- rnum = r->r.sig.next;
- if( !rnum && c->ctl.nextuid ) { /* read next uid record */
- read_record( c->ctl.nextuid, r, RECTYPE_UID );
- c->ctl.nextuid = r->r.uid.next;
- rnum = r->r.uid.siglist;
- }
- if( !rnum ) {
- c->ctl.eof = 1;
- return -1; /* return eof */
- }
- read_record( rnum, r, RECTYPE_SIG );
- if( r->r.sig.lid != c->lid ) {
- log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
- c->ctl.eof = 1;
- tdbio_invalid();
- }
- c->ctl.index = 0;
- }
- } while( !r->r.sig.sig[c->ctl.index++].lid );
-
- c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
- c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
- return 0;
-}
-#endif
-
-#if 0
-static int
-do_list_sigs( ulong root, ulong pk_lid, int depth,
- LOCAL_ID_TABLE lids, unsigned *lineno )
-{
- SIGREC_CONTEXT sx;
- int rc;
- u32 keyid[2];
-
- memset( &sx, 0, sizeof sx );
- sx.lid = pk_lid;
- for(;;) {
- rc = walk_sigrecs( &sx ); /* should we replace it and use */
- if( rc )
- break;
- rc = keyid_from_lid( sx.sig_lid, keyid );
- if( rc ) {
- printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
- print_sigflags( stdout, sx.sig_flag );
- putchar('\n');
- ++*lineno;
- }
- else {
- printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
- (ulong)keyid[1], sx.sig_lid );
- print_sigflags( stdout, sx.sig_flag );
- putchar(' ');
- /* check whether we already checked this pk_lid */
- if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
- print_user_id("[ultimately trusted]", keyid);
- ++*lineno;
- }
- else if( sx.sig_lid == pk_lid ) {
- printf("[self-signature]\n");
- ++*lineno;
- }
- else if( sx.sig_lid == root ) {
- printf("[closed]\n");
- ++*lineno;
- }
- else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
- unsigned refline;
- qry_lid_table_flag( lids, sx.sig_lid, &refline );
- printf("[see line %u]\n", refline);
- ++*lineno;
- }
- else if( depth+1 >= MAX_LIST_SIGS_DEPTH ) {
- print_user_id( "[too deeply nested]", keyid );
- ++*lineno;
- }
- else {
- print_user_id( "", keyid );
- ++*lineno;
- rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
- if( rc )
- break;
- }
- }
- }
- return rc==-1? 0 : rc;
-}
-#endif
-/****************
- * List all signatures of a public key
- */
-static int
-list_sigs( ulong pubkey_id )
-{
- int rc=0;
- #if 0
- u32 keyid[2];
- LOCAL_ID_TABLE lids;
- unsigned lineno = 1;
-
- rc = keyid_from_lid( pubkey_id, keyid );
- if( rc )
- return rc;
- printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
- print_user_id("", keyid);
- printf("----------------------\n");
-
- lids = new_lid_table();
- rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
- putchar('\n');
- release_lid_table(lids);
- #endif
- return rc;
-}
-
-/****************
- * List all records of a public key
- */
-static int
-list_records( ulong lid )
-{
- int rc;
- TRUSTREC dr, ur, rec;
- ulong recno;
-
- rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
- if( rc ) {
- log_error(_("lid %lu: read dir record failed: %s\n"),
- lid, gpg_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &dr, stdout );
-
- for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
- rc = tdbio_read_record( recno, &rec, 0 );
- if( rc ) {
- log_error(_("lid %lu: read key record failed: %s\n"),
- lid, gpg_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
-
- for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
- rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
- if( rc ) {
- log_error(_("lid %lu: read uid record failed: %s\n"),
- lid, gpg_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &ur, stdout );
- /* preference records */
- for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
- rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
- if( rc ) {
- log_error(_("lid %lu: read pref record failed: %s\n"),
- lid, gpg_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
- /* sig records */
- for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
- rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
- if( rc ) {
- log_error(_("lid %lu: read sig record failed: %s\n"),
- lid, gpg_errstr(rc));
- return rc;
- }
- tdbio_dump_record( &rec, stdout );
- }
- }
-
- /* add cache record dump here */
-
-
-
- return rc;
-}
-
-
-/****************
- * Dump the complte trustdb or only the entries of one key.
+ * Dump the entire trustdb or only the entries of one key.
*/
void
list_trustdb( const char *username )
@@ -336,38 +71,8 @@ list_trustdb( const char *username )
TRUSTREC rec;
init_trustdb();
-
- if( username && *username == '#' ) {
- int rc;
- ulong lid = atoi(username+1);
-
- if( (rc = list_records( lid)) )
- log_error(_("user '%s' read problem: %s\n"),
- username, gpg_errstr(rc));
- else if( (rc = list_sigs( lid )) )
- log_error(_("user '%s' list problem: %s\n"),
- username, gpg_errstr(rc));
- }
- else if( username ) {
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- int rc;
-
- if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
- log_error(_("user '%s' not found: %s\n"), username, gpg_errstr(rc) );
- else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
- log_error(_("problem finding '%s' in trustdb: %s\n"),
- username, gpg_errstr(rc));
- else if( rc == -1 )
- log_error(_("user '%s' not in trustdb\n"), username);
- else if( (rc = list_records( pk->local_id)) )
- log_error(_("user '%s' read problem: %s\n"),
- username, gpg_errstr(rc));
- else if( (rc = list_sigs( pk->local_id )) )
- log_error(_("user '%s' list problem: %s\n"),
- username, gpg_errstr(rc));
- free_public_key( pk );
- }
- else {
+ /* for now we ignore the user ID */
+ if (1) {
ulong recnum;
int i;
@@ -391,33 +96,22 @@ void
export_ownertrust()
{
TRUSTREC rec;
- TRUSTREC rec2;
ulong recnum;
int i;
byte *p;
- int rc;
init_trustdb();
printf(_("# List of assigned trustvalues, created %s\n"
"# (Use \"gpg --import-ownertrust\" to restore them)\n"),
asctimestamp( make_timestamp() ) );
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype == RECTYPE_DIR ) {
- if( !rec.r.dir.keylist ) {
- log_error(_("directory record w/o primary key\n"));
- continue;
- }
- if( !rec.r.dir.ownertrust )
+ if( rec.rectype == RECTYPE_TRUST ) {
+ if( !rec.r.trust.ownertrust )
continue;
- rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
- if( rc ) {
- log_error(_("error reading key record: %s\n"), gpg_errstr(rc));
- continue;
- }
- p = rec2.r.key.fingerprint;
- for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
+ p = rec.r.trust.fingerprint;
+ for(i=0; i < 20; i++, p++ )
printf("%02X", *p );
- printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
+ printf(":%u:\n", (unsigned int)rec.r.trust.ownertrust );
}
}
}
@@ -431,7 +125,10 @@ import_ownertrust( const char *fname )
char line[256];
char *p;
size_t n, fprlen;
- unsigned otrust;
+ unsigned int otrust;
+ byte fpr[20];
+ int any = 0;
+ int rc;
init_trustdb();
if( !fname || (*fname == '-' && !fname[1]) ) {
@@ -446,7 +143,6 @@ import_ownertrust( const char *fname )
while( fgets( line, DIM(line)-1, fp ) ) {
TRUSTREC rec;
- int rc;
if( !*line || *line == '#' )
continue;
@@ -475,51 +171,52 @@ import_ownertrust( const char *fname )
if( !otrust )
continue; /* no otrust defined - no need to update or insert */
/* convert the ascii fingerprint to binary */
- for(p=line, fprlen=0; *p != ':'; p += 2 )
- line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
- line[fprlen] = 0;
-
- repeat:
- rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
+ for(p=line, fprlen=0; fprlen < 20 && *p != ':'; p += 2 )
+ fpr[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
+ while (fprlen < 20)
+ fpr[fprlen++] = 0;
+
+ rc = tdbio_search_trust_byfpr (fpr, &rec);
if( !rc ) { /* found: update */
- if( rec.r.dir.ownertrust )
- log_info("LID %lu: changing trust from %u to %u\n",
- rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
- else
- log_info("LID %lu: setting trust to %u\n",
- rec.r.dir.lid, otrust );
- rec.r.dir.ownertrust = otrust;
- write_record( &rec );
+ if (rec.r.trust.ownertrust != otrust)
+ {
+ if( rec.r.trust.ownertrust )
+ log_info("changing ownertrust from %u to %u\n",
+ rec.r.trust.ownertrust, otrust );
+ else
+ log_info("setting ownertrust to %u\n", otrust );
+ rec.r.trust.ownertrust = otrust;
+ write_record (&rec );
+ any = 1;
+ }
}
- else if( rc == -1 ) { /* not found; get the key from the ring */
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
-
- log_info_f(fname, _("key not in trustdb, searching ring.\n"));
- rc = get_pubkey_byfprint( pk, line, fprlen );
- if( rc )
- log_info_f(fname, _("key not in ring: %s\n"), gpg_errstr(rc));
- else {
- rc = query_trust_record( pk ); /* only as assertion */
- if( rc != -1 )
- log_error_f(fname, _("Oops: key is now in trustdb???\n"));
- else {
- rc = insert_trust_record_by_pk( pk );
- if( !rc )
- goto repeat; /* update the ownertrust */
- log_error_f(fname, _("insert trust record failed: %s\n"),
- gpg_errstr(rc) );
- }
- }
+ else if( rc == -1 ) { /* not found: insert */
+ log_info("inserting ownertrust of %u\n", otrust );
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ memcpy (rec.r.trust.fingerprint, fpr, 20);
+ rec.r.trust.ownertrust = otrust;
+ write_record (&rec );
+ any = 1;
}
else /* error */
- log_error_f(fname, _("error finding dir record: %s\n"),
- gpg_errstr(rc));
+ log_error_f(fname, _("error finding trust record: %s\n"),
+ g10_errstr(rc));
}
if( ferror(fp) )
log_error_f(fname, _("read error: %s\n"), strerror(errno) );
if( !is_stdin )
fclose(fp);
- do_sync();
- sync_trustdb();
+
+ if (any)
+ {
+ revalidation_mark ();
+ rc = tdbio_sync ();
+ if (rc)
+ log_error (_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+ }
+
}
+
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 669f66ffc..537e4c0d4 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -1,5 +1,5 @@
/* tdbio.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -31,7 +31,7 @@
#include "errors.h"
#include "iobuf.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
#include "options.h"
#include "main.h"
@@ -39,6 +39,9 @@
#include "trustdb.h"
#include "tdbio.h"
+#if defined(HAVE_DOSISH_SYSTEM) && !defined(__CYGWIN32__)
+#define ftruncate chsize
+#endif
/****************
* Yes, this is a very simple implementation. We should really
@@ -83,6 +86,8 @@ static int db_fd = -1;
static int in_transaction;
static void open_db(void);
+static void migrate_from_v2 (void);
+
/*************************************
@@ -115,13 +120,13 @@ write_cache_item( CACHE_CTRL r )
if( lseek( db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
log_error(_("trustdb rec %lu: lseek failed: %s\n"),
r->recno, strerror(errno) );
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
}
n = write( db_fd, r->data, TRUST_RECORD_LEN);
if( n != TRUST_RECORD_LEN ) {
log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
r->recno, n, strerror(errno) );
- return GPGERR_WRITE_FILE;
+ return G10ERR_WRITE_FILE;
}
r->flags.dirty = 0;
return 0;
@@ -175,7 +180,7 @@ put_record_into_cache( ulong recno, const char *data )
}
/* see whether we reached the limit */
if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->flags.used = 1;
r->recno = recno;
memcpy( r->data, data, TRUST_RECORD_LEN );
@@ -218,7 +223,7 @@ put_record_into_cache( ulong recno, const char *data )
if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */
if( opt.debug && !(cache_entries % 100) )
log_debug("increasing tdbio cache size\n");
- r = gcry_xmalloc( sizeof *r );
+ r = m_alloc( sizeof *r );
r->flags.used = 1;
r->recno = recno;
memcpy( r->data, data, TRUST_RECORD_LEN );
@@ -230,7 +235,7 @@ put_record_into_cache( ulong recno, const char *data )
return 0;
}
log_info(_("trustdb transaction too large\n"));
- return GPGERR_RESOURCE_LIMIT;
+ return G10ERR_RESOURCE_LIMIT;
}
if( dirty_count ) {
int n = dirty_count / 5; /* discard some dirty entries */
@@ -406,6 +411,28 @@ cleanup(void)
}
}
+static int
+create_version_record (void)
+{
+ TRUSTREC rec;
+ int rc;
+
+ memset( &rec, 0, sizeof rec );
+ rec.r.ver.version = 3;
+ rec.r.ver.created = make_timestamp();
+ rec.r.ver.marginals = opt.marginals_needed;
+ rec.r.ver.completes = opt.completes_needed;
+ rec.r.ver.cert_depth = opt.max_cert_depth;
+ rec.rectype = RECTYPE_VER;
+ rec.recnum = 0;
+ rc = tdbio_write_record( &rec );
+ if( !rc )
+ tdbio_sync();
+ return rc;
+}
+
+
+
int
tdbio_set_dbname( const char *new_dbname, int create )
{
@@ -416,20 +443,23 @@ tdbio_set_dbname( const char *new_dbname, int create )
atexit( cleanup );
initialized = 1;
}
- fname = new_dbname? gcry_xstrdup( new_dbname )
- : make_filename(opt.homedir, "trustdb.gpg", NULL );
+ fname = new_dbname? m_strdup( new_dbname )
+ : make_filename(opt.homedir,
+ "trustdb" EXTSEP_S "gpg", NULL );
+
+ check_permissions(fname,0,0);
if( access( fname, R_OK ) ) {
if( errno != ENOENT ) {
log_error( _("%s: can't access: %s\n"), fname, strerror(errno) );
- gcry_free(fname);
- return GPGERR_TRUSTDB;
+ m_free(fname);
+ return G10ERR_TRUSTDB;
}
if( create ) {
FILE *fp;
TRUSTREC rec;
int rc;
- char *p = strrchr( fname, '/' );
+ char *p = strrchr( fname, DIRSEP_C );
assert(p);
*p = 0;
@@ -437,14 +467,22 @@ tdbio_set_dbname( const char *new_dbname, int create )
try_make_homedir( fname );
log_fatal( _("%s: directory does not exist!\n"), fname );
}
- *p = '/';
+ *p = DIRSEP_C;
+ m_free(db_name);
+ db_name = fname;
+#ifdef __riscos__
+ if( !lockhandle )
+ lockhandle = create_dotlock( db_name );
+ if( !lockhandle )
+ log_fatal( _("%s: can't create lock\n"), db_name );
+ if( make_dotlock( lockhandle, -1 ) )
+ log_fatal( _("%s: can't make lock\n"), db_name );
+#endif /* __riscos__ */
fp =fopen( fname, "wb" );
if( !fp )
log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) );
fclose(fp);
- gcry_free(db_name);
- db_name = fname;
#ifdef HAVE_DOSISH_SYSTEM
db_fd = open( db_name, O_RDWR | O_BINARY );
#else
@@ -453,25 +491,17 @@ tdbio_set_dbname( const char *new_dbname, int create )
if( db_fd == -1 )
log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
+#ifndef __riscos__
if( !lockhandle )
lockhandle = create_dotlock( db_name );
if( !lockhandle )
log_fatal( _("%s: can't create lock\n"), db_name );
+#endif /* !__riscos__ */
- memset( &rec, 0, sizeof rec );
- rec.r.ver.version = 2;
- rec.r.ver.created = make_timestamp();
- rec.r.ver.marginals = opt.marginals_needed;
- rec.r.ver.completes = opt.completes_needed;
- rec.r.ver.cert_depth = opt.max_cert_depth;
- rec.rectype = RECTYPE_VER;
- rec.recnum = 0;
- rc = tdbio_write_record( &rec );
- if( !rc )
- tdbio_sync();
+ rc = create_version_record ();
if( rc )
log_fatal( _("%s: failed to create version record: %s"),
- fname, gpg_errstr(rc));
+ fname, g10_errstr(rc));
/* and read again to check that we are okay */
if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
log_fatal( _("%s: invalid trustdb created\n"), db_name );
@@ -482,7 +512,7 @@ tdbio_set_dbname( const char *new_dbname, int create )
return 0;
}
}
- gcry_free(db_name);
+ m_free(db_name);
db_name = fname;
return 0;
}
@@ -499,27 +529,45 @@ tdbio_get_dbname()
static void
open_db()
{
- TRUSTREC rec;
- assert( db_fd == -1 );
-
- if( !lockhandle )
- lockhandle = create_dotlock( db_name );
- if( !lockhandle )
- log_fatal( _("%s: can't create lock\n"), db_name );
- #ifdef HAVE_DOSISH_SYSTEM
- db_fd = open( db_name, O_RDWR | O_BINARY );
- #else
- db_fd = open( db_name, O_RDWR );
- #endif
- if( db_fd == -1 )
- log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
- if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
- log_fatal( _("%s: invalid trustdb\n"), db_name );
+ byte buf[10];
+ int n;
+ TRUSTREC rec;
+
+ assert( db_fd == -1 );
+
+ if (!lockhandle )
+ lockhandle = create_dotlock( db_name );
+ if (!lockhandle )
+ log_fatal( _("%s: can't create lock\n"), db_name );
+#ifdef __riscos__
+ if (make_dotlock( lockhandle, -1 ) )
+ log_fatal( _("%s: can't make lock\n"), db_name );
+#endif /* __riscos__ */
+#ifdef HAVE_DOSISH_SYSTEM
+ db_fd = open (db_name, O_RDWR | O_BINARY );
+#else
+ db_fd = open (db_name, O_RDWR );
+#endif
+ if ( db_fd == -1 )
+ log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
+
+ /* check whether we need to do a version migration */
+ do
+ n = read (db_fd, buf, 5);
+ while (n==-1 && errno == EINTR);
+ if (n == 5 && !memcmp (buf, "\x01gpg\x02", 5))
+ {
+ migrate_from_v2 ();
+ }
+
+ /* read the version record */
+ if (tdbio_read_record (0, &rec, RECTYPE_VER ) )
+ log_fatal( _("%s: invalid trustdb\n"), db_name );
}
/****************
- * Make a hashtable: type 0 = key hash, 1 = sdir hash
+ * Make a hashtable: type 0 = trust hash
*/
static void
create_hashtable( TRUSTREC *vr, int type )
@@ -536,9 +584,8 @@ create_hashtable( TRUSTREC *vr, int type )
assert(recnum); /* this is will never be the first record */
if( !type )
- vr->r.ver.keyhashtbl = recnum;
- else
- vr->r.ver.sdirhashtbl = recnum;
+ vr->r.ver.trusthashtbl = recnum;
+
/* Now write the records */
n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
for(i=0; i < n; i++, recnum++ ) {
@@ -548,7 +595,7 @@ create_hashtable( TRUSTREC *vr, int type )
rc = tdbio_write_record( &rec );
if( rc )
log_fatal( _("%s: failed to create hashtable: %s\n"),
- db_name, gpg_errstr(rc));
+ db_name, g10_errstr(rc));
}
/* update the version record */
rc = tdbio_write_record( vr );
@@ -556,7 +603,7 @@ create_hashtable( TRUSTREC *vr, int type )
rc = tdbio_sync();
if( rc )
log_fatal( _("%s: error updating version record: %s\n"),
- db_name, gpg_errstr(rc));
+ db_name, g10_errstr(rc));
}
@@ -572,7 +619,7 @@ tdbio_db_matches_options()
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
if( !vr.r.ver.marginals && !vr.r.ver.completes
&& !vr.r.ver.cert_depth )
@@ -585,7 +632,7 @@ tdbio_db_matches_options()
rc = tdbio_sync();
if( rc )
log_error( _("%s: error writing version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
}
yes_no = vr.r.ver.marginals == opt.marginals_needed
@@ -597,105 +644,70 @@ tdbio_db_matches_options()
/****************
- * Return the modifiy stamp.
- * if modify_down is true, the modify_down stamp will be
- * returned, otherwise the modify_up stamp.
+ * Return the nextstamp value.
*/
ulong
-tdbio_read_modify_stamp( int modify_down )
+tdbio_read_nextcheck ()
{
TRUSTREC vr;
int rc;
- ulong mod;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
-
- mod = modify_down? vr.r.ver.mod_down : vr.r.ver.mod_up;
-
- /* Always return at least 1 to make comparison easier;
- * this is still far back in history (before Led Zeppelin III :-) */
- return mod ? mod : 1;
+ db_name, g10_errstr(rc) );
+ return vr.r.ver.nextcheck;
}
-void
-tdbio_write_modify_stamp( int up, int down )
+/* Return true when the stamp was actually changed. */
+int
+tdbio_write_nextcheck (ulong stamp)
{
TRUSTREC vr;
int rc;
- ulong stamp;
-
- if( !(up || down) )
- return;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
- stamp = make_timestamp();
- if( down )
- vr.r.ver.mod_down = stamp;
- if( up )
- vr.r.ver.mod_up = stamp;
+ if (vr.r.ver.nextcheck == stamp)
+ return 0;
+ vr.r.ver.nextcheck = stamp;
rc = tdbio_write_record( &vr );
if( rc )
log_fatal( _("%s: error writing version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
+ return 1;
}
+
/****************
- * Return the record number of the keyhash tbl or create a new one.
+ * Return the record number of the trusthash tbl or create a new one.
*/
static ulong
-get_keyhashrec(void)
+get_trusthashrec(void)
{
- static ulong keyhashtbl; /* record number of the key hashtable */
+ static ulong trusthashtbl; /* record number of the trust hashtable */
- if( !keyhashtbl ) {
+ if( !trusthashtbl ) {
TRUSTREC vr;
int rc;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
- if( !vr.r.ver.keyhashtbl )
+ db_name, g10_errstr(rc) );
+ if( !vr.r.ver.trusthashtbl )
create_hashtable( &vr, 0 );
- keyhashtbl = vr.r.ver.keyhashtbl;
+ trusthashtbl = vr.r.ver.trusthashtbl;
}
- return keyhashtbl;
+ return trusthashtbl;
}
-/****************
- * Return the record number of the shadow direcory hash table
- * or create a new one.
- */
-static ulong
-get_sdirhashrec(void)
-{
- static ulong sdirhashtbl; /* record number of the hashtable */
-
- if( !sdirhashtbl ) {
- TRUSTREC vr;
- int rc;
-
- rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
- if( rc )
- log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
- if( !vr.r.ver.sdirhashtbl )
- create_hashtable( &vr, 1 );
-
- sdirhashtbl = vr.r.ver.sdirhashtbl;
- }
- return sdirhashtbl;
-}
/****************
@@ -719,7 +731,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "upd_hashtable: read failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
@@ -729,7 +741,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name, "upd_hashtable: write htbl failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
}
@@ -738,7 +750,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_read_record( item, &rec, 0 );
if( rc ) {
log_error( "upd_hashtable: read item failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
@@ -747,7 +759,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
level++;
if( level >= keylen ) {
log_error( "hashtable has invalid indirections.\n");
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
goto next_level;
}
@@ -763,8 +775,8 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
- log_error( "scan keyhashtbl read hlst failed: %s\n",
- gpg_errstr(rc) );
+ log_error( "upd_hashtable: read hlst failed: %s\n",
+ g10_errstr(rc) );
return rc;
}
}
@@ -779,7 +791,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &rec );
if( rc )
log_error( "upd_hashtable: write hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc; /* done */
}
}
@@ -788,7 +800,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
&rec, RECTYPE_HLST );
if( rc ) {
log_error( "upd_hashtable: read hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
}
@@ -797,7 +809,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( "upd_hashtable: write hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
memset( &rec, 0, sizeof rec );
@@ -807,14 +819,12 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &rec );
if( rc )
log_error( "upd_hashtable: write ext hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc; /* done */
}
} /* end loop over hlst slots */
}
- else if( rec.rectype == RECTYPE_KEY
- || rec.rectype == RECTYPE_DIR
- || rec.rectype == RECTYPE_SDIR ) { /* insert a list record */
+ else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */
if( rec.recnum == newrecnum ) {
return 0;
}
@@ -827,7 +837,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( "upd_hashtable: write new hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
/* update the hashtable record */
@@ -835,14 +845,14 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_write_record( &lastrec );
if( rc )
log_error( "upd_hashtable: update htbl failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc; /* ready */
}
else {
log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n",
table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
list_trustdb(NULL);
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
}
@@ -870,7 +880,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "drop_from_hashtable: read failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
@@ -883,14 +893,14 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
rc = tdbio_write_record( &rec );
if( rc )
log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
rc = tdbio_read_record( item, &rec, 0 );
if( rc ) {
log_error( "drop_from_hashtable: read item failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
@@ -899,7 +909,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
level++;
if( level >= keylen ) {
log_error( "hashtable has invalid indirections.\n");
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
goto next_level;
}
@@ -912,7 +922,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
rc = tdbio_write_record( &rec );
if( rc )
log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
}
@@ -920,8 +930,8 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
- log_error( "scan keyhashtbl read hlst failed: %s\n",
- gpg_errstr(rc) );
+ log_error( "drop_from_hashtable: read hlst failed: %s\n",
+ g10_errstr(rc) );
return rc;
}
}
@@ -932,7 +942,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n",
table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
@@ -958,7 +968,7 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
hashrec += msb / ITEMS_PER_HTBL_RECORD;
rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
if( rc ) {
- log_error( db_name, "lookup_hashtable failed: %s\n", gpg_errstr(rc) );
+ log_error( db_name, "lookup_hashtable failed: %s\n", g10_errstr(rc) );
return rc;
}
@@ -968,7 +978,7 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
rc = tdbio_read_record( item, rec, 0 );
if( rc ) {
- log_error( db_name, "hashtable read failed: %s\n", gpg_errstr(rc) );
+ log_error( db_name, "hashtable read failed: %s\n", g10_errstr(rc) );
return rc;
}
if( rec->rectype == RECTYPE_HTBL ) {
@@ -976,7 +986,7 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
level++;
if( level >= keylen ) {
log_error( db_name, "hashtable has invalid indirections\n");
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
goto next_level;
}
@@ -991,7 +1001,7 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 );
if( rc ) {
log_error( "lookup_hashtable: read item failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
if( (*cmpfnc)( cmpdata, &tmp ) ) {
@@ -1004,7 +1014,7 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
if( rc ) {
log_error( "lookup_hashtable: read hlst failed: %s\n",
- gpg_errstr(rc) );
+ g10_errstr(rc) );
return rc;
}
}
@@ -1021,57 +1031,16 @@ lookup_hashtable( ulong table, const byte *key, size_t keylen,
}
-
-
/****************
- * Update the key hashtbl or create the table if it does not exist
+ * Update the trust hashtbl or create the table if it does not exist
*/
static int
-update_keyhashtbl( TRUSTREC *kr )
+update_trusthashtbl( TRUSTREC *tr )
{
- return upd_hashtable( get_keyhashrec(),
- kr->r.key.fingerprint,
- kr->r.key.fingerprint_len, kr->recnum );
+ return upd_hashtable( get_trusthashrec(),
+ tr->r.trust.fingerprint, 20, tr->recnum );
}
-/****************
- * Update the shadow dir hashtbl or create the table if it does not exist
- */
-static int
-update_sdirhashtbl( TRUSTREC *sr )
-{
- byte key[8];
-
- u32tobuf( key , sr->r.sdir.keyid[0] );
- u32tobuf( key+4 , sr->r.sdir.keyid[1] );
- return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
-}
-
-/****************
- * Drop the records from the key-hashtbl
- */
-static int
-drop_from_keyhashtbl( TRUSTREC *kr )
-{
- return drop_from_hashtable( get_keyhashrec(),
- kr->r.key.fingerprint,
- kr->r.key.fingerprint_len, kr->recnum );
-}
-
-/****************
- * Drop record drom the shadow dir hashtbl
- */
-static int
-drop_from_sdirhashtbl( TRUSTREC *sr )
-{
- byte key[8];
-
- u32tobuf( key , sr->r.sdir.keyid[0] );
- u32tobuf( key+4 , sr->r.sdir.keyid[1] );
- return drop_from_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
-}
-
-
void
@@ -1079,7 +1048,6 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{
int i;
ulong rnum = rec->recnum;
- byte *p;
fprintf(fp, "rec %5lu, ", rnum );
@@ -1087,116 +1055,18 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
case 0: fprintf(fp, "blank\n");
break;
case RECTYPE_VER: fprintf(fp,
- "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
- rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
+ "version, td=%lu, f=%lu, m/c/d=%d/%d/%d nc=%lu (%s)\n",
+ rec->r.ver.trusthashtbl,
rec->r.ver.firstfree,
rec->r.ver.marginals,
rec->r.ver.completes,
rec->r.ver.cert_depth,
- strtimestamp(rec->r.ver.mod_down) );
- fprintf(fp, ", up=%s\n", strtimestamp(rec->r.ver.mod_up) );
+ rec->r.ver.nextcheck,
+ strtimestamp(rec->r.ver.nextcheck)
+ );
break;
case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
break;
- case RECTYPE_DIR:
- fprintf(fp, "dir %lu, keys=%lu, uids=%lu, t=%02x",
- rec->r.dir.lid,
- rec->r.dir.keylist,
- rec->r.dir.uidlist,
- rec->r.dir.ownertrust );
- if( rec->r.dir.valcheck )
- fprintf( fp, ", v=%02x/%s", rec->r.dir.validity,
- strtimestamp(rec->r.dir.valcheck) );
- if( rec->r.dir.checkat )
- fprintf( fp, ", a=%s", strtimestamp(rec->r.dir.checkat) );
- if( rec->r.dir.dirflags & DIRF_CHECKED ) {
- if( rec->r.dir.dirflags & DIRF_VALID )
- fputs(", valid", fp );
- if( rec->r.dir.dirflags & DIRF_EXPIRED )
- fputs(", expired", fp );
- if( rec->r.dir.dirflags & DIRF_REVOKED )
- fputs(", revoked", fp );
- if( rec->r.dir.dirflags & DIRF_NEWKEYS )
- fputs(", newkeys", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_KEY:
- fprintf(fp, "key %lu, n=%lu a=%d ",
- rec->r.key.lid,
- rec->r.key.next,
- rec->r.key.pubkey_algo );
- for(i=0; i < rec->r.key.fingerprint_len; i++ )
- fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
- if( rec->r.key.keyflags & KEYF_CHECKED ) {
- if( rec->r.key.keyflags & KEYF_VALID )
- fputs(", valid", fp );
- if( rec->r.key.keyflags & KEYF_EXPIRED )
- fputs(", expired", fp );
- if( rec->r.key.keyflags & KEYF_REVOKED )
- fputs(", revoked", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_UID:
- fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
- rec->r.uid.lid,
- rec->r.uid.next,
- rec->r.uid.prefrec,
- rec->r.uid.siglist,
- rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
- fprintf( fp, ", v=%02x", rec->r.uid.validity );
- if( rec->r.uid.uidflags & UIDF_CHECKED ) {
- if( rec->r.uid.uidflags & UIDF_VALID )
- fputs(", valid", fp );
- if( rec->r.uid.uidflags & UIDF_REVOKED )
- fputs(", revoked", fp );
- }
- putc('\n', fp);
- break;
- case RECTYPE_PREF:
- fprintf(fp, "pref %lu, next=%lu,",
- rec->r.pref.lid, rec->r.pref.next);
- for(i=0,p=rec->r.pref.data; i < ITEMS_PER_PREF_RECORD; i+=2,p+=2 ) {
- if( *p )
- fprintf(fp, " %c%d", *p == PREFTYPE_SYM ? 'S' :
- *p == PREFTYPE_HASH ? 'H' :
- *p == PREFTYPE_COMPR ? 'Z' : '?', p[1]);
- }
- putc('\n', fp);
- break;
- case RECTYPE_SIG:
- fprintf(fp, "sig %lu, next=%lu,",
- rec->r.sig.lid, rec->r.sig.next );
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( rec->r.sig.sig[i].lid ) {
- fprintf(fp, " %lu:", rec->r.sig.sig[i].lid );
- if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) {
- fprintf(fp,"%c%c%c",
- (rec->r.sig.sig[i].flag & SIGF_VALID) ? 'V':
- (rec->r.sig.sig[i].flag & SIGF_IGNORED) ? 'I':'-',
- (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-',
- (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-');
- }
- else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY)
- fputs("?--", fp);
- else
- fputs("---", fp);
- }
- }
- putc('\n', fp);
- break;
- case RECTYPE_SDIR:
- fprintf(fp, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
- rec->r.sdir.lid,
- (ulong)rec->r.sdir.keyid[0],
- (ulong)rec->r.sdir.keyid[1],
- rec->r.sdir.pubkey_algo,
- (ulong)rec->r.sdir.hintlist );
- break;
- case RECTYPE_CACH:
- fprintf(fp, "cach\n");
- break;
case RECTYPE_HTBL:
fprintf(fp, "htbl,");
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
@@ -1209,6 +1079,20 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
putc('\n', fp);
break;
+ case RECTYPE_TRUST:
+ fprintf(fp, "trust ");
+ for(i=0; i < 20; i++ )
+ fprintf(fp, "%02X", rec->r.trust.fingerprint[i] );
+ fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust,
+ rec->r.trust.depth, rec->r.trust.validlist);
+ break;
+ case RECTYPE_VALID:
+ fprintf(fp, "valid ");
+ for(i=0; i < 20; i++ )
+ fprintf(fp, "%02X", rec->r.valid.namehash[i] );
+ fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity,
+ rec->r.valid.next);
+ break;
default:
fprintf(fp, "unknown type %d\n", rec->rectype );
break;
@@ -1233,7 +1117,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
if( !buf ) {
if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
- return GPGERR_READ_FILE;
+ return G10ERR_READ_FILE;
}
n = read( db_fd, readbuf, TRUST_RECORD_LEN);
if( !n ) {
@@ -1242,7 +1126,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
else if( n != TRUST_RECORD_LEN ) {
log_error(_("trustdb: read failed (n=%d): %s\n"), n,
strerror(errno) );
- return GPGERR_READ_FILE;
+ return G10ERR_READ_FILE;
}
buf = readbuf;
}
@@ -1253,7 +1137,7 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
if( expected && rec->rectype != expected ) {
log_error("%lu: read expected rec type %d, got %d\n",
recnum, expected, rec->rectype );
- return GPGERR_TRUSTDB;
+ return G10ERR_TRUSTDB;
}
p++; /* skip reserved byte */
switch( rec->rectype ) {
@@ -1262,123 +1146,35 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
case RECTYPE_VER: /* version record */
if( memcmp(buf+1, "gpg", 3 ) ) {
log_error( _("%s: not a trustdb file\n"), db_name );
- rc = GPGERR_TRUSTDB;
+ rc = G10ERR_TRUSTDB;
}
- p += 2; /* skip "pgp" */
+ p += 2; /* skip "gpg" */
rec->r.ver.version = *p++;
rec->r.ver.marginals = *p++;
rec->r.ver.completes = *p++;
rec->r.ver.cert_depth = *p++;
p += 4; /* lock flags */
rec->r.ver.created = buftoulong(p); p += 4;
- rec->r.ver.mod_down = buftoulong(p); p += 4;
- rec->r.ver.mod_up = buftoulong(p); p += 4;
- rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
+ rec->r.ver.nextcheck = buftoulong(p); p += 4;
+ p += 4;
+ p += 4;
rec->r.ver.firstfree =buftoulong(p); p += 4;
- rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
+ p += 4;
+ rec->r.ver.trusthashtbl =buftoulong(p); p += 4;
if( recnum ) {
log_error( _("%s: version record with recnum %lu\n"), db_name,
(ulong)recnum );
- rc = GPGERR_TRUSTDB;
+ rc = G10ERR_TRUSTDB;
}
- else if( rec->r.ver.version != 2 ) {
+ else if( rec->r.ver.version != 3 ) {
log_error( _("%s: invalid file version %d\n"), db_name,
rec->r.ver.version );
- rc = GPGERR_TRUSTDB;
+ rc = G10ERR_TRUSTDB;
}
break;
case RECTYPE_FREE:
rec->r.free.next = buftoulong(p); p += 4;
break;
- case RECTYPE_DIR: /*directory record */
- rec->r.dir.lid = buftoulong(p); p += 4;
- rec->r.dir.keylist = buftoulong(p); p += 4;
- rec->r.dir.uidlist = buftoulong(p); p += 4;
- rec->r.dir.cacherec = buftoulong(p); p += 4;
- rec->r.dir.ownertrust = *p++;
- rec->r.dir.dirflags = *p++;
- rec->r.dir.validity = *p++;
- rec->r.dir.valcheck = buftoulong(p); p += 4;
- rec->r.dir.checkat = buftoulong(p); p += 4;
- switch( rec->r.dir.validity ) {
- case 0:
- case TRUST_UNDEFINED:
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- case TRUST_ULTIMATE:
- break;
- default:
- log_info("lid %lu: invalid validity value - cleared\n", recnum);
- }
- if( rec->r.dir.lid != recnum ) {
- log_error( "%s: dir LID != recnum (%lu,%lu)\n",
- db_name, rec->r.dir.lid, (ulong)recnum );
- rc = GPGERR_TRUSTDB;
- }
- break;
- case RECTYPE_KEY: /* public key record */
- rec->r.key.lid = buftoulong(p); p += 4;
- rec->r.key.next = buftoulong(p); p += 4;
- p += 7;
- rec->r.key.keyflags = *p++;
- rec->r.key.pubkey_algo = *p++;
- rec->r.key.fingerprint_len = *p++;
- if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
- rec->r.key.fingerprint_len = 20;
- memcpy( rec->r.key.fingerprint, p, 20);
- break;
- case RECTYPE_UID: /* user id record */
- rec->r.uid.lid = buftoulong(p); p += 4;
- rec->r.uid.next = buftoulong(p); p += 4;
- rec->r.uid.prefrec = buftoulong(p); p += 4;
- rec->r.uid.siglist = buftoulong(p); p += 4;
- rec->r.uid.uidflags = *p++;
- rec->r.uid.validity = *p++;
- switch( rec->r.uid.validity ) {
- case 0:
- case TRUST_UNDEFINED:
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- case TRUST_ULTIMATE:
- break;
- default:
- log_info("lid %lu: invalid validity value - cleared\n", recnum);
- }
- memcpy( rec->r.uid.namehash, p, 20);
- break;
- case RECTYPE_PREF: /* preference record */
- rec->r.pref.lid = buftoulong(p); p += 4;
- rec->r.pref.next = buftoulong(p); p += 4;
- memcpy( rec->r.pref.data, p, 30 );
- break;
- case RECTYPE_SIG:
- rec->r.sig.lid = buftoulong(p); p += 4;
- rec->r.sig.next = buftoulong(p); p += 4;
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- rec->r.sig.sig[i].lid = buftoulong(p); p += 4;
- rec->r.sig.sig[i].flag = *p++;
- }
- break;
- case RECTYPE_SDIR: /* shadow directory record */
- rec->r.sdir.lid = buftoulong(p); p += 4;
- rec->r.sdir.keyid[0]= buftou32(p); p += 4;
- rec->r.sdir.keyid[1]= buftou32(p); p += 4;
- rec->r.sdir.pubkey_algo = *p++;
- p += 3;
- rec->r.sdir.hintlist = buftoulong(p);
- if( rec->r.sdir.lid != recnum ) {
- log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
- db_name, rec->r.sdir.lid, (ulong)recnum );
- rc = GPGERR_TRUSTDB;
- }
- break;
- case RECTYPE_CACH: /* cache record */
- rec->r.cache.lid = buftoulong(p); p += 4;
- memcpy(rec->r.cache.blockhash, p, 20); p += 20;
- rec->r.cache.trustlevel = *p++;
- break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
rec->r.htbl.item[i] = buftoulong(p); p += 4;
@@ -1390,10 +1186,22 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
}
break;
+ case RECTYPE_TRUST:
+ memcpy( rec->r.trust.fingerprint, p, 20); p+=20;
+ rec->r.trust.ownertrust = *p++;
+ rec->r.trust.depth = *p++;
+ p += 2;
+ rec->r.trust.validlist = buftoulong(p); p += 4;
+ break;
+ case RECTYPE_VALID:
+ memcpy( rec->r.valid.namehash, p, 20); p+=20;
+ rec->r.valid.validity = *p++;
+ rec->r.valid.next = buftoulong(p); p += 4;
+ break;
default:
log_error( "%s: invalid record type %d at recnum %lu\n",
db_name, rec->rectype, (ulong)recnum );
- rc = GPGERR_TRUSTDB;
+ rc = G10ERR_TRUSTDB;
break;
}
@@ -1430,79 +1238,18 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.ver.cert_depth;
p += 4; /* skip lock flags */
ulongtobuf(p, rec->r.ver.created); p += 4;
- ulongtobuf(p, rec->r.ver.mod_down); p += 4;
- ulongtobuf(p, rec->r.ver.mod_up); p += 4;
- ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
+ ulongtobuf(p, rec->r.ver.nextcheck); p += 4;
+ p += 4;
+ p += 4;
ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
- ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
+ p += 4;
+ ulongtobuf(p, rec->r.ver.trusthashtbl ); p += 4;
break;
case RECTYPE_FREE:
ulongtobuf(p, rec->r.free.next); p += 4;
break;
- case RECTYPE_DIR: /*directory record */
- ulongtobuf(p, rec->r.dir.lid); p += 4;
- ulongtobuf(p, rec->r.dir.keylist); p += 4;
- ulongtobuf(p, rec->r.dir.uidlist); p += 4;
- ulongtobuf(p, rec->r.dir.cacherec); p += 4;
- *p++ = rec->r.dir.ownertrust;
- *p++ = rec->r.dir.dirflags;
- *p++ = rec->r.dir.validity;
- ulongtobuf(p, rec->r.dir.valcheck); p += 4;
- ulongtobuf(p, rec->r.dir.checkat); p += 4;
- assert( rec->r.dir.lid == recnum );
- break;
-
- case RECTYPE_KEY:
- ulongtobuf(p, rec->r.key.lid); p += 4;
- ulongtobuf(p, rec->r.key.next); p += 4;
- p += 7;
- *p++ = rec->r.key.keyflags;
- *p++ = rec->r.key.pubkey_algo;
- *p++ = rec->r.key.fingerprint_len;
- memcpy( p, rec->r.key.fingerprint, 20); p += 20;
- break;
-
- case RECTYPE_UID: /* user id record */
- ulongtobuf(p, rec->r.uid.lid); p += 4;
- ulongtobuf(p, rec->r.uid.next); p += 4;
- ulongtobuf(p, rec->r.uid.prefrec); p += 4;
- ulongtobuf(p, rec->r.uid.siglist); p += 4;
- *p++ = rec->r.uid.uidflags;
- *p++ = rec->r.uid.validity;
- memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
- break;
-
- case RECTYPE_PREF:
- ulongtobuf(p, rec->r.pref.lid); p += 4;
- ulongtobuf(p, rec->r.pref.next); p += 4;
- memcpy( p, rec->r.pref.data, 30 );
- break;
-
- case RECTYPE_SIG:
- ulongtobuf(p, rec->r.sig.lid); p += 4;
- ulongtobuf(p, rec->r.sig.next); p += 4;
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
- *p++ = rec->r.sig.sig[i].flag;
- }
- break;
-
- case RECTYPE_SDIR:
- ulongtobuf( p, rec->r.sdir.lid); p += 4;
- u32tobuf( p, rec->r.sdir.keyid[0] ); p += 4;
- u32tobuf( p, rec->r.sdir.keyid[1] ); p += 4;
- *p++ = rec->r.sdir.pubkey_algo;
- p += 3;
- ulongtobuf( p, rec->r.sdir.hintlist );
- break;
-
- case RECTYPE_CACH:
- ulongtobuf(p, rec->r.cache.lid); p += 4;
- memcpy(p, rec->r.cache.blockhash, 20); p += 20;
- *p++ = rec->r.cache.trustlevel;
- break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
@@ -1517,6 +1264,20 @@ tdbio_write_record( TRUSTREC *rec )
}
break;
+ case RECTYPE_TRUST:
+ memcpy( p, rec->r.trust.fingerprint, 20); p += 20;
+ *p++ = rec->r.trust.ownertrust;
+ *p++ = rec->r.trust.depth;
+ p += 2;
+ ulongtobuf( p, rec->r.trust.validlist); p += 4;
+ break;
+
+ case RECTYPE_VALID:
+ memcpy( p, rec->r.valid.namehash, 20); p += 20;
+ *p++ = rec->r.valid.validity;
+ ulongtobuf( p, rec->r.valid.next); p += 4;
+ break;
+
default:
BUG();
}
@@ -1524,10 +1285,8 @@ tdbio_write_record( TRUSTREC *rec )
rc = put_record_into_cache( recnum, buf );
if( rc )
;
- else if( rec->rectype == RECTYPE_KEY )
- rc = update_keyhashtbl( rec );
- else if( rec->rectype == RECTYPE_SDIR )
- rc = update_sdirhashtbl( rec );
+ else if( rec->rectype == RECTYPE_TRUST )
+ rc = update_trusthashtbl( rec );
return rc;
}
@@ -1542,10 +1301,10 @@ tdbio_delete_record( ulong recnum )
rc = tdbio_read_record( recnum, &rec, 0 );
if( rc )
;
- else if( rec.rectype == RECTYPE_KEY )
- rc = drop_from_keyhashtbl( &rec );
- else if( rec.rectype == RECTYPE_SDIR )
- rc = drop_from_sdirhashtbl( &rec );
+ else if( rec.rectype == RECTYPE_TRUST ) {
+ rc = drop_from_hashtable( get_trusthashrec(),
+ rec.r.trust.fingerprint, 20, rec.recnum );
+ }
if( rc )
return rc;
@@ -1554,7 +1313,7 @@ tdbio_delete_record( ulong recnum )
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
rec.recnum = recnum;
rec.rectype = RECTYPE_FREE;
@@ -1581,13 +1340,13 @@ tdbio_new_recnum()
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
if( vr.r.ver.firstfree ) {
recnum = vr.r.ver.firstfree;
rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE );
if( rc ) {
log_error( _("%s: error reading free record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
return rc;
}
/* update dir record */
@@ -1595,7 +1354,7 @@ tdbio_new_recnum()
rc = tdbio_write_record( &vr );
if( rc ) {
log_error( _("%s: error writing dir record: %s\n"),
- db_name, gpg_errstr(rc) );
+ db_name, g10_errstr(rc) );
return rc;
}
/*zero out the new record */
@@ -1605,7 +1364,7 @@ tdbio_new_recnum()
rc = tdbio_write_record( &rec );
if( rc )
log_fatal(_("%s: failed to zero a record: %s\n"),
- db_name, gpg_errstr(rc));
+ db_name, g10_errstr(rc));
}
else { /* not found, append a new record */
offset = lseek( db_fd, 0, SEEK_END );
@@ -1622,131 +1381,193 @@ tdbio_new_recnum()
if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
log_error(_("trustdb rec %lu: lseek failed: %s\n"),
recnum, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
}
else {
int n = write( db_fd, &rec, TRUST_RECORD_LEN);
if( n != TRUST_RECORD_LEN ) {
log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
recnum, n, strerror(errno) );
- rc = GPGERR_WRITE_FILE;
+ rc = G10ERR_WRITE_FILE;
}
}
if( rc )
log_fatal(_("%s: failed to append a record: %s\n"),
- db_name, gpg_errstr(rc));
+ db_name, g10_errstr(rc));
}
return recnum ;
}
-/****************
- * Search the trustdb for a key which matches PK and return the dir record
- * The local_id of PK is set to the correct value
- */
-int
-tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec )
-{
- byte fingerprint[MAX_FINGERPRINT_LEN];
- size_t fingerlen;
- u32 keyid[2];
- int rc;
-
- keyid_from_pk( pk, keyid );
- fingerprint_from_pk( pk, fingerprint, &fingerlen );
- rc = tdbio_search_dir_byfpr( fingerprint, fingerlen,
- pk->pubkey_algo, rec );
-
- if( !rc ) {
- if( pk->local_id && pk->local_id != rec->recnum )
- log_error("%s: found record, but LID from memory does "
- "not match recnum (%lu,%lu)\n",
- db_name, pk->local_id, rec->recnum );
- pk->local_id = rec->recnum;
- }
- return rc;
-}
-
-
static int
-cmp_krec_fpr( void *dataptr, const TRUSTREC *rec )
+cmp_trec_fpr ( void *fpr, const TRUSTREC *rec )
{
- const struct cmp_krec_fpr_struct *d = dataptr;
-
- return rec->rectype == RECTYPE_KEY
- && ( !d->pubkey_algo || rec->r.key.pubkey_algo == d->pubkey_algo )
- && rec->r.key.fingerprint_len == d->fprlen
- && !memcmp( rec->r.key.fingerprint, d->fpr, d->fprlen );
+ return rec->rectype == RECTYPE_TRUST
+ && !memcmp( rec->r.trust.fingerprint, fpr, 20);
}
+
int
-tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
- int pubkey_algo, TRUSTREC *rec )
+tdbio_search_trust_byfpr( const byte *fingerprint, TRUSTREC *rec )
{
- struct cmp_krec_fpr_struct cmpdata;
- ulong recnum;
int rc;
- assert( fingerlen == 20 || fingerlen == 16 );
-
- /* locate the key using the hash table */
- cmpdata.pubkey_algo = pubkey_algo;
- cmpdata.fpr = fingerprint;
- cmpdata.fprlen = fingerlen;
- rc = lookup_hashtable( get_keyhashrec(), fingerprint, fingerlen,
- cmp_krec_fpr, &cmpdata, rec );
- if( !rc ) {
- recnum = rec->r.key.lid;
- /* Now read the dir record */
- rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
- if( rc )
- log_error("%s: can't read dirrec %lu: %s\n",
- db_name, recnum, gpg_errstr(rc) );
- }
+ /* locate the trust record using the hash table */
+ rc = lookup_hashtable( get_trusthashrec(), fingerprint, 20,
+ cmp_trec_fpr, (void*)fingerprint, rec );
return rc;
}
-
-
-static int
-cmp_sdir( void *dataptr, const TRUSTREC *rec )
+int
+tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
{
- const struct cmp_xdir_struct *d = dataptr;
+ byte fingerprint[MAX_FINGERPRINT_LEN];
+ size_t fingerlen;
- return rec->rectype == RECTYPE_SDIR
- && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo )
- && rec->r.sdir.keyid[0] == d->keyid[0]
- && rec->r.sdir.keyid[1] == d->keyid[1];
+ fingerprint_from_pk( pk, fingerprint, &fingerlen );
+ for (; fingerlen < 20; fingerlen++ )
+ fingerprint[fingerlen] = 0;
+ return tdbio_search_trust_byfpr (fingerprint, rec);
}
-int
-tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
-{
- struct cmp_xdir_struct cmpdata;
- int rc;
- byte key[8];
-
- /* locate the shadow dir record using the hash table */
- u32tobuf( key , keyid[0] );
- u32tobuf( key+4 , keyid[1] );
- cmpdata.pubkey_algo = pubkey_algo;
- cmpdata.keyid[0] = keyid[0];
- cmpdata.keyid[1] = keyid[1];
- rc = lookup_hashtable( get_sdirhashrec(), key, 8,
- cmp_sdir, &cmpdata, rec );
- return rc;
-}
-
void
tdbio_invalid(void)
{
log_error(_(
"the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n") );
- gpg_exit(2);
+ g10_exit(2);
+}
+
+/*
+ * Migrate the trustdb as just up to gpg 1.0.6 (trustdb version 2)
+ * to the 2.1 version as used with 1.0.6b - This is pretty trivial as needs
+ * only to scan the tdb and insert new the new trust records. The old ones are
+ * obsolte from now on
+ */
+static void
+migrate_from_v2 ()
+{
+ TRUSTREC rec;
+ int i, n;
+ struct {
+ ulong keyrecno;
+ byte ot;
+ byte okay;
+ byte fpr[20];
+ } *ottable;
+ int ottable_size, ottable_used;
+ byte oldbuf[40];
+ ulong recno;
+ int rc, count;
+
+ ottable_size = 5;
+ ottable = m_alloc (ottable_size * sizeof *ottable);
+ ottable_used = 0;
+
+ /* We have some restrictions here. We can't use the version record
+ * and we can't use any of the old hashtables because we dropped the
+ * code. So we first collect all ownertrusts and then use a second
+ * pass fo find the associated keys. We have to do this all without using
+ * the regular record read functions.
+ */
+
+ /* get all the ownertrusts */
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
+ for (recno=0;;recno++)
+ {
+ do
+ n = read (db_fd, oldbuf, 40);
+ while (n==-1 && errno == EINTR);
+ if (!n)
+ break; /* eof */
+ if (n != 40)
+ log_fatal ("migrate_vfrom_v2: read error or short read\n");
+
+ if (*oldbuf != 2)
+ continue;
+
+ /* v2 dir record */
+ if (ottable_used == ottable_size)
+ {
+ ottable_size += 1000;
+ ottable = m_realloc (ottable, ottable_size * sizeof *ottable);
+ }
+ ottable[ottable_used].keyrecno = buftoulong (oldbuf+6);
+ ottable[ottable_used].ot = oldbuf[18];
+ ottable[ottable_used].okay = 0;
+ memset (ottable[ottable_used].fpr,0, 20);
+ if (ottable[ottable_used].keyrecno && ottable[ottable_used].ot)
+ ottable_used++;
+ }
+ log_info ("found %d ownertrust records\n", ottable_used);
+
+ /* Read again and find the fingerprints */
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
+ for (recno=0;;recno++)
+ {
+ do
+ n = read (db_fd, oldbuf, 40);
+ while (n==-1 && errno == EINTR);
+ if (!n)
+ break; /* eof */
+ if (n != 40)
+ log_fatal ("migrate_from_v2: read error or short read\n");
+
+ if (*oldbuf != 3)
+ continue;
+
+ /* v2 key record */
+ for (i=0; i < ottable_used; i++)
+ {
+ if (ottable[i].keyrecno == recno)
+ {
+ memcpy (ottable[i].fpr, oldbuf+20, 20);
+ ottable[i].okay = 1;
+ break;
+ }
+ }
+ }
+
+ /* got everything - create the v3 trustdb */
+ if (ftruncate (db_fd, 0))
+ log_fatal ("can't truncate `%s': %s\n", db_name, strerror (errno) );
+ if (create_version_record ())
+ log_fatal ("failed to recreate version record of `%s'\n", db_name);
+
+ /* access the hash table, so it is store just after the version record,
+ * this is not needed put a dump is more pretty */
+ get_trusthashrec ();
+
+ /* And insert the old ownertrust values */
+ count = 0;
+ for (i=0; i < ottable_used; i++)
+ {
+ if (!ottable[i].okay)
+ continue;
+
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ memcpy(rec.r.trust.fingerprint, ottable[i].fpr, 20);
+ rec.r.trust.ownertrust = ottable[i].ot;
+ if (tdbio_write_record (&rec))
+ log_fatal ("failed to write trust record of `%s'\n", db_name);
+ count++;
+ }
+
+ revalidation_mark ();
+ rc = tdbio_sync ();
+ if (rc)
+ log_fatal ("failed to sync `%s'\n", db_name);
+ log_info ("migrated %d version 2 ownertrusts\n", count);
+ m_free (ottable);
}
+
diff --git a/g10/tdbio.h b/g10/tdbio.h
index a2e5404f6..f2c6bec1b 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -1,5 +1,5 @@
/* tdbio.h - Trust database I/O functions
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,8 +18,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_TDBIO_H
-#define GPG_TDBIO_H
+#ifndef G10_TDBIO_H
+#define G10_TDBIO_H
#include "host2net.h"
@@ -35,41 +35,13 @@
#define RECTYPE_VER 1
-#define RECTYPE_DIR 2
-#define RECTYPE_KEY 3
-#define RECTYPE_UID 4
-#define RECTYPE_PREF 5
-#define RECTYPE_SIG 6
-#define RECTYPE_SDIR 8
-#define RECTYPE_CACH 9
#define RECTYPE_HTBL 10
#define RECTYPE_HLST 11
+#define RECTYPE_TRUST 12
+#define RECTYPE_VALID 13
#define RECTYPE_FREE 254
-#define DIRF_CHECKED 1 /* has been checked - bits 1,2,3 are valid */
-#define DIRF_VALID 2 /* This key is valid: There is at least */
- /* one uid with a selfsignature or an revocation */
-#define DIRF_EXPIRED 4 /* the complete key has expired */
-#define DIRF_REVOKED 8 /* the complete key has been revoked */
-#define DIRF_NEWKEYS 128 /* new keys are available: we can check the sigs */
-
-#define KEYF_CHECKED 1 /* This key has been checked */
-#define KEYF_VALID 2 /* This is a valid (sub)key */
-#define KEYF_EXPIRED 4 /* this key is expired */
-#define KEYF_REVOKED 8 /* this key has been revoked */
-
-#define UIDF_CHECKED 1 /* user id has been checked - other bits are valid */
-#define UIDF_VALID 2 /* this is a valid user id */
-#define UIDF_REVOKED 8 /* this user id has been revoked */
-
-#define SIGF_CHECKED 1 /* signature has been checked - bits 0..6 are valid */
-#define SIGF_VALID 2 /* the signature is valid */
-#define SIGF_EXPIRED 4 /* the key of this signature has expired */
-#define SIGF_REVOKED 8 /* this signature has been revoked */
-#define SIGF_IGNORED 64 /* this signature is ignored by the system */
-#define SIGF_NOPUBKEY 128 /* there is no pubkey for this sig */
-
struct trust_record {
int rectype;
int mark;
@@ -78,73 +50,21 @@ struct trust_record {
ulong recnum;
union {
struct { /* version record: */
- byte version; /* should be 2 */
+ byte version; /* should be 3 */
byte marginals;
byte completes;
byte cert_depth;
ulong created; /* timestamp of trustdb creation */
- ulong mod_down; /* timestamp of last modification downward */
- ulong mod_up; /* timestamp of last modification upward */
- ulong keyhashtbl;
+ ulong nextcheck; /* timestamp of next scheduled check */
+ ulong reserved;
+ ulong reserved2;
ulong firstfree;
- ulong sdirhashtbl;
+ ulong reserved3;
+ ulong trusthashtbl;
} ver;
struct { /* free record */
ulong next;
} free;
- struct { /* directory record */
- ulong lid;
- ulong keylist; /* List of keys (the first is the primary key)*/
- ulong uidlist; /* list of uid records */
- ulong cacherec; /* the cache record */
- byte ownertrust;
- byte dirflags;
- byte validity; /* calculated trustlevel over all uids */
- ulong valcheck; /* timestamp of last validation check */
- ulong checkat; /* Check key when this time has been reached*/
- } dir;
- struct { /* primary public key record */
- ulong lid;
- ulong next; /* next key */
- byte keyflags;
- byte pubkey_algo;
- byte fingerprint_len;
- byte fingerprint[20];
- } key;
- struct { /* user id reord */
- ulong lid; /* point back to the directory record */
- ulong next; /* points to next user id record */
- ulong prefrec; /* recno of preference record */
- ulong siglist; /* list of valid signatures (w/o self-sig)*/
- byte uidflags;
- byte validity; /* calculated trustlevel of this uid */
- byte namehash[20]; /* ripemd hash of the username */
- } uid;
- struct { /* preference record */
- ulong lid; /* point back to the directory record */
- /* or 0 for a global pref record */
- ulong next; /* points to next pref record */
- byte data[ITEMS_PER_PREF_RECORD];
- } pref;
- struct { /* signature record */
- ulong lid;
- ulong next; /* recnno of next record or NULL for last one */
- struct {
- ulong lid; /* of pubkey record of signator (0=unused) */
- byte flag; /* SIGF_xxxxx */
- } sig[SIGS_PER_RECORD];
- } sig;
- struct {
- ulong lid;
- u32 keyid[2];
- byte pubkey_algo;
- u32 hintlist;
- } sdir;
- struct { /* cache record */
- ulong lid;
- byte blockhash[20];
- byte trustlevel; /* calculated trustlevel */
- } cache;
struct {
ulong item[ITEMS_PER_HTBL_RECORD];
} htbl;
@@ -152,25 +72,21 @@ struct trust_record {
ulong next;
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of another record */
} hlst;
+ struct {
+ byte fingerprint[20];
+ byte ownertrust;
+ byte depth;
+ ulong validlist;
+ } trust;
+ struct {
+ byte namehash[20];
+ ulong next;
+ byte validity;
+ } valid;
} r;
};
typedef struct trust_record TRUSTREC;
-typedef struct {
- ulong lid; /* localid */
- ulong sigrec;
- ulong sig_lid; /* returned signatures LID */
- unsigned sig_flag; /* returned signature record flag */
- struct { /* internal data */
- int init_done;
- int eof;
- TRUSTREC rec;
- ulong nextuid;
- int index;
- } ctl;
-} SIGREC_CONTEXT;
-
-
/*-- tdbio.c --*/
int tdbio_set_dbname( const char *new_dbname, int create );
const char *tdbio_get_dbname(void);
@@ -178,8 +94,8 @@ void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
int tdbio_write_record( TRUSTREC *rec );
int tdbio_db_matches_options(void);
-ulong tdbio_read_modify_stamp( int modify_down );
-void tdbio_write_modify_stamp( int up, int down );
+ulong tdbio_read_nextcheck (void);
+int tdbio_write_nextcheck (ulong stamp);
int tdbio_is_dirty(void);
int tdbio_sync(void);
int tdbio_begin_transaction(void);
@@ -187,12 +103,9 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record( ulong recnum );
ulong tdbio_new_recnum(void);
-int tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec );
-int tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
- int pubkey_algo, TRUSTREC *rec );
-int tdbio_search_dir( u32 *keyid, int pubkey_algo, TRUSTREC *rec );
-int tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec );
+int tdbio_search_trust_byfpr(const byte *fingerprint, TRUSTREC *rec );
+int tdbio_search_trust_bypk(PKT_public_key *pk, TRUSTREC *rec );
void tdbio_invalid(void);
-#endif /*GPG_TDBIO_H*/
+#endif /*G10_TDBIO_H*/
diff --git a/g10/textfilter.c b/g10/textfilter.c
index a360ffccb..ded030d79 100644
--- a/g10/textfilter.c
+++ b/g10/textfilter.c
@@ -1,5 +1,5 @@
/* textfilter.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -25,9 +25,9 @@
#include <errno.h>
#include <assert.h>
-#include <gcrypt.h>
#include "errors.h"
#include "iobuf.h"
+#include "memory.h"
#include "util.h"
#include "filter.h"
#include "i18n.h"
@@ -133,7 +133,7 @@ text_filter( void *opaque, int control,
if( tfx->truncated )
log_error(_("can't handle text lines longer than %d characters\n"),
MAX_LINELEN );
- gcry_free( tfx->buffer );
+ m_free( tfx->buffer );
tfx->buffer = NULL;
}
else if( control == IOBUFCTRL_DESC )
@@ -147,7 +147,7 @@ text_filter( void *opaque, int control,
* md is updated as required by rfc2440
*/
int
-copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md,
+copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
int escape_dash, int escape_from, int pgp2mode )
{
unsigned maxlen;
@@ -175,15 +175,15 @@ copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md,
/* update the message digest */
if( escape_dash ) {
if( pending_lf ) {
- gcry_md_putc( md, '\r' );
- gcry_md_putc( md, '\n' );
+ md_putc( md, '\r' );
+ md_putc( md, '\n' );
}
- gcry_md_write( md, buffer,
+ md_write( md, buffer,
len_without_trailing_chars( buffer, n,
pgp2mode? " \r\n":" \t\r\n"));
}
else
- gcry_md_write( md, buffer, n );
+ md_write( md, buffer, n );
pending_lf = buffer[n-1] == '\n';
/* write the output */
@@ -224,7 +224,7 @@ copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md,
if( !pending_lf ) { /* make sure that the file ends with a LF */
iobuf_writestr( out, LF );
if( !escape_dash )
- gcry_md_putc( md, '\n' );
+ md_putc( md, '\n' );
}
if( truncated )
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 1fd2383c0..85b7dbcb9 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1,5 +1,5 @@
/* trustdb.c
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -22,599 +22,353 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <ctype.h>
#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
-#include <gcrypt.h>
+#include "memory.h"
#include "util.h"
-#include "trustdb.h"
#include "options.h"
#include "packet.h"
#include "main.h"
#include "i18n.h"
#include "tdbio.h"
-#include "ttyio.h"
-
-#if MAX_FINGERPRINT_LEN > 20
- #error Must change structure of trustdb
-#endif
-
-struct keyid_list {
- struct keyid_list *next;
- u32 keyid[2];
-};
+#include "trustdb.h"
-struct local_id_item {
- struct local_id_item *next;
- ulong lid;
- unsigned flag;
-};
-struct local_id_table {
- struct local_id_table *next; /* only used to keep a list of unused tables */
- struct local_id_item *items[16];
+/*
+ * A structure to store key identification as well as some stuff needed
+ * for validation
+ */
+struct key_item {
+ struct key_item *next;
+ unsigned int ownertrust;
+ u32 kid[2];
};
-typedef struct local_id_table *LOCAL_ID_TABLE;
-
-
-struct enum_cert_paths_ctx {
- int init;
- int idx;
-};
-
+typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
-struct recno_list_struct {
- struct recno_list_struct *next;
- ulong recno;
- int type;
-};
-typedef struct recno_list_struct *RECNO_LIST;
-
-
-
-typedef struct trust_node *TN;
-struct trust_node {
- TN back; /* parent */
- TN list; /* list of other node (should all be of the same type)*/
- TN next; /* used to build the list */
- int is_uid; /* set if this is an uid node */
- ulong lid; /* key or uid recordnumber */
- union {
- struct {
- int ownertrust;
- int validity;
- /* helper */
- int buckstop;
- } k;
- struct {
- int marginal_count;
- int fully_count;
- int validity;
- } u;
- } n;
+/*
+ * Structure to keep track of keys, this is used as an array wherre
+ * the item right after the last one has a keyblock set to NULL.
+ * Maybe we can drop this thing and replace it by key_item
+ */
+struct key_array {
+ KBNODE keyblock;
};
-static TN used_tns;
-static int alloced_tns;
-static int max_alloced_tns;
-
-static struct keyid_list *trusted_key_list;
-
-static LOCAL_ID_TABLE new_lid_table(void);
-static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
-static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
-
-
-static int propagate_validity( TN root, TN node,
- int (*add_fnc)(ulong), unsigned *retflgs );
-
-static void print_user_id( FILE *fp, const char *text, u32 *keyid );
-static int do_check( TRUSTREC *drec, unsigned *trustlevel,
- const char *nhash, int (*add_fnc)(ulong),
- unsigned *retflgs);
-static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
-static int do_update_trust_record( KBNODE keyblock, TRUSTREC *drec,
- int sigs_only, int *modified );
-static int check_trust_record( TRUSTREC *drec, int sigs_only );
-static void mark_fresh_keys(void);
-
-/* a table used to keep track of ultimately trusted keys
- * which are the ones from our secrings and the trusted keys */
-static LOCAL_ID_TABLE ultikey_table;
-
-
-/* a table to keep track of newly importted keys. This one is
- * create by the insert_trust_record function and from time to time
- * used to verify key signature which have been done with these new keys */
-static LOCAL_ID_TABLE fresh_imported_keys;
-static int fresh_imported_keys_count;
-#define FRESH_KEY_CHECK_THRESHOLD 200
-
-/* list of unused lid items and tables */
-static LOCAL_ID_TABLE unused_lid_tables;
-static struct local_id_item *unused_lid_items;
-
+/* control information for the trust DB */
static struct {
int init;
int level;
char *dbname;
} trustdb_args;
-
-/**********************************************
- *********** record read write **************
- **********************************************/
-
-
-/****************
- * Read a record but die if it does not exist
- */
-static void
-read_record( ulong recno, TRUSTREC *rec, int rectype )
-{
- int rc = tdbio_read_record( recno, rec, rectype );
- if( !rc )
- return;
- log_error(_("trust record %lu, req type %d: read failed: %s\n"),
- recno, rectype, gpg_errstr(rc) );
- tdbio_invalid();
-}
+/* some globals */
+static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */
+static struct key_item *utk_list; /* all ultimately trusted keys */
+static int pending_check_trustdb;
-/****************
- * Wirte a record but die on error
- */
-static void
-write_record( TRUSTREC *rec )
-{
- int rc = tdbio_write_record( rec );
- if( !rc )
- return;
- log_error(_("trust record %lu, type %d: write failed: %s\n"),
- rec->recnum, rec->rectype, gpg_errstr(rc) );
- tdbio_invalid();
-}
-
-/****************
- * Delete a record but die on error
- */
-static void
-delete_record( ulong recno )
-{
- int rc = tdbio_delete_record( recno );
- if( !rc )
- return;
- log_error(_("trust record %lu: delete failed: %s\n"),
- recno, gpg_errstr(rc) );
- tdbio_invalid();
-}
-
-/****************
- * sync the db
- */
-static void
-do_sync(void)
-{
- int rc = tdbio_sync();
- if( !rc )
- return;
- log_error(_("trustdb: sync failed: %s\n"), gpg_errstr(rc) );
- gpg_exit(2);
-}
-
+static int validate_keys (int interactive);
/**********************************************
- ***************** helpers ******************
+ ************* some helpers *******************
**********************************************/
-
-static LOCAL_ID_TABLE
-new_lid_table(void)
+static struct key_item *
+new_key_item (void)
{
- LOCAL_ID_TABLE a;
-
- a = unused_lid_tables;
- if( a ) {
- unused_lid_tables = a->next;
- memset( a, 0, sizeof *a );
- }
- else
- a = gcry_xcalloc( 1, sizeof *a );
- return a;
+ struct key_item *k;
+
+ k = m_alloc_clear (sizeof *k);
+ return k;
}
-#if 0
static void
-release_lid_table( LOCAL_ID_TABLE tbl )
+release_key_items (struct key_item *k)
{
- struct local_id_item *a, *a2;
- int i;
-
- for(i=0; i < 16; i++ ) {
- for(a=tbl->items[i]; a; a = a2 ) {
- a2 = a->next;
- a->next = unused_lid_items;
- unused_lid_items = a;
- }
- }
- tbl->next = unused_lid_tables;
- unused_lid_tables = tbl;
-}
-#endif
-
+ struct key_item *k2;
-/****************
- * Remove all items from a LID table
- */
-static void
-clear_lid_table( LOCAL_ID_TABLE tbl )
-{
- struct local_id_item *a, *a2;
- int i;
-
- for(i=0; i < 16; i++ ) {
- for(a=tbl->items[i]; a; a = a2 ) {
- a2 = a->next;
- a->next = unused_lid_items;
- unused_lid_items = a;
- }
- tbl->items[i] = NULL;
+ for (; k; k = k2)
+ {
+ k2 = k->next;
+ m_free (k);
}
}
-
-/****************
- * Add a new item to the table or return 1 if we already have this item
+/*
+ * For fast keylook up we need a hash table. Each byte of a KeyIDs
+ * should be distributed equally over the 256 possible values (except
+ * for v3 keyIDs but we consider them as not important here). So we
+ * can just use 10 bits to index a table of 1024 key items.
+ * Possible optimization: Don not use key_items but other hash_table when the
+ * duplicates lists gets too large.
*/
-static int
-ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
+static KeyHashTable
+new_key_hash_table (void)
{
- struct local_id_item *a;
-
- for( a = tbl->items[lid & 0x0f]; a; a = a->next )
- if( a->lid == lid )
- return 1;
- a = unused_lid_items;
- if( a )
- unused_lid_items = a->next;
- else
- a = gcry_xmalloc( sizeof *a );
- a->lid = lid;
- a->flag = flag;
- a->next = tbl->items[lid & 0x0f];
- tbl->items[lid & 0x0f] = a;
- return 0;
+ struct key_item **tbl;
+
+ tbl = m_alloc_clear (1024 * sizeof *tbl);
+ return tbl;
}
-static int
-qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
+static void
+release_key_hash_table (KeyHashTable tbl)
{
- struct local_id_item *a;
+ int i;
- for( a = tbl->items[lid & 0x0f]; a; a = a->next )
- if( a->lid == lid ) {
- if( flag )
- *flag = a->flag;
- return 0;
- }
- return -1;
+ if (!tbl)
+ return;
+ for (i=0; i < 1024; i++)
+ release_key_items (tbl[i]);
+ m_free (tbl);
}
-
-static TN
-new_tn(void)
+/*
+ * Returns: True if the keyID is in the given hash table
+ */
+static int
+test_key_hash_table (KeyHashTable tbl, u32 *kid)
{
- TN t;
+ struct key_item *k;
- if( used_tns ) {
- t = used_tns;
- used_tns = t->next;
- memset( t, 0, sizeof *t );
- }
- else
- t = gcry_xcalloc( 1, sizeof *t );
- if( ++alloced_tns > max_alloced_tns )
- max_alloced_tns = alloced_tns;
- return t;
+ for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ return 1;
+ return 0;
}
-
+/*
+ * Add a new key to the hash table. The key is identified by its key ID.
+ */
static void
-release_tn( TN t )
+add_key_hash_table (KeyHashTable tbl, u32 *kid)
{
- if( t ) {
- t->next = used_tns;
- used_tns = t;
- alloced_tns--;
- }
-}
+ struct key_item *k, *kk;
+ for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ return; /* already in table */
+
+ kk = new_key_item ();
+ kk->kid[0] = kid[0];
+ kk->kid[1] = kid[1];
+ kk->next = tbl[(kid[1] & 0x03ff)];
+ tbl[(kid[1] & 0x03ff)] = kk;
+}
+/*
+ * Release a key_array
+ */
static void
-release_tn_tree( TN kr )
+release_key_array ( struct key_array *keys )
{
- TN kr2;
+ struct key_array *k;
- for( ; kr; kr = kr2 ) {
- release_tn_tree( kr->list );
- kr2 = kr->next;
- release_tn( kr );
+ if (keys) {
+ for (k=keys; k->keyblock; k++)
+ release_kbnode (k->keyblock);
+ m_free (keys);
}
}
+
+/*********************************************
+ ********** Initialization *****************
+ *********************************************/
-
-/**********************************************
- ****** access by LID and other helpers *******
- **********************************************/
-/****************
- * Return the keyid from the primary key identified by LID.
+/*
+ * Used to register extra ultimately trusted keys - this has to be done
+ * before initializing the validation module.
+ * FIXME: Should be replaced by a function to add those keys to the trustdb.
*/
-int
-keyid_from_lid( ulong lid, u32 *keyid )
+void
+register_trusted_key( const char *string )
{
- TRUSTREC rec;
- int rc;
-
- init_trustdb();
- keyid[0] = keyid[1] = 0;
- rc = tdbio_read_record( lid, &rec, 0 );
- if( rc ) {
- log_error(_("error reading dir record for LID %lu: %s\n"),
- lid, gpg_errstr(rc));
- return GPGERR_TRUSTDB;
- }
- if( rec.rectype == RECTYPE_SDIR )
- return 0;
- if( rec.rectype != RECTYPE_DIR ) {
- log_error(_("lid %lu: expected dir record, got type %d\n"),
- lid, rec.rectype );
- return GPGERR_TRUSTDB;
- }
- if( !rec.r.dir.keylist ) {
- log_error(_("no primary key for LID %lu\n"), lid );
- return GPGERR_TRUSTDB;
- }
- rc = tdbio_read_record( rec.r.dir.keylist, &rec, RECTYPE_KEY );
- if( rc ) {
- log_error(_("error reading primary key for LID %lu: %s\n"),
- lid, gpg_errstr(rc));
- return GPGERR_TRUSTDB;
- }
- keyid_from_fingerprint( rec.r.key.fingerprint, rec.r.key.fingerprint_len,
- keyid );
-
- return 0;
-}
+ KEYDB_SEARCH_DESC desc;
+ struct key_item *k;
+ if (classify_user_id (string, &desc) != KEYDB_SEARCH_MODE_LONG_KID ) {
+ log_error(_("`%s' is not a valid long keyID\n"), string );
+ return;
+ }
-ulong
-lid_from_keyblock( KBNODE keyblock )
-{
- KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- PKT_public_key *pk;
- if( !node )
- BUG();
- pk = node->pkt->pkt.public_key;
- if( !pk->local_id ) {
- TRUSTREC rec;
- init_trustdb();
-
- get_dir_record( pk, &rec );
- }
- return pk->local_id;
+ k = new_key_item ();
+ k->kid[0] = desc.u.kid[0];
+ k->kid[1] = desc.u.kid[1];
+ k->next = user_utk_list;
+ user_utk_list = k;
}
-
+/*
+ * Helper to add a key to the global list of ultimately trusted keys.
+ * Retruns: true = inserted, false = already in in list.
+ */
static int
-get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
+add_utk (u32 *kid)
{
- int rc=0;
+ struct key_item *k;
- if( pk->local_id ) {
- read_record( pk->local_id, rec, RECTYPE_DIR );
- }
- else { /* no local_id: scan the trustdb */
- if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
- log_error(_("get_dir_record: search_record failed: %s\n"),
- gpg_errstr(rc));
+ for (k = utk_list; k; k = k->next)
+ {
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ {
+ return 0;
+ }
}
- return rc;
-}
-static ulong
-lid_from_keyid_no_sdir( u32 *keyid )
-{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- TRUSTREC rec;
- ulong lid = 0;
- int rc;
-
- rc = get_pubkey( pk, keyid );
- if( !rc ) {
- if( pk->local_id )
- lid = pk->local_id;
- else {
- rc = tdbio_search_dir_bypk( pk, &rec );
- if( !rc )
- lid = rec.recnum;
- }
- }
- free_public_key( pk );
- return lid;
+ k = new_key_item ();
+ k->kid[0] = kid[0];
+ k->kid[1] = kid[1];
+ k->ownertrust = TRUST_ULTIMATE;
+ k->next = utk_list;
+ utk_list = k;
+ if( opt.verbose > 1 )
+ log_info(_("key %08lX: accepted as trusted key\n"), (ulong)kid[1]);
+ return 1;
}
-
-/***********************************************
- ************* Initialization ****************
- ***********************************************/
-
-void
-register_trusted_key( const char *string )
+/****************
+ * Verify that all our secret keys are usable and put them into the utk_list.
+ */
+static void
+verify_own_keys(void)
{
- u32 keyid[2];
- struct keyid_list *r;
+ TRUSTREC rec;
+ ulong recnum;
+ int rc;
+ struct key_item *k;
+ int hint_shown = 0;
+
+ if (utk_list)
+ return;
- if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
- log_error(_("'%s' is not a valid long keyID\n"), string );
- return;
+ /* scan the trustdb to find all ultimately trusted keys */
+ for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ )
+ {
+ if ( rec.rectype == RECTYPE_TRUST
+ && (rec.r.trust.ownertrust & TRUST_MASK) == TRUST_ULTIMATE)
+ {
+ byte *fpr = rec.r.trust.fingerprint;
+ int fprlen;
+ u32 kid[2];
+
+ /* Problem: We do only use fingerprints in the trustdb but
+ * we need the keyID here to indetify the key; we can only
+ * use that ugly hack to distinguish between 16 and 20
+ * butes fpr - it does not work always so we better change
+ * the whole validation code to only work with
+ * fingerprints */
+ fprlen = (!fpr[16] && !fpr[17] && !fpr[18] && !fpr[19])? 16:20;
+ keyid_from_fingerprint (fpr, fprlen, kid);
+ if (!add_utk (kid))
+ log_info(_("key %08lX occurs more than once in the trustdb\n"),
+ (ulong)kid[1]);
+ }
+ }
+
+ /* the --trusted-key option is again deprecated; however we automagically
+ * add those keys to the trustdb */
+ for (k = user_utk_list; k; k = k->next)
+ {
+ if ( add_utk (k->kid) )
+ { /* not yet in trustDB as ultimately trusted */
+ PKT_public_key pk;
+
+ memset (&pk, 0, sizeof pk);
+ rc = get_pubkey (&pk, k->kid);
+ if (rc) {
+ log_info(_("key %08lX: no public key for trusted key - skipped\n"),
+ (ulong)k->kid[1] );
+ }
+ else {
+ update_ownertrust (&pk,
+ ((get_ownertrust (&pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE ));
+ release_public_key_parts (&pk);
+ }
+ if (!hint_shown)
+ {
+ log_info ("the --trusted-key option is now obsolete; "
+ "use the --edit command instead.\n");
+ log_info ("given keys will be marked as trusted\n");
+ hint_shown = 1;
+ }
+ log_info ("key %08lX marked as ultimately trusted\n",
+ (ulong)k->kid[1]);
+ }
}
- for( r = trusted_key_list; r; r = r->next )
- if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
- return;
- r = gcry_xmalloc( sizeof *r );
- r->keyid[0] = keyid[0];
- r->keyid[1] = keyid[1];
- r->next = trusted_key_list;
- trusted_key_list = r;
-}
+ /* release the helper table table */
+ release_key_items (user_utk_list);
+ user_utk_list = NULL;
+ return;
+}
+
+/*********************************************
+ *********** TrustDB stuff *******************
+ *********************************************/
+/*
+ * Read a record but die if it does not exist
+ */
static void
-add_ultimate_key( PKT_public_key *pk, u32 *keyid )
+read_record (ulong recno, TRUSTREC *rec, int rectype )
{
- int rc;
-
- /* first make sure that the pubkey is in the trustdb */
- rc = query_trust_record( pk );
- if( rc == -1 && opt.dry_run )
- return;
- if( rc == -1 ) { /* put it into the trustdb */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error(_("key %08lX: can't put it into the trustdb\n"),
- (ulong)keyid[1] );
- return;
- }
+ int rc = tdbio_read_record (recno, rec, rectype);
+ if (rc)
+ {
+ log_error(_("trust record %lu, req type %d: read failed: %s\n"),
+ recno, rec->rectype, g10_errstr(rc) );
+ tdbio_invalid();
}
- else if( rc ) {
- log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
- return;
+ if (rectype != rec->rectype)
+ {
+ log_error(_("trust record %lu is not of requested type %d\n"),
+ rec->recnum, rectype);
+ tdbio_invalid();
}
-
- if( DBG_TRUST )
- log_debug("key %08lX.%lu: stored into ultikey_table\n",
- (ulong)keyid[1], pk->local_id );
-
- if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
- log_error(_("key %08lX: already in trusted key table\n"),
- (ulong)keyid[1]);
- else if( opt.verbose > 1 )
- log_info(_("key %08lX: accepted as trusted key.\n"),
- (ulong)keyid[1]);
-
}
-/****************
- * Verify that all our public keys are in the trustdb.
+/*
+ * Write a record and die on error
*/
-static int
-verify_own_keys(void)
+static void
+write_record (TRUSTREC *rec)
{
- int rc;
- void *enum_context = NULL;
- PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk );
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
- u32 keyid[2];
- struct keyid_list *kl;
-
-
- /* put the trusted keys into the ultikey table */
- for( kl = trusted_key_list; kl; kl = kl->next ) {
- keyid[0] = kl->keyid[0];
- keyid[1] = kl->keyid[1];
- /* get the public key */
- memset( pk, 0, sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_info(_("key %08lX: no public key for trusted key - skipped\n"),
- (ulong)keyid[1] );
- }
- else {
- add_ultimate_key( pk, keyid );
- release_public_key_parts( pk );
- }
+ int rc = tdbio_write_record (rec);
+ if (rc)
+ {
+ log_error(_("trust record %lu, type %d: write failed: %s\n"),
+ rec->recnum, rec->rectype, g10_errstr(rc) );
+ tdbio_invalid();
}
-
- /* And now add all secret keys to the ultikey table */
- while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
- int have_pk = 0;
-
- keyid_from_sk( sk, keyid );
-
- if( DBG_TRUST )
- log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] );
-
- if( !opt.quiet && is_secret_key_protected( sk ) < 1 )
- log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
- (ulong)keyid[1] );
-
- for( kl = trusted_key_list; kl; kl = kl->next ) {
- if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
- goto skip; /* already in trusted key table */
- }
-
- /* see whether we can access the public key of this secret key */
- memset( pk, 0, sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_info(_("key %08lX: secret key without public key - skipped\n"),
- (ulong)keyid[1] );
- goto skip;
- }
- have_pk=1;
-
- if( cmp_public_secret_key( pk, sk ) ) {
- log_info(_("key %08lX: secret and public key don't match\n"),
- (ulong)keyid[1] );
- goto skip;
- }
-
- add_ultimate_key( pk, keyid );
-
- skip:
- release_secret_key_parts( sk );
- if( have_pk )
- release_public_key_parts( pk );
- }
- if( rc != -1 )
- log_error(_("enumerate secret keys failed: %s\n"), gpg_errstr(rc) );
- else
- rc = 0;
-
- /* release the trusted keyid table */
- { struct keyid_list *kl2;
- for( kl = trusted_key_list; kl; kl = kl2 ) {
- kl2 = kl->next;
- gcry_free( kl );
- }
- trusted_key_list = NULL;
- }
-
- enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
- free_secret_key( sk );
- free_public_key( pk );
- return rc;
}
-
+/*
+ * sync the TrustDb and die on error
+ */
+static void
+do_sync(void)
+{
+ int rc = tdbio_sync ();
+ if(rc)
+ {
+ log_error (_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
+ g10_exit(2);
+ }
+}
/****************
@@ -629,2198 +383,1268 @@ setup_trustdb( int level, const char *dbname )
if( trustdb_args.init )
return 0;
trustdb_args.level = level;
- trustdb_args.dbname = dbname? gcry_xstrdup(dbname): NULL;
+ trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
return 0;
}
void
init_trustdb()
{
- int rc=0;
- int level = trustdb_args.level;
- const char* dbname = trustdb_args.dbname;
-
- if( trustdb_args.init )
- return;
+ int rc=0;
+ int level = trustdb_args.level;
+ const char* dbname = trustdb_args.dbname;
- trustdb_args.init = 1;
-
- if( !ultikey_table )
- ultikey_table = new_lid_table();
-
- if( !level || level==1 ) {
- rc = tdbio_set_dbname( dbname, !!level );
- if( !rc ) {
- if( !level )
- return;
+ if( trustdb_args.init )
+ return;
- /* verify that our own keys are in the trustDB
- * or move them to the trustdb. */
- rc = verify_own_keys();
+ trustdb_args.init = 1;
- /* should we check whether there is no other ultimately trusted
- * key in the database? */
- }
+ if ( !level || level==1)
+ {
+ rc = tdbio_set_dbname( dbname, !!level );
+ if( !rc )
+ {
+ if( !level )
+ return;
+
+ /* verify that our own keys are in the trustDB
+ * or move them to the trustdb. */
+ verify_own_keys();
+
+ /* should we check whether there is no other ultimately trusted
+ * key in the database? */
+ }
}
- else
- BUG();
- if( rc )
- log_fatal("can't init trustdb: %s\n", gpg_errstr(rc) );
+ else
+ BUG();
+ if( rc )
+ log_fatal("can't init trustdb: %s\n", g10_errstr(rc) );
}
-/****************
- * This function should be called in certain cases to sync the internal state
- * of the trustdb with the file image. Currently it is needed after
- * a sequence of insert_trust_record() calls.
- */
-void
-sync_trustdb()
-{
- if( fresh_imported_keys && fresh_imported_keys_count )
- mark_fresh_keys();
-}
-
-
/***********************************************
************* Print helpers ****************
***********************************************/
-static void
-print_user_id( FILE *fp, const char *text, u32 *keyid )
-{
- char *p;
- size_t n;
-
- p = get_user_id( keyid, &n );
- if( fp ) {
- fprintf( fp, "%s \"", text );
- print_utf8_string( fp, p, n );
- putc('\"', fp);
- putc('\n', fp);
- }
- else {
- tty_printf( "%s \"", text );
- tty_print_utf8_string( p, n );
- tty_printf( "\"\n" );
- }
- gcry_free(p);
-}
-
-
/****************
* This function returns a letter for a trustvalue Trust flags
* are ignore.
*/
int
-trust_letter( unsigned value )
+trust_letter (unsigned int value)
{
- switch( (value & TRUST_MASK) ) {
- case TRUST_UNKNOWN: return '-';
- case TRUST_EXPIRED: return 'e';
- case TRUST_UNDEFINED: return 'q';
- case TRUST_NEVER: return 'n';
- case TRUST_MARGINAL: return 'm';
- case TRUST_FULLY: return 'f';
- case TRUST_ULTIMATE: return 'u';
- default: return 0 ;
+ switch( (value & TRUST_MASK) )
+ {
+ case TRUST_UNKNOWN: return '-';
+ case TRUST_EXPIRED: return 'e';
+ case TRUST_UNDEFINED: return 'q';
+ case TRUST_NEVER: return 'n';
+ case TRUST_MARGINAL: return 'm';
+ case TRUST_FULLY: return 'f';
+ case TRUST_ULTIMATE: return 'u';
+ default: return 0;
}
}
-#if 0
-static void
-print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
-{
- int rc, c, i;
- u32 keyid[2];
- char *p;
- size_t n;
-
- for( i = 0; i < pathlen; i++ ) {
- if( highlight )
- fputs(highlight == path[i].lid? "* ":" ", fp );
- rc = keyid_from_lid( path[i].lid, keyid );
- if( rc )
- fprintf(fp, "????????.%lu:", path[i].lid );
- else
- fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
- c = trust_letter(path[i].otrust);
- if( c )
- putc( c, fp );
- else
- fprintf( fp, "%02x", path[i].otrust );
- putc('/', fp);
- c = trust_letter(path[i].trust);
- if( c )
- putc( c, fp );
- else
- fprintf( fp, "%02x", path[i].trust );
- putc(' ', fp);
- p = get_user_id( keyid, &n );
- putc(' ', fp);
- putc('\"', fp);
- print_utf8_string( fp, p, n > 40? 40:n );
- putc('\"', fp);
- gcry_free(p);
- putc('\n', fp );
- }
-}
-#endif
-
-
-static void
-print_default_uid( FILE *fp, ulong lid )
-{
- u32 keyid[2];
-
- if( !keyid_from_lid( lid, keyid ) )
- print_user_id( fp, "", keyid );
-}
-
+/****************
+ * Recreate the WoT but do not ask for new ownertrusts. Special
+ * feature: In batch mode and without a forced yes, this is only done
+ * when a check is due. This can be used to run the check from a crontab
+ */
+void
+check_trustdb ()
+{
+ init_trustdb();
+ if (opt.batch && !opt.answer_yes)
+ {
+ ulong scheduled;
+
+ scheduled = tdbio_read_nextcheck ();
+ if (!scheduled)
+ {
+ log_info (_("no need for a trustdb check\n"));
+ return;
+ }
-static void
-print_uid_from_keyblock( FILE *fp, KBNODE keyblock, ulong urecno )
-{
- TRUSTREC urec;
- KBNODE node;
- byte uhash[20];
-
- read_record( urecno, &urec, RECTYPE_UID );
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID ) {
- PKT_user_id *uidpkt = node->pkt->pkt.user_id;
-
- if( uidpkt->photo ) {
- gcry_md_hash_buffer( GCRY_MD_RMD160, uhash,
- uidpkt->photo, uidpkt->photolen );
- }
- else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, uhash,
- uidpkt->name, uidpkt->len );
- }
- if( !memcmp( uhash, urec.r.uid.namehash, 20 ) ) {
- print_string( fp, uidpkt->name, uidpkt->len, ':' );
- return;
- }
- }
+ if (scheduled > make_timestamp ())
+ {
+ log_info (_("next trustdb check due at %s\n"),
+ strtimestamp (scheduled));
+ return;
+ }
}
- fputs("[?]", fp );
+ validate_keys (0);
}
-
-static void
-dump_tn_tree( FILE *fp, int level, TN tree )
+/*
+ * Recreate the WoT.
+ */
+void
+update_trustdb()
{
- TN kr, ur;
-
- for( kr=tree; kr; kr = kr->next ) {
- if( fp ) {
- fprintf( fp, "%*s", level*4, "" );
- fprintf( fp, "K%lu(ot=%d,val=%d) ", kr->lid,
- kr->n.k.ownertrust,
- kr->n.k.validity );
- }
- else {
- tty_printf("%*s", level*4, "" );
- tty_printf("K%lu(ot=%d,val=%d) ", kr->lid,
- kr->n.k.ownertrust,
- kr->n.k.validity );
- }
- print_default_uid( fp, kr->lid );
- for( ur=kr->list; ur; ur = ur->next ) {
- if( fp ) {
- fprintf(fp, "%*s ", level*4, "" );
- fprintf(fp, "U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
- ur->n.u.marginal_count,
- ur->n.u.fully_count,
- ur->n.u.validity
- );
- }
- else {
- tty_printf("%*s ", level*4, "" );
- tty_printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
- ur->n.u.marginal_count,
- ur->n.u.fully_count,
- ur->n.u.validity
- );
- }
- dump_tn_tree( fp, level+1, ur->list );
- }
- }
+ init_trustdb();
+ validate_keys (1);
}
-/****************
- * Special version of dump_tn_tree, which prints it colon delimited.
- * Format:
- * level:keyid:type:recno:ot:val:mc:cc:name:
- * With TYPE = U for a user ID
- * K for a key
- * The RECNO is either the one of the dir record or the one of the uid record.
- * OT is the the usual trust letter and only availabel on K lines.
- * VAL is the calcualted validity
- * MC is the marginal trust counter and only available on U lines
- * CC is the same for the complete count
- * NAME ist the username and only printed on U lines
- */
-static void
-dump_tn_tree_with_colons( int level, TN tree )
+void
+revalidation_mark (void)
{
- TN kr, ur;
-
- for( kr=tree; kr; kr = kr->next ) {
- KBNODE kb = NULL;
- u32 kid[2];
-
- keyid_from_lid( kr->lid, kid );
- get_keyblock_bylid( &kb, kr->lid );
-
- printf( "%d:%08lX%08lX:K:%lu:%c:%c::::\n",
- level, (ulong)kid[0], (ulong)kid[1], kr->lid,
- trust_letter( kr->n.k.ownertrust ),
- trust_letter( kr->n.k.validity ) );
- for( ur=kr->list; ur; ur = ur->next ) {
- printf( "%d:%08lX%08lX:U:%lu::%c:%d:%d:",
- level, (ulong)kid[0], (ulong)kid[1], ur->lid,
- trust_letter( kr->n.u.validity ),
- ur->n.u.marginal_count,
- ur->n.u.fully_count );
- print_uid_from_keyblock( stdout, kb, ur->lid );
- putchar(':');
- putchar('\n');
- dump_tn_tree_with_colons( level+1, ur->list );
- }
- release_kbnode( kb );
- }
+ init_trustdb();
+ /* we simply set the time for the next check to 1 (far back in 1970)
+ * so that a --update-trustdb will be scheduled */
+ if (tdbio_write_nextcheck (1))
+ do_sync ();
+ pending_check_trustdb = 1;
}
-
/***********************************************
- ************* trustdb maintenance ***********
+ *********** Ownertrust et al. ****************
***********************************************/
-/****************
- * Create or update shadow dir record and return the LID of the record
- */
-static ulong
-create_shadow_dir( PKT_signature *sig )
-{
- TRUSTREC sdir;
- int rc;
-
- /* first see whether we already have such a record */
- rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
- if( rc && rc != -1 ) {
- log_error("tdbio_search_sdir failed: %s\n", gpg_errstr(rc));
- tdbio_invalid();
- }
- if( rc == -1 ) { /* not found: create */
- memset( &sdir, 0, sizeof sdir );
- sdir.recnum = tdbio_new_recnum();
- sdir.rectype= RECTYPE_SDIR;
- sdir.r.sdir.lid = sdir.recnum;
- sdir.r.sdir.keyid[0] = sig->keyid[0];
- sdir.r.sdir.keyid[1] = sig->keyid[1];
- sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
- write_record( &sdir );
- }
- return sdir.recnum;
-}
-
-
-static ulong
-find_or_create_lid( PKT_signature *sig )
-{
- ulong lid;
-
- lid = lid_from_keyid_no_sdir( sig->keyid );
- if( !lid )
- lid = create_shadow_dir( sig );
- return lid;
+static int
+read_trust_record (PKT_public_key *pk, TRUSTREC *rec)
+{
+ int rc;
+
+ init_trustdb();
+ rc = tdbio_search_trust_bypk (pk, rec);
+ if (rc == -1)
+ return -1; /* no record yet */
+ if (rc)
+ {
+ log_error ("trustdb: searching trust record failed: %s\n",
+ g10_errstr (rc));
+ return rc;
+ }
+
+ if (rec->rectype != RECTYPE_TRUST)
+ {
+ log_error ("trustdb: record %lu is not a trust record\n",
+ rec->recnum);
+ return G10ERR_TRUSTDB;
+ }
+
+ return 0;
}
-
/****************
- * Check the validity of a key and calculate the keyflags
- * keynode points to
- * a node with a [sub]key. mainkid has the key ID of the primary key
- * keyblock is the complete keyblock which is needed for signature
- * checking. LID and PK is only used in verbose mode.
+ * Return the assigned ownertrust value for the given public key.
+ * The key should be the primary key.
*/
-static unsigned int
-check_keybinding( KBNODE keyblock, KBNODE keynode, u32 *mainkid,
- ulong lid, PKT_public_key *pk )
+unsigned int
+get_ownertrust ( PKT_public_key *pk)
{
- KBNODE node;
- int keybind_seen = 0;
- int revoke_seen = 0;
- unsigned int keyflags=0;
- int is_main = (keynode->pkt->pkttype == PKT_PUBLIC_KEY);
- int rc;
-
- if( DBG_TRUST )
- log_debug("check_keybinding: %08lX.%lu\n",
- (ulong)mainkid[1], lid );
-
- if( is_main ) {
- /* a primary key is always valid (user IDs are handled elsewhere)*/
- keyflags = KEYF_CHECKED | KEYF_VALID;
- }
-
- for( node=keynode->next; node; node = node->next ) {
- PKT_signature *sig;
-
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
-
- sig = node->pkt->pkt.signature;
-
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures */
-
- if( sig->sig_class == 0x18 && !keybind_seen && !is_main ) {
- /* check until we find a valid keybinding */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_("key %08lX.%lu: Good subkey binding\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- keyflags |= KEYF_CHECKED | KEYF_VALID;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, gpg_errstr(rc) );
- keyflags |= KEYF_CHECKED;
- keyflags &= ~KEYF_VALID;
- }
- keybind_seen = 1;
- }
- else if( sig->sig_class == 0x20 && !revoke_seen ) {
- /* this is a key revocation certificate: check it */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_("key %08lX.%lu: Valid key revocation\n"),
- (ulong)keyid_from_pk(pk, NULL), lid );
- keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid key revocation: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, gpg_errstr(rc) );
- }
- revoke_seen = 1;
- }
- else if( sig->sig_class == 0x28 && !revoke_seen && !is_main ) {
- /* this is a subkey revocation certificate: check it */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info(_(
- "key %08lX.%lu: Valid subkey revocation\n"),
- (ulong)keyid_from_pk(pk,NULL), lid );
- keyflags |= KEYF_REVOKED;
- }
- else {
- log_info(_(
- "key %08lX.%lu: Invalid subkey binding: %s\n"),
- (ulong)keyid_from_pk(pk,NULL), lid, gpg_errstr(rc) );
- }
- revoke_seen = 1;
- }
- /* Hmmm: should we handle direct key signatures here? */
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_trust_record (pk, &rec);
+ if (rc == -1)
+ return TRUST_UNKNOWN; /* no record yet */
+ if (rc)
+ {
+ tdbio_invalid ();
+ return rc; /* actually never reached */
}
-
- return keyflags;
+
+ return rec.r.trust.ownertrust;
}
-
-static ulong
-make_key_records( KBNODE keyblock, ulong lid, u32 *keyid, int *mainrev )
+/*
+ * Same as get_ownertrust but return a trust letter instead of an value.
+ */
+int
+get_ownertrust_info (PKT_public_key *pk)
{
- TRUSTREC *krecs, **kend, *k, *k2;
- KBNODE node;
- PKT_public_key *pk;
- byte fpr[MAX_FINGERPRINT_LEN];
- size_t fprlen;
- ulong keyrecno;
-
- *mainrev = 0;
- krecs = NULL; kend = &krecs;
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype != PKT_PUBLIC_KEY
- && node->pkt->pkttype != PKT_PUBLIC_SUBKEY )
- continue;
- pk = node->pkt->pkt.public_key;
- fingerprint_from_pk( pk, fpr, &fprlen );
-
- /* create the key record */
- k = gcry_xcalloc( 1, sizeof *k );
- k->rectype = RECTYPE_KEY;
- k->r.key.lid = lid;
- k->r.key.pubkey_algo = pk->pubkey_algo;
- k->r.key.fingerprint_len = fprlen;
- memcpy(k->r.key.fingerprint, fpr, fprlen );
- k->recnum = tdbio_new_recnum();
- *kend = k;
- kend = &k->next;
-
- k->r.key.keyflags = check_keybinding( keyblock, node, keyid, lid, pk );
- if( (k->r.key.keyflags & KEYF_REVOKED)
- && node->pkt->pkttype == PKT_PUBLIC_KEY )
- *mainrev = 1;
- }
+ unsigned int otrust;
+ int c;
- keyrecno = krecs? krecs->recnum : 0;
- /* write the keylist and release the memory */
- for( k = krecs; k ; k = k2 ) {
- if( k->next )
- k->r.key.next = k->next->recnum;
- write_record( k );
- k2 = k->next;
- gcry_free( k );
- }
- return keyrecno;
+ otrust = get_ownertrust (pk);
+ c = trust_letter( (otrust & TRUST_MASK) );
+ if( !c )
+ c = '?';
+ return c;
}
-
-/****************
- * Check the validity of a user ID and calculate the uidflags
- * keynode points to a node with a user ID.
- * mainkid has the key ID of the primary key, keyblock is the complete
- * keyblock which is needed for signature checking.
- * Returns: The uid flags and the self-signature which is considered to
- * be the most current.
+/*
+ * Set the trust value of the given public key to the new value.
+ * The key should be a primary one.
*/
-static unsigned int
-check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid,
- PKT_signature **bestsig )
-{
- KBNODE node;
- unsigned int uidflags = 0;
- PKT_signature *sig;
- PKT_signature *selfsig = NULL; /* the latest valid self signature */
- int rc;
-
- if( DBG_TRUST ) {
- PKT_user_id *uid;
- log_debug("check_uidsigs: %08lX.%lu \"",
- (ulong)mainkid[1], lid );
- assert(keynode->pkt->pkttype == PKT_USER_ID );
- uid = keynode->pkt->pkt.user_id;
- print_string( log_stream(), uid->name, uid->len, '\"' );
- fputs("\"\n", log_stream());
+void
+update_ownertrust (PKT_public_key *pk, unsigned int new_trust )
+{
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_trust_record (pk, &rec);
+ if (!rc)
+ {
+ if (DBG_TRUST)
+ log_debug ("update ownertrust from %u to %u\n",
+ (unsigned int)rec.r.trust.ownertrust, new_trust );
+ if (rec.r.trust.ownertrust != new_trust)
+ {
+ rec.r.trust.ownertrust = new_trust;
+ write_record( &rec );
+ revalidation_mark ();
+ do_sync ();
+ }
}
+ else if (rc == -1)
+ { /* no record yet - create a new one */
+ size_t dummy;
- /* first we check only the selfsignatures */
- for( node=keynode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid, _("Good self-signature") );
- uidflags |= UIDF_CHECKED | UIDF_VALID;
- if( !selfsig )
- selfsig = sig; /* use the first valid sig */
- else if( sig->timestamp > selfsig->timestamp
- && sig->sig_class >= selfsig->sig_class )
- selfsig = sig; /* but this one is newer */
- }
- else {
- log_info( "uid %08lX: %s: %s\n",
- (ulong)mainkid[1], _("Invalid self-signature"),
- gpg_errstr(rc) );
- uidflags |= UIDF_CHECKED;
- }
- }
- }
+ if (DBG_TRUST)
+ log_debug ("insert ownertrust %u\n", new_trust );
- /* and now check for revocations - we must do this after the
- * self signature check because a self-signature which is newer
- * than a revocation makes the revocation invalid.
- * RFC2440 is quiet about tis but I feel this is reasonable for
- * non-primary-key revocations. */
- for( node=keynode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] != sig->keyid[0] || mainkid[1] != sig->keyid[1] )
- continue; /* we only care about self-signatures for now */
-
- if( sig->sig_class == 0x30 ) { /* cert revocation */
- rc = check_key_signature( keyblock, node, NULL );
- if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid,
- _("Valid user ID revocation skipped "
- "due to a newer self signature") );
- }
- else if( !rc ) {
- if( opt.verbose )
- log_info( "uid %08lX.%lu: %s\n",
- (ulong)mainkid[1], lid, _("Valid user ID revocation") );
- uidflags |= UIDF_CHECKED | UIDF_VALID | UIDF_REVOKED;
- }
- else {
- log_info("uid %08lX: %s: %s\n",
- (ulong)mainkid[1], _("Invalid user ID revocation"),
- gpg_errstr(rc) );
- }
- }
+ memset (&rec, 0, sizeof rec);
+ rec.recnum = tdbio_new_recnum ();
+ rec.rectype = RECTYPE_TRUST;
+ fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
+ rec.r.trust.ownertrust = new_trust;
+ write_record (&rec);
+ revalidation_mark ();
+ do_sync ();
+ rc = 0;
+ }
+ else
+ {
+ tdbio_invalid ();
}
-
- *bestsig = selfsig;
- return uidflags;
}
-
-static unsigned int
-check_sig_record( KBNODE keyblock, KBNODE signode,
- ulong siglid, int sigidx, u32 *keyid, ulong lid,
- u32 *r_expiretime, int *mod_down, int *mod_up )
-{
- PKT_signature *sig = signode->pkt->pkt.signature;
- unsigned int sigflag = 0;
- TRUSTREC tmp;
- int revocation=0, expired=0, rc;
-
- if( DBG_TRUST )
- log_debug("check_sig_record: %08lX.%lu %lu[%d]\n",
- (ulong)keyid[1], lid, siglid, sigidx );
- *r_expiretime = 0;
- if( (sig->sig_class&~3) == 0x10 ) /* regular certification */
- ;
- else if( sig->sig_class == 0x30 ) /* cert revocation */
- revocation = 1;
- else
- return SIGF_CHECKED | SIGF_IGNORED;
-
- read_record( siglid, &tmp, 0 );
- if( tmp.rectype == RECTYPE_DIR ) {
- /* the public key is in the trustdb: check sig */
- rc = check_key_signature2( keyblock, signode, NULL,
- r_expiretime, &expired );
- if( !rc ) { /* valid signature */
- if( opt.verbose )
- log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s\n",
- (ulong)keyid[1], lid, siglid, sigidx,
- (ulong)sig->keyid[1],
- revocation? _("Valid certificate revocation")
- : _("Good certificate") );
- sigflag |= SIGF_CHECKED | SIGF_VALID;
- if( expired ) {
- sigflag |= SIGF_EXPIRED;
- /* We have to reset the expiretime, so that this signature
- * does not get checked over and over due to the reached
- * expiretime */
- *r_expiretime = 0;
- }
- if( revocation ) {
- sigflag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- else
- *mod_up = 1;
- }
- else if( rc == GPGERR_NO_PUBKEY ) {
- /* This may happen if the key is still in the trustdb
- * but not available in the keystorage */
- sigflag |= SIGF_NOPUBKEY;
- *mod_down = 1;
- if( revocation )
- sigflag |= SIGF_REVOKED;
- }
- else {
- log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s: %s\n",
- (ulong)keyid[1], lid, siglid, sigidx,
- (ulong)sig->keyid[1],
- revocation? _("Invalid certificate revocation")
- : _("Invalid certificate"),
- gpg_errstr(rc));
- sigflag |= SIGF_CHECKED;
- if( revocation ) {
- sigflag |= SIGF_REVOKED;
- *mod_down = 1;
- }
- }
- }
- else if( tmp.rectype == RECTYPE_SDIR ) {
- /* better check that it is the right one */
- if( tmp.r.sdir.keyid[0] == sig->keyid[0]
- && tmp.r.sdir.keyid[1] == sig->keyid[1]
- && (!tmp.r.sdir.pubkey_algo
- || tmp.r.sdir.pubkey_algo == sig->pubkey_algo ))
- sigflag |= SIGF_NOPUBKEY;
- else
- log_error(_("sig record %lu[%d] points to wrong record.\n"),
- siglid, sigidx );
+/* Clear the ownertrust value. Return true if a changed actually happend. */
+int
+clear_ownertrust (PKT_public_key *pk)
+{
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_trust_record (pk, &rec);
+ if (!rc)
+ {
+ if (DBG_TRUST)
+ log_debug ("clearing ownertrust (old value %u)\n",
+ (unsigned int)rec.r.trust.ownertrust);
+ if (rec.r.trust.ownertrust)
+ {
+ rec.r.trust.ownertrust = 0;
+ write_record( &rec );
+ revalidation_mark ();
+ do_sync ();
+ return 1;
+ }
}
- else {
- log_error(_("sig record %lu[%d] points to wrong record.\n"),
- siglid, sigidx );
- tdbio_invalid();
+ else if (rc != -1)
+ {
+ tdbio_invalid ();
}
-
- return sigflag;
+ return 0;
}
-/****************
- * Make the sig records for the given uid record
- * We don't set flags here or even check the signatures; this will
- * happen latter.
+/*
+ * Note: Caller has to do a sync
*/
-static ulong
-make_sig_records( KBNODE keyblock, KBNODE uidnode,
- ulong lid, u32 *mainkid, u32 *min_expire,
- int *mod_down, int *mod_up )
-{
- TRUSTREC *srecs, **s_end, *s=NULL, *s2;
- KBNODE node;
- PKT_signature *sig;
- ulong sigrecno, siglid;
- int i, sigidx = 0;
- u32 expiretime;
-
- srecs = NULL; s_end = &srecs;
- for( node=uidnode->next; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_USER_ID
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* ready */
- if( node->pkt->pkttype != PKT_SIGNATURE )
- continue; /* don't care about other packets */
- sig = node->pkt->pkt.signature;
- if( mainkid[0] == sig->keyid[0] && mainkid[1] == sig->keyid[1] )
- continue; /* we don't care about self-signatures here */
-
- siglid = find_or_create_lid( sig );
- /* smash dups */
- /* FIXME: Here we have a problem:
- * We can't distinguish between a certification and a certification
- * revocation without looking at class of the signature - we have
- * to see how we can store the sigclass in the sigrecord..
- * Argg- I hope I can get rid of this ugly trustdb ASAP.
- */
- for( s2 = s; s2 ; s2 = s2->next ) {
- for(i=0; i < sigidx; i++ ) {
- if( s2->r.sig.sig[i].lid == siglid )
- goto leaveduptest;
- }
- }
- for( s2 = srecs; s2 ; s2 = s2->next ) {
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( s2->r.sig.sig[i].lid == siglid )
- goto leaveduptest;
- }
- }
- leaveduptest:
- if( s2 ) {
- log_info( "sig %08lX.%lu: %s\n", (ulong)mainkid[1], lid,
- _("duplicated certificate - deleted") );
- continue;
- }
+static void
+update_validity (PKT_public_key *pk, const byte *namehash,
+ int depth, int validity)
+{
+ TRUSTREC trec, vrec;
+ int rc;
+ ulong recno;
+
+ rc = read_trust_record (pk, &trec);
+ if (rc && rc != -1)
+ {
+ tdbio_invalid ();
+ return;
+ }
+ if (rc == -1) /* no record yet - create a new one */
+ {
+ size_t dummy;
+
+ rc = 0;
+ memset (&trec, 0, sizeof trec);
+ trec.recnum = tdbio_new_recnum ();
+ trec.rectype = RECTYPE_TRUST;
+ fingerprint_from_pk (pk, trec.r.trust.fingerprint, &dummy);
+ trec.r.trust.ownertrust = 0;
+ }
+
+ /* locate an existing one */
+ recno = trec.r.trust.validlist;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
+ if ( !memcmp (vrec.r.valid.namehash, namehash, 20) )
+ break;
+ recno = vrec.r.valid.next;
+ }
+
+ if (!recno) /* insert a new validity record */
+ {
+ memset (&vrec, 0, sizeof vrec);
+ vrec.recnum = tdbio_new_recnum ();
+ vrec.rectype = RECTYPE_VALID;
+ memcpy (vrec.r.valid.namehash, namehash, 20);
+ vrec.r.valid.next = trec.r.trust.validlist;
+ }
+ vrec.r.valid.validity = validity;
+ write_record (&vrec);
+ trec.r.trust.depth = depth;
+ trec.r.trust.validlist = vrec.recnum;
+ write_record (&trec);
+}
+
+
+/* reset validity for all user IDs. Caller must sync. */
+static int
+clear_validity (PKT_public_key *pk)
+{
+ TRUSTREC trec, vrec;
+ int rc;
+ ulong recno;
+ int any = 0;
+
+ rc = read_trust_record (pk, &trec);
+ if (rc && rc != -1)
+ {
+ tdbio_invalid ();
+ return 0;
+ }
+ if (rc == -1) /* no record yet - no need to clerar it then ;-) */
+ return 0;
- /* create the sig record */
- if( !sigidx ) {
- s = gcry_xcalloc( 1, sizeof *s );
- s->rectype = RECTYPE_SIG;
- s->r.sig.lid = lid;
- }
- s->r.sig.sig[sigidx].lid = siglid;
- s->r.sig.sig[sigidx].flag= check_sig_record( keyblock, node,
- siglid, sigidx,
- mainkid, lid, &expiretime,
- mod_down, mod_up );
-
- sigidx++;
- if( sigidx == SIGS_PER_RECORD ) {
- s->recnum = tdbio_new_recnum();
- *s_end = s;
- s_end = &s->next;
- sigidx = 0;
- }
- /* keep track of signers pk expire time */
- if( expiretime && (!*min_expire || *min_expire > expiretime ) )
- *min_expire = expiretime;
- }
- if( sigidx ) {
- s->recnum = tdbio_new_recnum();
- *s_end = s;
- s_end = &s->next;
+ /* reset validity for all user IDs */
+ recno = trec.r.trust.validlist;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
+ if ((vrec.r.valid.validity & TRUST_MASK))
+ {
+ vrec.r.valid.validity &= ~TRUST_MASK;
+ write_record (&vrec);
+ any = 1;
+ }
+ recno = vrec.r.valid.next;
}
- sigrecno = srecs? srecs->recnum : 0;
- /* write the keylist and release the memory */
- for( s = srecs; s ; s = s2 ) {
- if( s->next )
- s->r.sig.next = s->next->recnum;
- write_record( s );
- s2 = s->next;
- gcry_free( s );
- }
- return sigrecno;
+ return any;
}
+
+/***********************************************
+ ********* Query trustdb values **************
+ ***********************************************/
-/****************
- * Make a preference record (or a list of them) according to the supplied
- * signature.
- * Returns: The record number of the first pref record.
+/*
+ * Return the validity information for PK. If the namehash is not
+ * NULL, the validity of the corresponsing user ID is returned,
+ * otherwise, a reasonable value for the entire key is returned.
*/
-static ulong
-make_pref_record( PKT_signature *sig, ulong lid )
-{
- static struct {
- sigsubpkttype_t subpkttype;
- int preftype;
- } ptable[] = {
- { SIGSUBPKT_PREF_SYM, PREFTYPE_SYM },
- { SIGSUBPKT_PREF_HASH, PREFTYPE_HASH },
- { SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR },
- { 0, 0 }
- };
- TRUSTREC *precs, **p_end, *p=NULL, *p2;
- ulong precno;
- int k, idx=0;
- const byte *s;
- size_t n;
-
- #if (ITEMS_PER_PREF_RECORD % 2) != 0
- #error ITEMS_PER_PREF_RECORD must have an even value
- #endif
-
- precs = NULL; p_end = &precs;
- for(k=0; ptable[k].subpkttype; k++ ) {
- s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
- if( !s )
- continue;
- for( ; n; n--, s++ ) {
- if( !idx ) {
- p = gcry_xcalloc( 1, sizeof *p );
- p->rectype = RECTYPE_PREF;
- p->r.pref.lid = lid;
- }
- p->r.pref.data[idx++] = ptable[k].preftype;
- p->r.pref.data[idx++] = *s;
- if( idx >= ITEMS_PER_PREF_RECORD ) {
- p->recnum = tdbio_new_recnum();
- *p_end = p;
- p_end = &p->next;
- idx = 0;
- }
- }
- }
- if( idx ) {
- p->recnum = tdbio_new_recnum();
- *p_end = p;
- p_end = &p->next;
- }
-
- precno = precs? precs->recnum : 0;
- /* write the precs and release the memory */
- for( p = precs; p ; p = p2 ) {
- if( p->next )
- p->r.pref.next = p->next->recnum;
- write_record( p );
- p2 = p->next;
- gcry_free( p );
+unsigned int
+get_validity (PKT_public_key *pk, const byte *namehash)
+{
+ static int did_nextcheck;
+ TRUSTREC trec, vrec;
+ int rc;
+ ulong recno;
+ unsigned int validity;
+ u32 kid[2];
+ PKT_public_key *main_pk;
+
+ init_trustdb ();
+ if (!did_nextcheck)
+ {
+ ulong scheduled;
+
+ did_nextcheck = 1;
+ scheduled = tdbio_read_nextcheck ();
+ if (scheduled && scheduled <= make_timestamp ())
+ {
+ if (opt.no_auto_check_trustdb)
+ {
+ pending_check_trustdb = 1;
+ log_info ("please do a --check-trustdb\n");
+ }
+ else
+ {
+ log_info (_("checking the trustdb\n"));
+ validate_keys (0);
+ }
+ }
}
- return precno;
-}
-
-
-static ulong
-make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire,
- int *mod_down, int *mod_up )
-{
- TRUSTREC *urecs, **uend, *u, *u2;
- KBNODE node;
- PKT_user_id *uid;
- byte uidhash[20];
- ulong uidrecno;
-
- urecs = NULL; uend = &urecs;
- for( node=keyblock; node; node = node->next ) {
- PKT_signature *bestsig;
-
- if( node->pkt->pkttype != PKT_USER_ID )
- continue;
- uid = node->pkt->pkt.user_id;
- if( uid->photo ) {
- gcry_md_hash_buffer( GCRY_MD_RMD160, uidhash,
- uid->photo, uid->photolen );
- }
- else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, uidhash,
- uid->name, uid->len );
- }
- /* create the uid record */
- u = gcry_xcalloc( 1, sizeof *u );
- u->rectype = RECTYPE_UID;
- u->r.uid.lid = lid;
- memcpy(u->r.uid.namehash, uidhash, 20 );
- u->recnum = tdbio_new_recnum();
- *uend = u;
- uend = &u->next;
-
- u->r.uid.uidflags = check_uidsigs( keyblock, node, keyid,
- lid, &bestsig );
- if( (u->r.uid.uidflags & UIDF_CHECKED)
- && (u->r.uid.uidflags & UIDF_VALID) ) {
- u->r.uid.prefrec = bestsig? make_pref_record( bestsig, lid ) : 0;
+ keyid_from_pk (pk, kid);
+ if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1])
+ { /* this is a subkey - get the mainkey */
+ main_pk = m_alloc_clear (sizeof *main_pk);
+ rc = get_pubkey (main_pk, pk->main_keyid);
+ if (rc)
+ {
+ log_error ("error getting main key %08lX of subkey %08lX: %s\n",
+ (ulong)pk->main_keyid[1], (ulong)kid[1], g10_errstr(rc));
+ validity = TRUST_UNKNOWN;
+ goto leave;
}
-
- /* the next test is really bad because we should modify
- * out modification timestamps only if we really have a change.
- * But because we are deleting the uid records first it is somewhat
- * difficult to track those changes. fixme */
- if( !( u->r.uid.uidflags & UIDF_VALID )
- || ( u->r.uid.uidflags & UIDF_REVOKED ) )
- *mod_down=1;
- else
- *mod_up=1;
-
- /* create the list of signatures */
- u->r.uid.siglist = make_sig_records( keyblock, node,
- lid, keyid, min_expire,
- mod_down, mod_up );
- }
-
- uidrecno = urecs? urecs->recnum : 0;
- /* write the uidlist and release the memory */
- for( u = urecs; u ; u = u2 ) {
- if( u->next )
- u->r.uid.next = u->next->recnum;
- write_record( u );
- u2 = u->next;
- gcry_free( u );
}
- return uidrecno;
+ else
+ main_pk = pk;
+
+ rc = read_trust_record (main_pk, &trec);
+ if (rc && rc != -1)
+ {
+ tdbio_invalid ();
+ return 0;
+ }
+ if (rc == -1) /* no record found */
+ {
+ validity = TRUST_UNKNOWN;
+ goto leave;
+ }
+
+ /* loop over all user IDs */
+ recno = trec.r.trust.validlist;
+ validity = 0;
+ while (recno)
+ {
+ read_record (recno, &vrec, RECTYPE_VALID);
+ if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
+ validity = (vrec.r.valid.validity & TRUST_MASK);
+ if ( namehash && !memcmp (vrec.r.valid.namehash, namehash, 20) )
+ break;
+ recno = vrec.r.valid.next;
+ }
+
+ if (recno) /* okay, use the user ID associated one */
+ validity = (vrec.r.valid.validity & TRUST_MASK);
+
+ if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
+ validity |= TRUST_FLAG_DISABLED;
+
+ leave:
+ /* set some flags direct from the key */
+ if (main_pk->is_revoked)
+ validity |= TRUST_FLAG_REVOKED;
+ if (main_pk != pk && pk->is_revoked)
+ validity |= TRUST_FLAG_SUB_REVOKED;
+ /* Note: expiration is a trust value and not a flag - don't know why
+ * I initially designed it that way */
+ if (main_pk->has_expired || pk->has_expired)
+ validity = (validity & ~TRUST_MASK) | TRUST_EXPIRED;
+
+ if (pending_check_trustdb)
+ validity |= TRUST_FLAG_PENDING_CHECK;
+
+ if (main_pk != pk)
+ free_public_key (main_pk);
+ return validity;
}
-
-/****************
- * Update all the info from the public keyblock.
- * The key must already exist in the keydb.
- */
int
-update_trust_record( KBNODE keyblock, int recheck, int *modified )
+get_validity_info (PKT_public_key *pk, const byte *namehash)
{
- TRUSTREC drec;
- int rc;
+ int trustlevel;
+ int c;
- /* NOTE: We don't need recheck anymore, but this might chnage again in
- * the future */
- if( opt.dry_run )
- return 0;
- if( modified )
- *modified = 0;
- init_trustdb();
- rc = get_dir_record( find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key, &drec );
- if( rc )
- return rc;
-
- rc = do_update_trust_record( keyblock, &drec, 0, modified );
- return rc;
+ trustlevel = get_validity (pk, namehash);
+ if( trustlevel & TRUST_FLAG_DISABLED )
+ return 'd';
+ if( trustlevel & TRUST_FLAG_REVOKED )
+ return 'r';
+ c = trust_letter ( (trustlevel & TRUST_MASK) );
+ if( !c )
+ c = '?';
+ return c;
}
-/****************
- * Same as update_trust_record, but this functions expects the dir record.
- * On exit the dir record will reflect any changes made.
- * With sigs_only set only foreign key signatures are checked.
- */
-static int
-do_update_trust_record( KBNODE keyblock, TRUSTREC *drec,
- int sigs_only, int *modified )
-{
- PKT_public_key *primary_pk;
- TRUSTREC krec, urec, prec, helprec;
- int i, rc = 0;
- u32 keyid[2]; /* keyid of primary key */
- int mod_up = 0;
- int mod_down = 0;
- ulong recno, r2;
- u32 expiretime;
-
- primary_pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
- if( !primary_pk->local_id )
- primary_pk->local_id = drec->recnum;
-
- keyid_from_pk( primary_pk, keyid );
- if( DBG_TRUST )
- log_debug("do_update_trust_record: %08lX.%lu\n",
- (ulong)keyid[1], drec->recnum );
-
- rc = tdbio_begin_transaction();
- if( rc )
- return rc;
-
- /* delete the old stuff FIXME: implementend sigs_only */
- for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
- read_record( recno, &krec, RECTYPE_KEY );
- delete_record( recno );
- }
- drec->r.dir.keylist = 0;
- for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
- read_record( recno, &urec, RECTYPE_UID );
- for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
- read_record( r2, &prec, RECTYPE_PREF );
- delete_record( r2 );
- }
- for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
- read_record( r2, &helprec, RECTYPE_SIG );
- delete_record( r2 );
- }
- delete_record( recno );
- }
- drec->r.dir.uidlist = 0;
-
-
- /* insert new stuff */
- drec->r.dir.dirflags &= ~DIRF_REVOKED;
- drec->r.dir.dirflags &= ~DIRF_NEWKEYS;
- drec->r.dir.keylist = make_key_records( keyblock, drec->recnum, keyid, &i );
- if( i ) /* primary key has been revoked */
- drec->r.dir.dirflags |= DIRF_REVOKED;
- expiretime = 0;
- drec->r.dir.uidlist = make_uid_records( keyblock, drec->recnum, keyid,
- &expiretime, &mod_down, &mod_up );
- if( rc )
- rc = tdbio_cancel_transaction();
- else {
- if( modified && tdbio_is_dirty() )
- *modified = 1;
- drec->r.dir.dirflags |= DIRF_CHECKED;
- drec->r.dir.valcheck = 0;
- drec->r.dir.checkat = expiretime;
- write_record( drec );
- tdbio_write_modify_stamp( mod_up, mod_down );
- rc = tdbio_end_transaction();
- }
- return rc;
-}
-/****************
- * Insert a trust record into the TrustDB
- * This function assumes that the record does not yet exist.
- */
-int
-insert_trust_record( KBNODE keyblock )
+void
+list_trust_path( const char *username )
{
- TRUSTREC dirrec;
- TRUSTREC shadow;
- KBNODE node;
- int rc = 0;
- PKT_public_key *pk;
-
-
- if( opt.dry_run )
- return 0;
-
- init_trustdb();
-
- pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
- if( pk->local_id ) {
- log_debug("insert_trust_record with pk->local_id=%lu (2)\n",
- pk->local_id );
- rc = update_trust_record( keyblock, 1, NULL );
- return rc;
- }
-
- /* We have to look for a shadow dir record which must be reused
- * as the dir record. */
- rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
- if( rc && rc != -1 ) {
- log_error(_("tdbio_search_dir failed: %s\n"), gpg_errstr(rc));
- tdbio_invalid();
- }
- memset( &dirrec, 0, sizeof dirrec );
- dirrec.rectype = RECTYPE_DIR;
- if( !rc ) /* we have a shadow dir record - convert to dir record */
- dirrec.recnum = shadow.recnum;
- else
- dirrec.recnum = tdbio_new_recnum();
- dirrec.r.dir.lid = dirrec.recnum;
- write_record( &dirrec );
-
- /* put the LID into the keyblock */
- pk->local_id = dirrec.r.dir.lid;
- for( node=keyblock; node; node = node->next ) {
- if( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- PKT_public_key *a_pk = node->pkt->pkt.public_key;
- a_pk->local_id = dirrec.r.dir.lid;
- }
- else if( node->pkt->pkttype == PKT_SIGNATURE ) {
- PKT_signature *a_sig = node->pkt->pkt.signature;
- a_sig->local_id = dirrec.r.dir.lid;
- }
- }
-
-
- /* mark tdb as modified upwards */
- tdbio_write_modify_stamp( 1, 0 );
-
- /* and put all the other stuff into the keydb */
- rc = do_update_trust_record( keyblock, &dirrec, 0, NULL );
-
- do_sync();
-
- /* keep track of new keys */
- if( !fresh_imported_keys )
- fresh_imported_keys = new_lid_table();
- ins_lid_table_item( fresh_imported_keys, pk->local_id, 0 );
- if( ++fresh_imported_keys_count > FRESH_KEY_CHECK_THRESHOLD )
- mark_fresh_keys();
-
- return rc;
}
/****************
- * Insert a trust record indentified by a PK into the TrustDB
+ * Enumerate all keys, which are needed to build all trust paths for
+ * the given key. This function does not return the key itself or
+ * the ultimate key (the last point in cerificate chain). Only
+ * certificate chains which ends up at an ultimately trusted key
+ * are listed. If ownertrust or validity is not NULL, the corresponding
+ * value for the returned LID is also returned in these variable(s).
+ *
+ * 1) create a void pointer and initialize it to NULL
+ * 2) pass this void pointer by reference to this function.
+ * Set lid to the key you want to enumerate and pass it by reference.
+ * 3) call this function as long as it does not return -1
+ * to indicate EOF. LID does contain the next key used to build the web
+ * 4) Always call this function a last time with LID set to NULL,
+ * so that it can free its context.
+ *
+ * Returns: -1 on EOF or the level of the returned LID
*/
int
-insert_trust_record_by_pk( PKT_public_key *pk )
-{
- KBNODE keyblock = NULL;
- byte fingerprint[MAX_FINGERPRINT_LEN];
- size_t fingerlen;
- int rc;
-
- /* get the keyblock */
- fingerprint_from_pk( pk, fingerprint, &fingerlen );
- rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
- if( rc ) { /* that should never happen */
- log_debug( "insert_trust_record_by_pk: keyblock not found: %s\n",
- gpg_errstr(rc) );
- }
- else {
- rc = insert_trust_record( keyblock );
- if( !rc ) /* copy the LID into the PK */
- pk->local_id = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key->local_id;
- }
-
- release_kbnode( keyblock );
- return rc;
-}
-
-
-/****************
- * Check one trust record. This function is called for every
- * directory record which is to be checked. The supplied
- * dir record is modified according to the performed actions.
- * Currently we only do an update_trust_record.
- */
-static int
-check_trust_record( TRUSTREC *drec, int sigs_only )
+enum_cert_paths( void **context, ulong *lid,
+ unsigned *ownertrust, unsigned *validity )
{
- KBNODE keyblock;
- int modified, rc;
-
- rc = get_keyblock_bylid( &keyblock, drec->recnum );
- if( rc ) {
- log_debug( "check_trust_record %lu: keyblock not found: %s\n",
- drec->recnum, gpg_errstr(rc) );
- return rc;
- }
-
- rc = do_update_trust_record( keyblock, drec, sigs_only, &modified );
- release_kbnode( keyblock );
-
- return rc;
+ return -1;
}
/****************
- * Walk over the keyrings and create trustdb records for all keys
- * which are not currently in the trustdb.
- * It is intended to be used after a fast-import operation.
+ * Print the current path
*/
void
-update_trustdb()
+enum_cert_paths_print( void **context, FILE *fp,
+ int refresh, ulong selected_lid )
{
- KBNODE keyblock = NULL;
- KBPOS kbpos;
- int rc;
-
- if( opt.dry_run )
- return;
-
- init_trustdb();
- rc = enum_keyblocks_begin( &kbpos, 0 );
- if( !rc ) {
- ulong count=0, err_count=0, new_count=0;
-
- while( !(rc = enum_keyblocks_next( kbpos, 1, &keyblock )) ) {
- /*int modified;*/
- TRUSTREC drec;
- PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
- ->pkt->pkt.public_key;
-
- rc = get_dir_record( pk, &drec );
- if( rc == -1 ) { /* not in trustdb: insert */
- rc = insert_trust_record( keyblock );
- if( rc && !pk->local_id ) {
- log_error(_("lid ?: insert failed: %s\n"),
- gpg_errstr(rc) );
- err_count++;
- }
- else if( rc ) {
- log_error(_("lid %lu: insert failed: %s\n"),
- pk->local_id, gpg_errstr(rc) );
- err_count++;
- }
- else {
- if( opt.verbose )
- log_info(_("lid %lu: inserted\n"), pk->local_id );
- new_count++;
- }
- }
- else if( rc ) {
- log_error(_("error reading dir record: %s\n"), gpg_errstr(rc));
- err_count++;
- }
-
- release_kbnode( keyblock ); keyblock = NULL;
- if( !(++count % 100) )
- log_info(_("%lu keys so far processed\n"), count);
- }
- log_info(_("%lu keys processed\n"), count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( new_count )
- log_info(_("\t%lu keys inserted\n"), new_count);
- }
- if( rc && rc != -1 )
- log_error(_("enumerate keyblocks failed: %s\n"), gpg_errstr(rc));
-
- enum_keyblocks_end( kbpos );
- release_kbnode( keyblock );
+ return;
}
+
+/****************************************
+ *********** NEW NEW NEW ****************
+ ****************************************/
-/****************
- * Do all required checks in the trustdb. This function walks over all
- * records in the trustdb and does scheduled processing.
- */
-void
-check_trustdb( const char *username )
+static int
+ask_ownertrust (u32 *kid)
{
- TRUSTREC rec;
- ulong recnum;
- ulong count=0, upd_count=0, err_count=0, skip_count=0, sigonly_count=0;
- ulong current_time = make_timestamp();
-
- if( username )
- log_info("given user IDs ignored in check_trustdb\n");
-
- init_trustdb();
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- int sigs_only;
-
- if( rec.rectype != RECTYPE_DIR )
- continue; /* we only want the dir records */
-
- if( count && !(count % 100) && !opt.quiet )
- log_info(_("%lu keys so far processed\n"), count);
- count++;
- sigs_only = 0;
-
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
- ;
- else if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) {
- if( !(rec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- skip_count++;
- continue; /* not scheduled for checking */
- }
- sigs_only = 1; /* new public keys - check them */
- sigonly_count++;
- }
-
- if( !rec.r.dir.keylist ) {
- log_info(_("lid %lu: dir record w/o key - skipped\n"), recnum);
- skip_count++;
- continue;
- }
+ PKT_public_key *pk;
+ int rc;
+ int ot;
- check_trust_record( &rec, sigs_only );
+ pk = m_alloc_clear (sizeof *pk);
+ rc = get_pubkey (pk, kid);
+ if (rc)
+ {
+ log_error (_("public key %08lX not found: %s\n"),
+ (ulong)kid[1], g10_errstr(rc) );
+ return TRUST_UNKNOWN;
}
-
- log_info(_("%lu keys processed\n"), count);
- if( sigonly_count )
- log_info(_("\t%lu due to new pubkeys\n"), sigonly_count);
- if( skip_count )
- log_info(_("\t%lu keys skipped\n"), skip_count);
- if( err_count )
- log_info(_("\t%lu keys with errors\n"), err_count);
- if( upd_count )
- log_info(_("\t%lu keys updated\n"), upd_count);
+
+ ot=edit_ownertrust(pk,0);
+ if(ot>0)
+ ot = get_ownertrust (pk);
+ else if(ot==0)
+ ot = TRUST_UNDEFINED;
+ else
+ ot = -1; /* quit */
+ free_public_key( pk );
+ return ot;
}
-
-/***********************************************
- ********* Trust calculation *****************
- ***********************************************/
-
-/****************
- * Find all certification paths of a given LID.
- * Limit the search to MAX_DEPTH. stack is a helper variable which
- * should have been allocated with size max_depth, stack[0] should
- * be setup to the key we are investigating, so the minimal depth
- * we should ever see in this function is 1.
- * Returns: a new tree
- * certchain_set must be a valid set or point to NULL; this function
- * may modifiy it.
- *
- * Hmmm: add a fastscan mode which stops at valid validity nodes.
- */
-static TN
-build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
+static void
+mark_keyblock_seen (KeyHashTable tbl, KBNODE node)
{
- TRUSTREC dirrec;
- TRUSTREC uidrec;
- ulong uidrno;
- TN keynode;
-
- if( depth >= max_depth )
- return NULL;
-
- keynode = new_tn();
- if( !helproot )
- helproot = keynode;
- keynode->lid = lid;
- if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) {
- /* this is an ultimately trusted key;
- * which means that we have found the end of the chain:
- * We do this here prior to reading the dir record
- * because we don't really need the info from that record */
- keynode->n.k.ownertrust = TRUST_ULTIMATE;
- keynode->n.k.buckstop = 1;
- return keynode;
- }
- read_record( lid, &dirrec, 0 );
- if( dirrec.rectype != RECTYPE_DIR ) {
- if( dirrec.rectype != RECTYPE_SDIR )
- log_debug("lid %lu, has rectype %d"
- " - skipped\n", lid, dirrec.rectype );
- gcry_free(keynode);
- return NULL;
- }
-
- if( dirrec.r.dir.checkat && dirrec.r.dir.checkat <= make_timestamp() ) {
- check_trust_record( &dirrec, 0 );
- }
- else if( (dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- check_trust_record( &dirrec, 1 );
- }
-
- keynode->n.k.ownertrust = dirrec.r.dir.ownertrust & TRUST_MASK;
-
- /* loop over all user ids */
- for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) {
- TRUSTREC sigrec;
- ulong sigrno;
- TN uidnode = NULL;
-
- read_record( uidrno, &uidrec, RECTYPE_UID );
-
- if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) )
- continue; /* user id has not been checked */
- if( !(uidrec.r.uid.uidflags & UIDF_VALID) )
- continue; /* user id is not valid */
- if( (uidrec.r.uid.uidflags & UIDF_REVOKED) )
- continue; /* user id has been revoked */
-
- /* loop over all signature records */
- for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) {
- int i;
- TN tn;
-
- read_record( sigrno, &sigrec, RECTYPE_SIG );
-
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( !sigrec.r.sig.sig[i].lid )
- continue; /* skip deleted sigs */
- if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) )
- continue; /* skip unchecked signatures */
- if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) )
- continue; /* skip invalid signatures */
- if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) )
- continue; /* skip expired signatures */
- if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) )
- continue; /* skip revoked signatures */
- /* check for cycles */
- for( tn=keynode; tn && tn->lid != sigrec.r.sig.sig[i].lid;
- tn = tn->back )
- ;
- if( tn )
- continue; /* cycle found */
-
- tn = build_cert_tree( sigrec.r.sig.sig[i].lid,
- depth+1, max_depth, helproot );
- if( !tn )
- continue; /* cert chain too deep or error */
-
- if( !uidnode ) {
- uidnode = new_tn();
- uidnode->back = keynode;
- uidnode->lid = uidrno;
- uidnode->is_uid = 1;
- uidnode->next = keynode->list;
- keynode->list = uidnode;
- }
-
- tn->back = uidnode;
- tn->next = uidnode->list;
- uidnode->list = tn;
- if( tn->n.k.buckstop ) {
- /* ultimately trusted key found:
- * no need to check more signatures of this uid */
- sigrec.r.sig.next = 0;
- break;
- }
- }
- } /* end loop over sig recs */
- } /* end loop over user ids */
+ for ( ;node; node = node->next )
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ u32 aki[2];
- if( !keynode->list ) {
- release_tn_tree( keynode );
- keynode = NULL;
- }
-
- return keynode;
+ keyid_from_pk (node->pkt->pkt.public_key, aki);
+ add_key_hash_table (tbl, aki);
+ }
}
+
static void
-upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs )
-{
- TRUSTREC rec;
-
- read_record( lid, &rec, RECTYPE_DIR );
- if( DBG_TRUST )
- log_debug("upd_one_ownertrust of %lu from %u to %u\n",
- lid, (unsigned)rec.r.dir.ownertrust, new_trust );
- if( retflgs ) {
- if( (new_trust & TRUST_MASK) > (rec.r.dir.ownertrust & TRUST_MASK) )
- *retflgs |= 16; /* modified up */
- else
- *retflgs |= 32; /* modified down */
+dump_key_array (int depth, struct key_array *keys)
+{
+ struct key_array *kar;
+
+ for (kar=keys; kar->keyblock; kar++)
+ {
+ KBNODE node = kar->keyblock;
+ u32 kid[2];
+
+ keyid_from_pk(node->pkt->pkt.public_key, kid);
+ printf ("%d:%08lX%08lX:K::%c::::\n",
+ depth, (ulong)kid[0], (ulong)kid[1], '?');
+
+ for (; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ int len = node->pkt->pkt.user_id->len;
+
+ if (len > 30)
+ len = 30;
+ printf ("%d:%08lX%08lX:U:::%c:::",
+ depth, (ulong)kid[0], (ulong)kid[1],
+ (node->flag & 4)? 'f':
+ (node->flag & 2)? 'm':
+ (node->flag & 1)? 'q':'-');
+ print_string (stdout, node->pkt->pkt.user_id->name, len, ':');
+ putchar (':');
+ putchar ('\n');
+ }
+ }
}
+}
- /* we preserve the disabled state here */
- if( (rec.r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- rec.r.dir.ownertrust = new_trust | TRUST_FLAG_DISABLED;
- else
- rec.r.dir.ownertrust = new_trust & ~TRUST_FLAG_DISABLED;
- write_record( &rec );
-}
-/****************
- * Update the ownertrust in the complete tree.
- */
static void
-propagate_ownertrust( TN kr, ulong lid, unsigned trust )
-{
- TN ur;
-
- for( ; kr; kr = kr->next ) {
- if( kr->lid == lid )
- kr->n.k.ownertrust = trust;
- for( ur=kr->list; ur; ur = ur->next )
- propagate_ownertrust( ur->list, lid, trust );
+store_validation_status (int depth, KBNODE keyblock)
+{
+ KBNODE node;
+ byte namehash[20];
+ int status;
+ int any = 0;
+
+ for (node=keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+
+ if (node->flag & 4)
+ status = TRUST_FULLY;
+ else if (node->flag & 2)
+ status = TRUST_MARGINAL;
+ else if (node->flag & 1)
+ status = TRUST_UNDEFINED;
+ else
+ status = 0;
+
+ if (status)
+ {
+ if( uid->attrib_data )
+ rmd160_hash_buffer (namehash,uid->attrib_data,uid->attrib_len);
+ else
+ rmd160_hash_buffer (namehash, uid->name, uid->len );
+
+ update_validity (keyblock->pkt->pkt.public_key,
+ namehash, depth, status);
+ any = 1;
+ }
+ }
}
-}
-/****************
- * Calculate the validity of all keys in the tree and especially
- * the one of the top key. If add_fnc is not NULL, it is used to
- * ask for missing ownertrust values (but only if this will help
- * us to increase the validity.
- * add_fnc is expected to take the LID of the key under question
- * and return a ownertrust value or an error: positive values
- * are assumed to be the new ownertrust value; a 0 does mean no change,
- * a -1 is a request to cancel this validation procedure, a -2 requests
- * a listing of the sub-tree using the tty functions.
- *
- *
- * Returns: 0 = okay
+ if (any)
+ do_sync ();
+}
+
+/*
+ * check whether the signature sig is in the klist k
*/
-static int
-propagate_validity( TN root, TN node, int (*add_fnc)(ulong), unsigned *retflgs )
+static struct key_item *
+is_in_klist (struct key_item *k, PKT_signature *sig)
{
- TN kr, ur;
- int max_validity = 0;
-
- assert( !node->is_uid );
- if( node->n.k.ownertrust == TRUST_ULTIMATE ) {
- /* this is one of our keys */
- assert( !node->list ); /* it should be a leaf */
- node->n.k.validity = TRUST_ULTIMATE;
- if( retflgs )
- *retflgs |= 1; /* found a path to an ultimately trusted key */
- return 0;
+ for (; k; k = k->next)
+ {
+ if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
+ return k;
}
-
- /* loop over all user ids */
- for( ur=node->list; ur && max_validity <= TRUST_FULLY; ur = ur->next ) {
- assert( ur->is_uid );
- /* loop over all signators */
- for(kr=ur->list; kr && max_validity <= TRUST_FULLY; kr = kr->next ) {
- if( propagate_validity( root, kr, add_fnc, retflgs ) )
- return -1; /* quit */
- if( kr->n.k.validity == TRUST_ULTIMATE ) {
- ur->n.u.fully_count = opt.completes_needed;
- }
- else if( kr->n.k.validity == TRUST_FULLY ) {
- if( add_fnc && !kr->n.k.ownertrust ) {
- int rc;
-
- if( retflgs )
- *retflgs |= 2; /* found key with undefined ownertrust*/
- do {
- rc = add_fnc( kr->lid );
- switch( rc ) {
- case TRUST_NEVER:
- case TRUST_MARGINAL:
- case TRUST_FULLY:
- propagate_ownertrust( root, kr->lid, rc );
- upd_one_ownertrust( kr->lid, rc, retflgs );
- if( retflgs )
- *retflgs |= 4; /* changed */
- break;
- case -1:
- return -1; /* cancel */
- case -2:
- dump_tn_tree( NULL, 0, kr );
- tty_printf("\n");
- break;
- default:
- break;
- }
- } while( rc == -2 );
- }
- if( kr->n.k.ownertrust == TRUST_FULLY )
- ur->n.u.fully_count++;
- else if( kr->n.k.ownertrust == TRUST_MARGINAL )
- ur->n.u.marginal_count++;
- }
-
- if( ur->n.u.fully_count >= opt.completes_needed
- || ur->n.u.marginal_count >= opt.marginals_needed )
- ur->n.u.validity = TRUST_FULLY;
- else if( ur->n.u.fully_count || ur->n.u.marginal_count )
- ur->n.u.validity = TRUST_MARGINAL;
-
- if( ur->n.u.validity >= max_validity )
- max_validity = ur->n.u.validity;
- }
- }
-
- node->n.k.validity = max_validity;
- return 0;
+ return NULL;
}
-
-
-/****************
- * Given the directory record of a key, check whether we can
- * find a path to an ultimately trusted key. We do this by
- * checking all key signatures up to a some depth.
+/*
+ * Mark the signature of the given UID which are used to certify it.
+ * To do this, we first revmove all signatures which are not valid and
+ * from the remain ones we look for the latest one. If this is not a
+ * certification revocation signature we mark the signature by setting
+ * node flag bit 8. Note that flag bits 9 and 10 are used for internal
+ * purposes.
*/
-static int
-verify_key( int max_depth, TRUSTREC *drec, const char *namehash,
- int (*add_fnc)(ulong), unsigned *retflgs )
-{
- TN tree;
- int keytrust;
- int pv_result;
-
- tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
- if( !tree )
- return TRUST_UNDEFINED;
- pv_result = propagate_validity( tree, tree, add_fnc, retflgs );
- if( namehash && tree->n.k.validity != TRUST_ULTIMATE ) {
- /* find the matching user id.
- * We don't do this here if the key is ultimately trusted; in
- * this case there will be no lids for the user IDs and frankly
- * it does not make sense to compare by the name if we do
- * have the secret key.
- * fixme: the way we handle this is too inefficient */
- TN ur;
- TRUSTREC rec;
-
- keytrust = 0;
- for( ur=tree->list; ur; ur = ur->next ) {
- read_record( ur->lid, &rec, RECTYPE_UID );
- if( !memcmp( namehash, rec.r.uid.namehash, 20 ) ) {
- keytrust = ur->n.u.validity;
- break;
- }
- }
- }
- else
- keytrust = tree->n.k.validity;
-
- /* update the cached validity values */
- if( !pv_result
- && keytrust >= TRUST_UNDEFINED
- && tdbio_db_matches_options()
- && ( !drec->r.dir.valcheck || drec->r.dir.validity != keytrust ) ) {
- TN ur;
- TRUSTREC rec;
-
- for( ur=tree->list; ur; ur = ur->next ) {
- read_record( ur->lid, &rec, RECTYPE_UID );
- if( rec.r.uid.validity != ur->n.u.validity ) {
- rec.r.uid.validity = ur->n.u.validity;
- write_record( &rec );
- }
- }
+static void
+mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
+ u32 *main_kid, struct key_item *klist,
+ u32 curtime, u32 *next_expire)
+{
+ KBNODE node;
+ PKT_signature *sig;
+
+ /* first check all signatures */
+ for (node=uidnode->next; node; node = node->next)
+ {
+ node->flag &= ~(1<<8 | 1<<9 | 1<<10);
+ if (node->pkt->pkttype == PKT_USER_ID
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break; /* ready */
+ if (node->pkt->pkttype != PKT_SIGNATURE)
+ continue;
+
+ sig = node->pkt->pkt.signature;
+ if (sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
+ continue; /* ignore self-signatures */
+ if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
+ continue; /* we only look at these signature classes */
+ if (!is_in_klist (klist, sig))
+ continue; /* no need to check it then */
+ if (check_key_signature (keyblock, node, NULL))
+ continue; /* ignore invalid signatures */
+ node->flag |= 1<<9;
+ }
+ /* reset the remaining flags */
+ for (; node; node = node->next)
+ node->flag &= ~(1<<8 | 1<<9 | 1 << 10);
+
+ /* kbnode flag usage: bit 9 is here set for signatures to consider,
+ * bit 10 will be set by the loop to keep track of keyIDs already
+ * processed, bit 8 will be set for the usable signatures */
+
+ /* for each cert figure out the latest valid one */
+ for (node=uidnode->next; node; node = node->next)
+ {
+ KBNODE n, signode;
+ u32 kid[2];
+ u32 sigdate;
+
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break;
+ if ( !(node->flag & (1<<9)) )
+ continue; /* not a node to look at */
+ if ( (node->flag & (1<<10)) )
+ continue; /* signature with a keyID already processed */
+ node->flag |= (1<<10); /* mark this node as processed */
+ sig = node->pkt->pkt.signature;
+ signode = node;
+ sigdate = sig->timestamp;
+ kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
+ for (n=uidnode->next; n; n = n->next)
+ {
+ if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ break;
+ if ( !(n->flag & (1<<9)) )
+ continue;
+ if ( (n->flag & (1<<10)) )
+ continue; /* shortcut already processed signatures */
+ sig = n->pkt->pkt.signature;
+ if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
+ continue;
+ n->flag |= (1<<10); /* mark this node as processed */
+
+ /* If signode is nonrevocable and unexpired and n isn't,
+ then take signode (skip). It doesn't matter which is
+ older: if signode was older then we don't want to take n
+ as signode is nonrevocable. If n was older then we're
+ automatically fine. */
+
+ if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
+ !signode->pkt->pkt.signature->flags.revocable &&
+ (signode->pkt->pkt.signature->expiredate==0 ||
+ signode->pkt->pkt.signature->expiredate>curtime))) &&
+ (!(IS_UID_SIG(n->pkt->pkt.signature) &&
+ !n->pkt->pkt.signature->flags.revocable &&
+ (n->pkt->pkt.signature->expiredate==0 ||
+ n->pkt->pkt.signature->expiredate>curtime))))
+ continue;
- drec->r.dir.validity = tree->n.k.validity;
- drec->r.dir.valcheck = make_timestamp();
- write_record( drec );
- do_sync();
+ /* If n is nonrevocable and unexpired and signode isn't,
+ then take n. Again, it doesn't matter which is older: if
+ n was older then we don't want to take signode as n is
+ nonrevocable. If signode was older then we're
+ automatically fine. */
+
+ if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
+ !signode->pkt->pkt.signature->flags.revocable &&
+ (signode->pkt->pkt.signature->expiredate==0 ||
+ signode->pkt->pkt.signature->expiredate>curtime))) &&
+ ((IS_UID_SIG(n->pkt->pkt.signature) &&
+ !n->pkt->pkt.signature->flags.revocable &&
+ (n->pkt->pkt.signature->expiredate==0 ||
+ n->pkt->pkt.signature->expiredate>curtime))))
+ {
+ signode = n;
+ sigdate = sig->timestamp;
+ continue;
+ }
+
+ /* At this point, if it's newer, it goes in as the only
+ remaining possibilities are signode and n are both either
+ revocable or expired or both nonrevocable and unexpired.
+ If the timestamps are equal take the later ordered
+ packet, presuming that the key packets are hopefully in
+ their original order. */
+
+ if (sig->timestamp >= sigdate)
+ {
+ signode = n;
+ sigdate = sig->timestamp;
+ }
+ }
+ sig = signode->pkt->pkt.signature;
+ if (IS_UID_SIG (sig))
+ { /* this seems to be a usable one which is not revoked.
+ * Just need to check whether there is an expiration time,
+ * We do the expired certification after finding a suitable
+ * certification, the assumption is that a signator does not
+ * want that after the expiration of his certificate the
+ * system falls back to an older certification which has a
+ * different expiration time */
+ const byte *p;
+ u32 expire;
+
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
+ expire = p? sig->timestamp + buffer_to_u32(p) : 0;
+
+ if (expire==0 || expire > curtime )
+ {
+ signode->flag |= (1<<8); /* yeah, found a good cert */
+ if (expire && expire < *next_expire)
+ *next_expire = expire;
+ }
+ }
}
-
- release_tn_tree( tree );
- return keytrust;
}
-/****************
- * we have the pubkey record and all needed informations are in the trustdb
- * but nothing more is known.
+/*
+ * Return true if the key is signed by one of the keys in the given
+ * key ID list. User IDs with a valid signature are marked by node
+ * flags as follows:
+ * flag bit 0: There is at least one signature
+ * 1: There is marginal confidence that this is a legitimate uid
+ * 2: There is full confidence that this is a legitimate uid.
+ * 8: Used for internal purposes.
+ * 9: Ditto (in mark_usable_uid_certs())
+ * 10: Ditto (ditto)
+ * This function assumes that all kbnode flags are cleared on entry.
*/
static int
-do_check( TRUSTREC *dr, unsigned *validity,
- const char *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
-{
- if( !dr->r.dir.keylist ) {
- log_error(_("Ooops, no keys\n"));
- return GPGERR_TRUSTDB;
- }
- if( !dr->r.dir.uidlist ) {
- log_error(_("Ooops, no user IDs\n"));
- return GPGERR_TRUSTDB;
+validate_one_keyblock (KBNODE kb, struct key_item *klist,
+ u32 curtime, u32 *next_expire)
+{
+ struct key_item *kr;
+ KBNODE node, uidnode=NULL;
+ PKT_public_key *pk = kb->pkt->pkt.public_key;
+ u32 main_kid[2];
+ int issigned=0, any_signed = 0, fully_count =0, marginal_count = 0;
+
+ keyid_from_pk(pk, main_kid);
+ for (node=kb; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (uidnode && issigned)
+ {
+ if (fully_count >= opt.completes_needed
+ || marginal_count >= opt.marginals_needed )
+ uidnode->flag |= 4;
+ else if (fully_count || marginal_count)
+ uidnode->flag |= 2;
+ uidnode->flag |= 1;
+ any_signed = 1;
+ }
+ uidnode = node;
+ issigned = 0;
+ fully_count = marginal_count = 0;
+ mark_usable_uid_certs (kb, uidnode, main_kid, klist,
+ curtime, next_expire);
+ }
+ else if (node->pkt->pkttype == PKT_SIGNATURE
+ && (node->flag & (1<<8)) )
+ {
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ kr = is_in_klist (klist, sig);
+ if (kr)
+ {
+ if (kr->ownertrust == TRUST_ULTIMATE)
+ fully_count = opt.completes_needed;
+ else if (kr->ownertrust == TRUST_FULLY)
+ fully_count++;
+ else if (kr->ownertrust == TRUST_MARGINAL)
+ marginal_count++;
+ issigned = 1;
+ }
+ }
}
- if( retflgs )
- *retflgs &= ~(16|32); /* reset the 2 special flags */
-
- if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- *validity = 0; /* no need to check further */
- else if( namehash ) {
- /* Fixme: use a cache */
- *validity = verify_key( opt.max_cert_depth, dr, namehash,
- add_fnc, retflgs );
- }
- else if( !add_fnc
- && tdbio_db_matches_options()
- /* FIXME, TODO: This comparision is WRONG ! */
- && dr->r.dir.valcheck
- > tdbio_read_modify_stamp( (dr->r.dir.validity < TRUST_FULLY) )
- && dr->r.dir.validity )
- *validity = dr->r.dir.validity;
- else
- *validity = verify_key( opt.max_cert_depth, dr, NULL,
- add_fnc, retflgs );
-
- if( !(*validity & TRUST_MASK) )
- *validity = TRUST_UNDEFINED;
-
- if( (dr->r.dir.ownertrust & TRUST_FLAG_DISABLED) )
- *validity |= TRUST_FLAG_DISABLED;
-
- if( dr->r.dir.dirflags & DIRF_REVOKED )
- *validity |= TRUST_FLAG_REVOKED;
-
- /* If we have changed some ownertrusts, set the trustdb timestamps
- * and do a sync */
- if( retflgs && (*retflgs & (16|32)) ) {
- tdbio_write_modify_stamp( (*retflgs & 16), (*retflgs & 32) );
- do_sync();
+ if (uidnode && issigned)
+ {
+ if (fully_count >= opt.completes_needed
+ || marginal_count >= opt.marginals_needed )
+ uidnode->flag |= 4;
+ else if (fully_count || marginal_count)
+ uidnode->flag |= 2;
+ uidnode->flag |= 1;
+ any_signed = 1;
}
-
- return 0;
+ return any_signed;
}
-
-/***********************************************
- ********* Change trustdb values **************
- ***********************************************/
-
-int
-update_ownertrust( ulong lid, unsigned new_trust )
-{
- TRUSTREC rec;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- if( DBG_TRUST )
- log_debug("update_ownertrust of %lu from %u to %u\n",
- lid, (unsigned)rec.r.dir.ownertrust, new_trust );
- rec.r.dir.ownertrust = new_trust;
- write_record( &rec );
- do_sync();
- return 0;
-}
-
-
-int
-clear_trust_checked_flag( PKT_public_key *pk )
-{
- TRUSTREC rec;
- int rc;
-
- if( opt.dry_run )
- return 0;
-
- init_trustdb();
- rc = get_dir_record( pk, &rec );
- if( rc )
- return rc;
-
- /* check whether they are already reset */
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) && !rec.r.dir.valcheck )
- return 0;
-
- /* reset the flag */
- rec.r.dir.dirflags &= ~DIRF_CHECKED;
- rec.r.dir.valcheck = 0;
- write_record( &rec );
- do_sync();
- return 0;
-}
-
-
-
-
-
-/***********************************************
- ********* Query trustdb values **************
- ***********************************************/
-
-
-/****************
- * This function simply looks for the key in the trustdb
- * and makes sure that pk->local_id is set to the correct value.
- * Return: 0 = found
- * -1 = not found
- * other = error
- */
-int
-query_trust_record( PKT_public_key *pk )
+static int
+search_skipfnc (void *opaque, u32 *kid)
{
- TRUSTREC rec;
- init_trustdb();
- return get_dir_record( pk, &rec );
+ return test_key_hash_table ((KeyHashTable)opaque, kid);
}
-/****************
- * Get the trustlevel for this PK.
- * Note: This does not ask any questions
- * Returns: 0 okay of an errorcode
- *
- * It operates this way:
- * locate the pk in the trustdb
- * found:
- * Do we have a valid cache record for it?
- * yes: return trustlevel from cache
- * no: make a cache record and all the other stuff
- * not found:
- * try to insert the pubkey into the trustdb and check again
- *
- * Problems: How do we get the complete keyblock to check that the
- * cache record is actually valid? Think we need a clever
- * cache in getkey.c to keep track of this stuff. Maybe it
- * is not necessary to check this if we use a local pubring. Hmmmm.
+/*
+ * Scan all keys and return a key_array of all suitable keys from
+ * kllist. The caller has to pass keydb handle so that we don't use
+ * to create our own. Returns either a key_array or NULL in case of
+ * an error. No results found are indicated by an empty array.
+ * Caller hast to release the returned array.
*/
-int
-check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
- const byte *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
-{
- TRUSTREC rec;
- unsigned trustlevel = TRUST_UNKNOWN;
- int rc=0;
- u32 cur_time;
- u32 keyid[2];
-
-
- init_trustdb();
- keyid_from_pk( pk, keyid );
-
- /* get the pubkey record */
- if( pk->local_id ) {
- read_record( pk->local_id, &rec, RECTYPE_DIR );
- }
- else { /* no local_id: scan the trustdb */
- if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
- log_error(_("check_trust: search dir record failed: %s\n"),
- gpg_errstr(rc));
- return rc;
- }
- else if( rc == -1 && opt.dry_run )
- return GPGERR_GENERAL;
- else if( rc == -1 ) { /* not found - insert */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error(_("key %08lX: insert trust record failed: %s\n"),
- (ulong)keyid[1], gpg_errstr(rc));
- goto leave;
- }
- log_info(_("key %08lX.%lu: inserted into trustdb\n"),
- (ulong)keyid[1], pk->local_id );
- /* and re-read the dir record */
- read_record( pk->local_id, &rec, RECTYPE_DIR );
- }
- }
- cur_time = make_timestamp();
- if( pk->timestamp > cur_time ) {
- log_info(_("key %08lX.%lu: created in future "
- "(time warp or clock problem)\n"),
- (ulong)keyid[1], pk->local_id );
- if( !opt.ignore_time_conflict )
- return GPGERR_TIME_CONFLICT;
- }
+static struct key_array *
+validate_key_list (KEYDB_HANDLE hd, KeyHashTable visited,
+ struct key_item *klist, u32 curtime, u32 *next_expire)
+{
+ KBNODE keyblock = NULL;
+ struct key_array *keys = NULL;
+ size_t nkeys, maxkeys;
+ int rc;
+ KEYDB_SEARCH_DESC desc;
+
+ maxkeys = 1000;
+ keys = m_alloc ((maxkeys+1) * sizeof *keys);
+ nkeys = 0;
+
+ rc = keydb_search_reset (hd);
+ if (rc)
+ {
+ log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ desc.skipfnc = search_skipfnc;
+ desc.skipfncvalue = visited;
+ rc = keydb_search (hd, &desc, 1);
+ if (rc == -1)
+ {
+ keys[nkeys].keyblock = NULL;
+ return keys;
+ }
+ if (rc)
+ {
+ log_error ("keydb_search_first failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
+ do
+ {
+ PKT_public_key *pk;
+
+ rc = keydb_get_keyblock (hd, &keyblock);
+ if (rc)
+ {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
+ }
+
+ if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+ {
+ log_debug ("ooops: invalid pkttype %d encountered\n",
+ keyblock->pkt->pkttype);
+ dump_kbnode (keyblock);
+ release_kbnode(keyblock);
+ continue;
+ }
- if( !(rec.r.dir.dirflags & DIRF_CHECKED) )
- check_trust_record( &rec, 0 );
- else if( rec.r.dir.checkat && rec.r.dir.checkat <= cur_time )
- check_trust_record( &rec, 0 );
- else if( (rec.r.dir.dirflags & DIRF_NEWKEYS) )
- check_trust_record( &rec, 1 );
-
- if( pk->expiredate && pk->expiredate <= cur_time ) {
- log_info(_("key %08lX.%lu: expired at %s\n"),
- (ulong)keyid[1], pk->local_id,
- asctimestamp( pk->expiredate) );
- trustlevel = TRUST_EXPIRED;
- }
- else {
- rc = do_check( &rec, &trustlevel, namehash, add_fnc, retflgs );
- if( rc ) {
- log_error(_("key %08lX.%lu: trust check failed: %s\n"),
- (ulong)keyid[1], pk->local_id, gpg_errstr(rc));
- return rc;
- }
- }
+ /* prepare the keyblock for further processing */
+ merge_keys_and_selfsig (keyblock);
+ clear_kbnode_flags (keyblock);
+ pk = keyblock->pkt->pkt.public_key;
+ if (pk->has_expired || pk->is_revoked)
+ {
+ /* it does not make sense to look further at those keys */
+ mark_keyblock_seen (visited, keyblock);
+ }
+ else if (validate_one_keyblock (keyblock, klist, curtime, next_expire))
+ {
+ if (pk->expiredate && pk->expiredate >= curtime
+ && pk->expiredate < *next_expire)
+ *next_expire = pk->expiredate;
+
+ if (nkeys == maxkeys) {
+ maxkeys += 1000;
+ keys = m_realloc (keys, (maxkeys+1) * sizeof *keys);
+ }
+ keys[nkeys++].keyblock = keyblock;
+ /* this key is signed - don't check it again */
+ mark_keyblock_seen (visited, keyblock);
+ keyblock = NULL;
+ }
- /* is a subkey has been requested, we have to check its keyflags */
- if( !rc ) {
- TRUSTREC krec;
- byte fpr[MAX_FINGERPRINT_LEN] = {0}; /* to avoid compiler warnings */
- size_t fprlen = 0;
- ulong recno;
- int kcount=0;
-
- for( recno = rec.r.dir.keylist; recno; recno = krec.r.key.next ) {
- read_record( recno, &krec, RECTYPE_KEY );
- if( ++kcount == 1 )
- continue; /* skip the primary key */
- if( kcount == 2 ) /* now we need the fingerprint */
- fingerprint_from_pk( pk, fpr, &fprlen );
-
- if( krec.r.key.fingerprint_len == fprlen
- && !memcmp( krec.r.key.fingerprint, fpr, fprlen ) ) {
- /* found the subkey */
- if( (krec.r.key.keyflags & KEYF_REVOKED) )
- trustlevel |= TRUST_FLAG_SUB_REVOKED;
- /* should we check for keybinding here??? */
- /* Hmmm: Maybe this whole checking stuff should not go
- * into the trustdb, but be done direct from the keyblock.
- * Chnage this all when we add an abstarction layer around
- * the way certificates are handled by different standards */
- break;
- }
- }
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ }
+ while ( !(rc = keydb_search (hd, &desc, 1)) );
+ if (rc && rc != -1)
+ {
+ log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
+ m_free (keys);
+ return NULL;
}
-
- leave:
- if( DBG_TRUST )
- log_debug("check_trust() returns trustlevel %04x.\n", trustlevel);
- *r_trustlevel = trustlevel;
- return 0;
-}
+ keys[nkeys].keyblock = NULL;
+ return keys;
+}
-/****************
- * scan the whole trustdb and mark all signature records whose keys
- * are freshly imported.
- */
static void
-mark_fresh_keys()
-{
- TRUSTREC dirrec, rec;
- ulong recnum, lid;
- int i;
-
- memset( &dirrec, 0, sizeof dirrec );
-
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype != RECTYPE_SIG )
- continue;
- /* if we have already have the dir record, we can check it now */
- if( dirrec.recnum == rec.r.sig.lid
- && (dirrec.r.dir.dirflags & DIRF_NEWKEYS) )
- continue; /* flag is already set */
-
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- if( !(lid=rec.r.sig.sig[i].lid) )
- continue; /* skip deleted sigs */
- if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) )
- continue; /* skip checked signatures */
- if( qry_lid_table_flag( fresh_imported_keys, lid, NULL ) )
- continue; /* not in the list of new keys */
- read_record( rec.r.sig.lid, &dirrec, RECTYPE_DIR );
- if( !(dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) {
- dirrec.r.dir.dirflags |= DIRF_NEWKEYS;
- write_record( &dirrec );
- }
- break;
- }
- }
-
- do_sync();
-
- clear_lid_table( fresh_imported_keys );
- fresh_imported_keys_count = 0;
-}
-
-
-
-int
-query_trust_info( PKT_public_key *pk, const byte *namehash )
-{
- unsigned trustlevel;
- int c;
-
- init_trustdb();
- if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) )
- return '?';
- if( trustlevel & TRUST_FLAG_DISABLED )
- return 'd';
- if( trustlevel & TRUST_FLAG_REVOKED )
- return 'r';
- c = trust_letter( (trustlevel & TRUST_MASK) );
- if( !c )
- c = '?';
- return c;
-}
-
-
-
-/****************
- * Return the assigned ownertrust value for the given LID
- */
-unsigned
-get_ownertrust( ulong lid )
-{
- TRUSTREC rec;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- return rec.r.dir.ownertrust;
-}
-
-int
-get_ownertrust_info( ulong lid )
-{
- unsigned otrust;
- int c;
-
- init_trustdb();
- otrust = get_ownertrust( lid );
- c = trust_letter( (otrust & TRUST_MASK) );
- if( !c )
- c = '?';
- return c;
-}
-
-
-
-void
-list_trust_path( const char *username )
-{
- int rc;
- ulong lid;
- TRUSTREC rec;
- TN tree;
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
-
- init_trustdb();
- if( (rc = get_pubkey_byname(NULL, pk, username, NULL )) )
- log_error(_("user '%s' not found: %s\n"), username, gpg_errstr(rc) );
- else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
- log_error(_("problem finding '%s' in trustdb: %s\n"),
- username, gpg_errstr(rc));
- else if( rc == -1 ) {
- log_info(_("user '%s' not in trustdb - inserting\n"), username);
- rc = insert_trust_record_by_pk( pk );
- if( rc )
- log_error(_("failed to put '%s' into trustdb: %s\n"),
- username, gpg_errstr(rc));
- else {
- assert( pk->local_id );
- }
+reset_unconnected_keys (KEYDB_HANDLE hd, KeyHashTable visited)
+{
+ int rc;
+ KBNODE keyblock = NULL;
+ KEYDB_SEARCH_DESC desc;
+ int count = 0, nreset = 0;
+
+ rc = keydb_search_reset (hd);
+ if (rc)
+ {
+ log_error ("keydb_search_reset failed: %s\n", g10_errstr(rc));
+ return;
+ }
+
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+ desc.skipfnc = search_skipfnc;
+ desc.skipfncvalue = visited;
+ rc = keydb_search (hd, &desc, 1);
+ if (rc && rc != -1 )
+ log_error ("keydb_search_first failed: %s\n", g10_errstr(rc));
+ else if (!rc)
+ {
+ desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
+ do
+ {
+ rc = keydb_get_keyblock (hd, &keyblock);
+ if (rc)
+ {
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ break;
+ }
+ count++;
+
+ if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY) /* paranoid assertion*/
+ {
+ nreset += clear_validity (keyblock->pkt->pkt.public_key);
+ release_kbnode (keyblock);
+ }
+ }
+ while ( !(rc = keydb_search (hd, &desc, 1)) );
+ if (rc && rc != -1)
+ log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
}
- lid = pk->local_id;
-
- tree = build_cert_tree( lid, 0, opt.max_cert_depth, NULL );
- if( tree )
- propagate_validity( tree, tree, NULL, NULL );
- if( opt.with_colons )
- dump_tn_tree_with_colons( 0, tree );
- else
- dump_tn_tree( stdout, 0, tree );
- /*printf("(alloced tns=%d max=%d)\n", alloced_tns, max_alloced_tns );*/
- release_tn_tree( tree );
- /*printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
- query_trust_info( pk, NULL ) ); */
-
- free_public_key( pk );
-
-}
+ if (opt.verbose)
+ log_info ("%d unconnected keys (%d trust records cleared)\n",
+ count, nreset);
+ do_sync ();
+}
-
-
-/****************
- * Enumerate all keys, which are needed to build all trust paths for
- * the given key. This function does not return the key itself or
- * the ultimate key (the last point in cerificate chain). Only
- * certificate chains which ends up at an ultimately trusted key
- * are listed. If ownertrust or validity is not NULL, the corresponding
- * value for the returned LID is also returned in these variable(s).
+/*
+ * Run the key validation procedure.
*
- * 1) create a void pointer and initialize it to NULL
- * 2) pass this void pointer by reference to this function.
- * Set lid to the key you want to enumerate and pass it by reference.
- * 3) call this function as long as it does not return -1
- * to indicate EOF. LID does contain the next key used to build the web
- * 4) Always call this function a last time with LID set to NULL,
- * so that it can free its context.
+ * This works this way:
+ * Step 1: Find all ultimately trusted keys (UTK).
+ * mark them all as seen and put them into klist.
+ * Step 2: loop max_cert_times
+ * Step 3: if OWNERTRUST of any key in klist is undefined
+ * ask user to assign ownertrust
+ * Step 4: Loop over all keys in the keyDB which are not marked seen
+ * Step 5: if key is revoked or expired
+ * mark key as seen
+ * continue loop at Step 4
+ * Step 6: For each user ID of that key signed by a key in klist
+ * Calculate validity by counting trusted signatures.
+ * Set validity of user ID
+ * Step 7: If any signed user ID was found
+ * mark key as seen
+ * End Loop
+ * Step 8: Build a new klist from all fully trusted keys from step 6
+ * End Loop
+ * Ready
*
- * Returns: -1 on EOF or the level of the returned LID
- */
-int
-enum_cert_paths( void **context, ulong *lid,
- unsigned *ownertrust, unsigned *validity )
-{
- return -1;
- #if 0
- struct enum_cert_paths_ctx *ctx;
- fixme: ..... tsl;
-
- init_trustdb();
- if( !lid ) { /* release the context */
- if( *context ) {
- FIXME: ........tsl2;
-
- ctx = *context;
- for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
- tsl2 = tsl->next;
- gcry_free( tsl );
- }
- *context = NULL;
- }
- return -1;
- }
-
- if( !*context ) {
- FIXME .... *tmppath;
- TRUSTREC rec;
-
- if( !*lid )
- return -1;
-
- ctx = gcry_xcalloc( 1, sizeof *ctx );
- *context = ctx;
- /* collect the paths */
- #if 0
- read_record( *lid, &rec, RECTYPE_DIR );
- tmppath = gcry_xcalloc( 1, (opt.max_cert_depth+1)* sizeof *tmppath );
- tsl = NULL;
- collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
- gcry_free( tmppath );
- sort_tsl_list( &tsl );
- #endif
- /* setup the context */
- ctx->tsl_head = tsl;
- ctx->tsl = ctx->tsl_head;
- ctx->idx = 0;
- }
- else
- ctx = *context;
-
- while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
- ctx->tsl = ctx->tsl->next;
- ctx->idx = 0;
- }
- tsl = ctx->tsl;
- if( !tsl )
- return -1; /* eof */
-
- if( ownertrust )
- *ownertrust = tsl->path[ctx->idx].otrust;
- if( validity )
- *validity = tsl->path[ctx->idx].trust;
- *lid = tsl->path[ctx->idx].lid;
- ctx->idx++;
- return ctx->idx-1;
- #endif
-}
-
-
-/****************
- * Print the current path
*/
-void
-enum_cert_paths_print( void **context, FILE *fp,
- int refresh, ulong selected_lid )
-{
- return;
- #if 0
- struct enum_cert_paths_ctx *ctx;
- FIXME......... tsl;
-
- if( !*context )
- return;
- init_trustdb();
- ctx = *context;
- if( !ctx->tsl )
- return;
- tsl = ctx->tsl;
-
- if( !fp )
- fp = stderr;
-
- if( refresh ) { /* update the ownertrust and if possible the validity */
- int i;
- int match = tdbio_db_matches_options();
-
- for( i = 0; i < tsl->pathlen; i++ ) {
- TRUSTREC rec;
-
- read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
- tsl->path[i].otrust = rec.r.dir.ownertrust;
- /* update validity only if we have it in the cache
- * calculation is too time consuming */
- if( match && rec.r.dir.valcheck && rec.r.dir.validity ) {
- tsl->path[i].trust = rec.r.dir.validity;
- if( rec.r.dir.dirflags & DIRF_REVOKED )
- tsl->path[i].trust = TRUST_FLAG_REVOKED;
+static int
+validate_keys (int interactive)
+{
+ int rc = 0;
+ int quit=0;
+ struct key_item *klist = NULL;
+ struct key_item *k;
+ struct key_array *keys = NULL;
+ struct key_array *kar;
+ KEYDB_HANDLE kdb = NULL;
+ KBNODE node;
+ int depth;
+ int key_count;
+ int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate;
+ KeyHashTable visited;
+ u32 start_time, next_expire;
+
+ start_time = make_timestamp ();
+ next_expire = 0xffffffff; /* set next expire to the year 2106 */
+ visited = new_key_hash_table ();
+ /* Fixme: Instead of always building a UTK list, we could just build it
+ * here when needed */
+ if (!utk_list)
+ {
+ log_info ("no ultimately trusted keys found\n");
+ goto leave;
+ }
+
+
+ /* mark all UTKs as visited and set validity to ultimate */
+ for (k=utk_list; k; k = k->next)
+ {
+ KBNODE keyblock;
+ PKT_public_key *pk;
+
+ keyblock = get_pubkeyblock (k->kid);
+ if (!keyblock)
+ {
+ log_error (_("public key of ultimately"
+ " trusted key %08lX not found\n"), (ulong)k->kid[1]);
+ continue;
+ }
+ mark_keyblock_seen (visited, keyblock);
+ pk = keyblock->pkt->pkt.public_key;
+ for (node=keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ byte namehash[20];
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+
+ if( uid->attrib_data )
+ rmd160_hash_buffer (namehash,uid->attrib_data,uid->attrib_len);
+ else
+ rmd160_hash_buffer (namehash, uid->name, uid->len );
+ update_validity (pk, namehash, 0, TRUST_ULTIMATE);
+ }
+ }
+ if ( pk->expiredate && pk->expiredate >= start_time
+ && pk->expiredate < next_expire)
+ next_expire = pk->expiredate;
+
+ release_kbnode (keyblock);
+ do_sync ();
+ }
+
+
+ klist = utk_list;
+ kdb = keydb_new (0);
+
+ for (depth=0; depth < opt.max_cert_depth; depth++)
+ {
+ /* See whether we should assign ownertrust values to the keys in
+ utk_list. */
+ ot_unknown = ot_undefined = ot_never = 0;
+ ot_marginal = ot_full = ot_ultimate = 0;
+ for (k=klist; k; k = k->next)
+ {
+ if (interactive && k->ownertrust == TRUST_UNKNOWN)
+ k->ownertrust = ask_ownertrust (k->kid);
+ if (k->ownertrust == -1)
+ {
+ quit=1;
+ goto leave;
}
- }
- }
+ else if (k->ownertrust == TRUST_UNKNOWN)
+ ot_unknown++;
+ else if (k->ownertrust == TRUST_UNDEFINED)
+ ot_undefined++;
+ else if (k->ownertrust == TRUST_NEVER)
+ ot_never++;
+ else if (k->ownertrust == TRUST_MARGINAL)
+ ot_marginal++;
+ else if (k->ownertrust == TRUST_FULLY)
+ ot_full++;
+ else if (k->ownertrust == TRUST_ULTIMATE)
+ ot_ultimate++;
+ }
- print_path( tsl->pathlen, tsl->path, fp, selected_lid );
- #endif
-}
+ /* Find all keys which are signed by a key in kdlist */
+ keys = validate_key_list (kdb, visited, klist, start_time, &next_expire);
+ if (!keys)
+ {
+ log_error ("validate_key_list failed\n");
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
-/*
- * Return an allocated buffer with the preference values for
- * the key with LID and the userid which is identified by the
- * HAMEHASH or the first one if namehash is NULL. ret_n receives
- * the length of the allocated buffer. Structure of the buffer is
- * a repeated sequences of 2 bytes; where the first byte describes the
- * type of the preference and the second one the value. The constants
- * PREFTYPE_xxxx should be used to reference a type.
- */
-byte *
-get_pref_data( ulong lid, const byte *namehash, size_t *ret_n )
-{
- TRUSTREC rec;
- ulong recno;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
- read_record( recno, &rec, RECTYPE_UID );
- if( rec.r.uid.prefrec
- && ( !namehash || !memcmp(namehash, rec.r.uid.namehash, 20) )) {
- byte *buf;
- /* found the correct one or the first one */
- read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
- if( rec.r.pref.next )
- log_info(_("WARNING: can't yet handle long pref records\n"));
- buf = gcry_xmalloc( ITEMS_PER_PREF_RECORD );
- memcpy( buf, rec.r.pref.data, ITEMS_PER_PREF_RECORD );
- *ret_n = ITEMS_PER_PREF_RECORD;
- return buf;
- }
+ for (key_count=0, kar=keys; kar->keyblock; kar++, key_count++)
+ ;
+
+ /* Store the calculated valididation status somewhere */
+ if (opt.verbose > 1)
+ dump_key_array (depth, keys);
+
+ log_info (_("checking at depth %d signed=%d"
+ " ot(-/q/n/m/f/u)=%d/%d/%d/%d/%d/%d\n"),
+ depth, key_count, ot_unknown, ot_undefined,
+ ot_never, ot_marginal, ot_full, ot_ultimate );
+
+ for (kar=keys; kar->keyblock; kar++)
+ store_validation_status (depth, kar->keyblock);
+
+ /* Build a new kdlist from all fully valid keys in KEYS */
+ if (klist != utk_list)
+ release_key_items (klist);
+ klist = NULL;
+ for (kar=keys; kar->keyblock; kar++)
+ {
+ for (node=kar->keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID && (node->flag & 4))
+ {
+ k = new_key_item ();
+ keyid_from_pk (kar->keyblock->pkt->pkt.public_key, k->kid);
+ k->ownertrust = get_ownertrust (kar->keyblock
+ ->pkt->pkt.public_key);
+ k->next = klist;
+ klist = k;
+ break;
+ }
+ }
+ }
+ release_key_array (keys);
+ keys = NULL;
+ if (!klist)
+ break; /* no need to dive in deeper */
+ }
+
+ reset_unconnected_keys (kdb, visited);
+
+ leave:
+ keydb_release (kdb);
+ release_key_array (keys);
+ release_key_items (klist);
+ release_key_hash_table (visited);
+ if (!rc && !quit) /* mark trustDB as checked */
+ {
+ if (next_expire == 0xffffffff || next_expire < start_time )
+ tdbio_write_nextcheck (0);
+ else
+ {
+ tdbio_write_nextcheck (next_expire);
+ log_info (_("next trustdb check due at %s\n"),
+ strtimestamp (next_expire));
+ }
+ do_sync ();
+ pending_check_trustdb = 0;
}
- return NULL;
+ return rc;
}
-
-/****************
- * Check whether the algorithm is in one of the pref records
- */
-int
-is_algo_in_prefs( ulong lid, int preftype, int algo )
-{
- TRUSTREC rec;
- ulong recno;
- int i;
- byte *pref;
-
- init_trustdb();
- read_record( lid, &rec, RECTYPE_DIR );
- for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
- read_record( recno, &rec, RECTYPE_UID );
- if( rec.r.uid.prefrec ) {
- read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
- if( rec.r.pref.next )
- log_info(_("WARNING: can't yet handle long pref records\n"));
- pref = rec.r.pref.data;
- for(i=0; i+1 < ITEMS_PER_PREF_RECORD; i+=2 ) {
- if( pref[i] == preftype && pref[i+1] == algo )
- return 1;
- }
- }
- }
- return 0;
-}
-
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 1279edb0f..c94a2daa1 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -1,5 +1,5 @@
/* trustdb.h - Trust database
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -18,13 +18,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-#ifndef GPG_TRUSTDB_H
-#define GPG_TRUSTDB_H
+#ifndef G10_TRUSTDB_H
+#define G10_TRUSTDB_H
/* Trust values must be sorted in ascending order */
#define TRUST_MASK 15
-#define TRUST_UNKNOWN 0 /* o: not yet calculated */
+#define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */
#define TRUST_EXPIRED 1 /* e: calculation may be invalid */
#define TRUST_UNDEFINED 2 /* q: not enough information for calculation */
#define TRUST_NEVER 3 /* n: never trust this pubkey */
@@ -33,43 +33,37 @@
#define TRUST_ULTIMATE 6 /* u: ultimately trusted */
/* trust values not covered by the mask */
#define TRUST_FLAG_REVOKED 32 /* r: revoked */
-#define TRUST_FLAG_SUB_REVOKED 64
+#define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */
#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
-
-
-#define PREFTYPE_SYM 1
-#define PREFTYPE_HASH 2
-#define PREFTYPE_COMPR 3
-
+#define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
/*-- trustdb.c --*/
-void list_trust_path( const char *username );
void register_trusted_key( const char *string );
-void check_trustdb( const char *username );
-void update_trustdb( void );
+void check_trustdb (void);
+void update_trustdb (void);
int setup_trustdb( int level, const char *dbname );
void init_trustdb( void );
void sync_trustdb( void );
-int check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
- const byte* nh, int (*add_fnc)(ulong), unsigned *retflgs );
-int query_trust_info( PKT_public_key *pk, const byte *nh );
+
+int trust_letter( unsigned value );
+
+void revalidation_mark (void);
+
+unsigned int get_validity (PKT_public_key *pk, const byte *namehash);
+int get_validity_info (PKT_public_key *pk, const byte *namehash);
+
+void list_trust_path( const char *username );
+
int enum_cert_paths( void **context, ulong *lid,
unsigned *ownertrust, unsigned *validity );
void enum_cert_paths_print( void **context, FILE *fp,
int refresh, ulong selected_lid );
-unsigned get_ownertrust( ulong lid );
-int get_ownertrust_info( ulong lid );
-byte *get_pref_data( ulong lid, const byte *namehash, size_t *ret_n );
-int is_algo_in_prefs( ulong lid, int preftype, int algo );
-int keyid_from_lid( ulong lid, u32 *keyid );
-ulong lid_from_keyblock( KBNODE keyblock );
-int query_trust_record( PKT_public_key *pk );
-int clear_trust_checked_flag( PKT_public_key *pk );
-int update_trust_record( KBNODE keyblock, int fast, int *modified );
-int insert_trust_record( KBNODE keyblock );
-int insert_trust_record_by_pk( PKT_public_key *pk );
-int update_ownertrust( ulong lid, unsigned new_trust );
-int trust_letter( unsigned value );
+
+unsigned int get_ownertrust (PKT_public_key *pk);
+int get_ownertrust_info (PKT_public_key *pk);
+void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
+int clear_ownertrust (PKT_public_key *pk);
+
/*-- tdbdump.c --*/
void list_trustdb(const char *username);
@@ -77,6 +71,6 @@ void export_ownertrust(void);
void import_ownertrust(const char *fname);
/*-- pkclist.c --*/
-int edit_ownertrust( ulong lid, int mode );
+int edit_ownertrust (PKT_public_key *pk, int mode );
-#endif /*GPG_TRUSTDB_H*/
+#endif /*G10_TRUSTDB_H*/
diff --git a/g10/verify.c b/g10/verify.c
index f3f9a36eb..7ab20c140 100644
--- a/g10/verify.c
+++ b/g10/verify.c
@@ -1,5 +1,5 @@
/* verify.c - verify signed data
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,13 +24,14 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <unistd.h> /* for isatty() */
-#include <gcrypt.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
+#include "memory.h"
#include "util.h"
#include "main.h"
#include "status.h"
@@ -60,13 +61,38 @@ verify_signatures( int nfiles, char **files )
STRLIST sl;
memset( &afx, 0, sizeof afx);
+ /* decide whether we should handle a detached or a normal signature,
+ * which is needed so that the code later can hash the correct data and
+ * not have a normal signature act as detached signature and ignoring the
+ * indended signed material from the 2nd file or stdin.
+ * 1. gpg <file - normal
+ * 2. gpg file - normal (or detached)
+ * 3. gpg file <file2 - detached
+ * 4. gpg file file2 - detached
+ * The question is how decide between case 2 and 3? The only way
+ * we can do it is by reading one byte from stdin and the unget
+ * it; the problem here is that we may be reading from the
+ * terminal (which could be detected using isatty() but won't work
+ * when under contol of a pty using program (e.g. expect)) and
+ * might get us in trouble when stdin is used for another purpose
+ * (--passphrase-fd 0). So we have to break with the behaviour
+ * prior to gpg 1.0.4 by assuming that case 3 is a normal
+ * signature (where file2 is ignored and require for a detached
+ * signature to indicate signed material comes from stdin by using
+ * case 4 with a file2 of "-".
+ *
+ * Actually we don't have to change anything here but can handle
+ * that all quite easily in mainproc.c
+ */
+
+
sigfile = nfiles? *files : NULL;
/* open the signature file */
fp = iobuf_open(sigfile);
if( !fp ) {
log_error(_("can't open `%s'\n"), print_fname_stdin(sigfile));
- return GPGERR_OPEN_FILE;
+ return G10ERR_OPEN_FILE;
}
if( !opt.no_armor && use_armor_filter( fp ) )
@@ -89,13 +115,13 @@ verify_signatures( int nfiles, char **files )
}
-static void
+void
print_file_status( int status, const char *name, int what )
{
- char *p = gcry_xmalloc(strlen(name)+10);
+ char *p = m_alloc(strlen(name)+10);
sprintf(p, "%d %s", what, name );
write_status_text( status, p );
- gcry_free(p);
+ m_free(p);
}
@@ -111,7 +137,7 @@ verify_one_file( const char *name )
if( !fp ) {
print_file_status( STATUS_FILE_ERROR, name, 1 );
log_error(_("can't open `%s'\n"), print_fname_stdin(name));
- return GPGERR_OPEN_FILE;
+ return G10ERR_OPEN_FILE;
}
if( !opt.no_armor ) {
@@ -145,7 +171,7 @@ verify_files( int nfiles, char **files )
lno++;
if( !*line || line[strlen(line)-1] != '\n' ) {
log_error(_("input line %u too long or missing LF\n"), lno );
- return GPGERR_GENERAL;
+ return G10ERR_GENERAL;
}
/* This code does not work on MSDOS but how cares there are
* also no script languages available. We don't strip any
@@ -161,4 +187,3 @@ verify_files( int nfiles, char **files )
}
return 0;
}
-