diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 7014 | ||||
-rw-r--r-- | g10/Makefile.am | 123 | ||||
-rw-r--r-- | g10/armor.c | 1322 | ||||
-rw-r--r-- | g10/build-packet.c | 1167 | ||||
-rw-r--r-- | g10/cipher.c | 152 | ||||
-rw-r--r-- | g10/compress.c | 310 | ||||
-rw-r--r-- | g10/decrypt.c | 138 | ||||
-rw-r--r-- | g10/delkey.c | 221 | ||||
-rw-r--r-- | g10/encode.c | 798 | ||||
-rw-r--r-- | g10/exec.c | 617 | ||||
-rw-r--r-- | g10/exec.h | 23 | ||||
-rw-r--r-- | g10/export.c | 350 | ||||
-rw-r--r-- | g10/filter.h | 142 | ||||
-rw-r--r-- | g10/free-packet.c | 547 | ||||
-rw-r--r-- | g10/g10.c | 2816 | ||||
-rw-r--r-- | g10/getkey.c | 2476 | ||||
-rw-r--r-- | g10/gpgv.c | 374 | ||||
-rw-r--r-- | g10/import.c | 1796 | ||||
-rw-r--r-- | g10/kbnode.c | 399 | ||||
-rw-r--r-- | g10/keydb.c | 686 | ||||
-rw-r--r-- | g10/keydb.h | 265 | ||||
-rw-r--r-- | g10/keyedit.c | 3281 | ||||
-rw-r--r-- | g10/keygen.c | 2429 | ||||
-rw-r--r-- | g10/keyid.c | 502 | ||||
-rw-r--r-- | g10/keylist.c | 1116 | ||||
-rw-r--r-- | g10/keyring.c | 1558 | ||||
-rw-r--r-- | g10/keyring.h | 45 | ||||
-rw-r--r-- | g10/keyserver.c | 1264 | ||||
-rw-r--r-- | g10/main.h | 224 | ||||
-rw-r--r-- | g10/mainproc.c | 1656 | ||||
-rw-r--r-- | g10/misc.c | 548 | ||||
-rw-r--r-- | g10/openfile.c | 362 | ||||
-rw-r--r-- | g10/options.h | 208 | ||||
-rw-r--r-- | g10/options.skel | 203 | ||||
-rw-r--r-- | g10/packet.h | 494 | ||||
-rw-r--r-- | g10/parse-packet.c | 2260 | ||||
-rw-r--r-- | g10/passphrase.c | 1164 | ||||
-rw-r--r-- | g10/photoid.c | 332 | ||||
-rw-r--r-- | g10/photoid.h | 14 | ||||
-rw-r--r-- | g10/pkclist.c | 1303 | ||||
-rw-r--r-- | g10/plaintext.c | 418 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 296 | ||||
-rw-r--r-- | g10/revoke.c | 717 | ||||
-rw-r--r-- | g10/seckey-cert.c | 382 | ||||
-rw-r--r-- | g10/sig-check.c | 619 | ||||
-rw-r--r-- | g10/sign.c | 1300 | ||||
-rw-r--r-- | g10/signal.c | 217 | ||||
-rw-r--r-- | g10/status.c | 693 | ||||
-rw-r--r-- | g10/status.h | 126 | ||||
-rw-r--r-- | g10/tdbio.c | 1578 | ||||
-rw-r--r-- | g10/tdbio.h | 111 | ||||
-rw-r--r-- | g10/textfilter.c | 235 | ||||
-rw-r--r-- | g10/trustdb.c | 1642 | ||||
-rw-r--r-- | g10/trustdb.h | 76 | ||||
-rw-r--r-- | g10/verify.c | 189 |
55 files changed, 0 insertions, 49298 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog deleted file mode 100644 index d4221d1c3..000000000 --- a/g10/ChangeLog +++ /dev/null @@ -1,7014 +0,0 @@ -2002-10-17 Werner Koch <wk@gnupg.org> - - * pkclist.c (do_edit_ownertrust): Show all user IDs. This should - be enhanced to also show the current trust level. Suggested by - Florian Weimer. - -2002-10-17 David Shaw <dshaw@jabberwocky.com> - - * g10.c (main): Handle --strict and --no-strict from the command - line before the options file is loaded. - -2002-10-15 David Shaw <dshaw@jabberwocky.com> - - * g10.c (main): Disable --textmode when encrypting (symmetric or - pk) in --pgp2 mode as PGP 2 can't handle the unknown length - literal packet. Reported by Michael Richardson. - -2002-10-14 David Shaw <dshaw@jabberwocky.com> - - * keyserver-internal.h, keyserver.c (print_keyrec, parse_keyrec, - show_prompt, keyserver_search_prompt, keyserver_spawn): Go to - version 1 of the keyserver protocol. This is a better design, - similar to --with-colons, that allows for keys with multiple user - IDs rather than using multiple keys. It also matches the machine - readable pksd format. Also use a prettier --search-keys listing - format that can fill different size windows (currently set at 24 - lines). - -2002-10-12 Werner Koch <wk@gnupg.org> - - * keygen.c (print_status_key_created): New. - (do_generate_keypair): Use it to print the fingerprint. - (generate_subkeypair): Likewise. - -2002-10-11 David Shaw <dshaw@jabberwocky.com> - - * keyedit.c (menu_addrevoker): Properly back out if the signature - fails. Also, do not allow appointing the same revoker twice, and - report ALREADY_SIGNED if the user tries it. - -2002-10-07 David Shaw <dshaw@jabberwocky.com> - - * import.c (import_keys_internal): Missed one s/inp/inp2/. - - * keylist.c (print_capabilities): Properly indicate per-key - capabilities of sign&encrypt primary keys that have - secret-parts-missing (i.e. no capabilities at all) - - * mainproc.c (symkey_decrypt_sesskey): Fix compiler warning. - -2002-10-04 David Shaw <dshaw@jabberwocky.com> - - * getkey.c (get_pubkey_direct): Don't cache keys retrieved via - this function as they may not have all their fields filled in. - - * sig-check.c (signature_check2): Use new is_primary flag to check - rather than comparing main_keyid with keyid as this still works in - the case of a not fully filled in pk. - -2002-10-04 Werner Koch <wk@gnupg.org> - - * import.c (import_keys_internal): s/inp/inp2/ to avoid shadowing - warning. - - * passphrase.c (agent_get_passphrase): Fixed signed/unsigned char - problem in %-escaping. Noted by Ingo Klöcker. - -2002-10-03 David Shaw <dshaw@jabberwocky.com> - - * options.h, g10.c (main): Add --strict and --no-strict to switch - the log_warning severity level from info to error. - - * keylist.c (print_capabilities): Secret-parts-missing keys should - show that fact in the capabilities, and only primary signing keys - can certify other keys. - - * packet.h, parse_packet.c (parse_key): Add is_primary flag for - public keys (it already exists for secret keys). - -2002-10-02 David Shaw <dshaw@jabberwocky.com> - - * import.c (import_secret_one): Check for an illegal (>110) - protection cipher when importing a secret key. - - * keylist.c (list_keyblock_print): Show a '#' for a - secret-parts-missing key. - - * parse_packet.c (parse_key): Some comments. - - * revoke.c (gen_revoke): Remove some debugging code. - - * trustdb.c (verify_own_keys): Make trusted-key a non-deprecated - option again. - - * seckey-cert.c (do_check): Don't give the IDEA warning unless the - cipher in question is in fact IDEA. - -2002-10-01 David Shaw <dshaw@jabberwocky.com> - - * import.c (import_one): Make sure that a newly imported key - starts with a clean ownertrust. - -2002-10-01 Werner Koch <wk@gnupg.org> - - * getkey.c (get_pubkey_direct): New. - (merge_selfsigs_main): Use it here to look for an ultimately - trusted key. Using the full get_pubkey might lead to an - infinitive recursion. - -2002-09-29 David Shaw <dshaw@jabberwocky.com> - - * keyserver.c (parse_keyserver_uri): Force the keyserver URI - scheme to lowercase to be case-insensitive. - -2002-09-28 David Shaw <dshaw@jabberwocky.com> - - * export.c (do_export_stream): Comment. - - * sig-check.c (check_key_signature2): Properly handle a - non-designated revocation import. - -2002-09-26 Werner Koch <wk@gnupg.org> - - * g10.c (set_homedir): New. Changed all direct assignments to use - this. - * gpgv.c (set_homedir): Ditto. - -2002-09-25 David Shaw <dshaw@jabberwocky.com> - - * Makefile.am: Link gpg with EGDLIBS (i.e. NETLIBS) as EGD uses - sockets. Remove the old NETLIBS variable since the keyserver - stuff is no longer internal. - -2002-09-24 David Shaw <dshaw@jabberwocky.com> - - * import.c (import_keys_stream): Fix compiler type warning. - - * keyring.c (keyring_rebuild_cache), sig-check.c - (check_key_signature2), import.c (import, chk_self_sigs): Minor - language cleanups. - -2002-09-23 Stefan Bellon <sbellon@sbellon.de> - - * main.h: Introduced fast-import as import option. Removed - fast as separate option from prototypes. - * import.c (parse_import_options): Added fast-import option. - (import_*): Removed fast as separate option. - * g10.c (main): Added option fast-import, removed old fast - as separate argument. - * keyserver.c (keyserver_spawn): Removed old fast as separate - argument. - -2002-09-22 Stefan Bellon <sbellon@sbellon.de> - - * import.c (import_keys, import_keys_stream, - import_keys_internal): Added trustdb update/check to key import if - not fast-import and interactive set/no-auto-check-trustdb unset. - Avoided function clone by introducing import_keys_internal. - -2002-09-19 David Shaw <dshaw@jabberwocky.com> - - * keyserver.c (keyserver_spawn): Properly handle line truncation. - Don't leak memory (~10-20 bytes) on searches. - (keyserver_search_prompt): Cleanup. - - * keylist.c (list_keyblock_colon): Show 1F direct key signatures - in --with-colons listing. - -2002-09-16 David Shaw <dshaw@jabberwocky.com> - - * keyedit.c (menu_addrevoker): The direct key signature for - revocation keys must be at least v4 to carry the revocation key - subpacket. Add a PGP 2.x warning for revocation keys. - -2002-09-14 David Shaw <dshaw@jabberwocky.com> - - * g10.c (check_permissions): Rearrange strings to make translating - easier (don't incorporate string parts). - - * keyedit.c (sign_uids): Make strings translatable. - - * sig-check.c (check_key_signature2): Make string translatable. - -2002-09-13 David Shaw <dshaw@jabberwocky.com> - - * getkey.c (check_revocation_keys): Move.... - * main.h, sig-check.c (check_revocation_keys): to here. Also - return the signature_check error code rather than 0/1 and cache - the sig result. - - * sig-check.c (check_key_signature2): Divert to - check_revocation_keys if a revocation sig is made by someone other - than the pk owner. - - * getkey.c (merge_selfsigs_main): Tidy. - -2002-09-13 Werner Koch <wk@gnupg.org> - - * g10.c (main) [__MINGW32__]: Activate oLoadExtension. - -2002-09-12 David Shaw <dshaw@jabberwocky.com> - - * Makefile.am, hkp.c, hkp.h, keyserver.c (keyserver_work): Remove - internal HKP support. - - * keyserver.c (keyserver_spawn): Remove whitespace after keyserver - commands. - -2002-09-10 David Shaw <dshaw@jabberwocky.com> - - * exec.c (expand_args): Remove loop left over from earlier - implementation. - (exec_write): Missed one tick. - -2002-09-10 Werner Koch <wk@gnupg.org> - - * g10.c, options.h: Removed option --emulate-checksum-bug. - * misc.c (checksum_u16_nobug): Removed. - (checksum_u16): Removed the bug emulation. - (checksum_mpi): Ditto. - (checksum_mpi_counted_nbits): Removed and replaced all calls - with checksum_mpi. - - * parse-packet.c (read_protected_v3_mpi): New. - (parse_key): Use it here to store it as an opaque MPI. - * seckey-cert.c (do_check): Changed the v3 unprotection to the new - why to store these keys. - (protect_secret_key): Likewise. - * build-packet.c (do_secret_key): And changed the writing. - - * tdbio.c (tdbio_set_dbname, open_db): Use new macro MY_O_BINARY - to avoid silly ifdefs. - (open_db): Fallback to RDONLY so that gpg may be used from a - RO-medium. - - * encode.c (encode_simple): Make sure we don't use an ESK packet - when we don't have a salt in the S2K. - - * misc.c (pct_expando) <case f>: Make sure that LEN is initialized. - - * exec.c (exec_finish): Use ticks to denote filenames in messages. - (make_tempdir, exec_write): Changed format of messages. - - * keyserver.c (print_keyinfo): Release USERID in on error. - (keyserver_work) [!DISABLE_KEYSERVER_HELPERS]: Exclude the unused - code. - -2002-09-09 Werner Koch <wk@gnupg.org> - - * parse-packet.c (make_attribute_uidname): Add new ar MAX_NAMELEN - for sanity checks. Changed both callers. Limit the size of an %s. - - * options.skel: Comment lock-once out, so that this file does not - change anything when copied to a new home directory. - * openfile.c (try_make_homedir): Don't exit after copying the - option skeleton. - - * options.h: Don't use a comma when declaring variables over more - than one line. - - * mainproc.c (symkey_decrypt_sesskey): Check length of the session - key. - - * hkp.c (dehtmlize): Use ascii_tolower to protect against weird - locales. Cast the argument for isspace for the sake of broken - HP/UXes. - (parse_hkp_index): s/ascii_memcasecmp/ascii_strncasecmp/. - - * g10.c: Removed option --emulate-3des-s2k-bug. - - * passphrase.c (hash_passphrase): Was used here. - - * export.c (parse_export_options) - * keyserver.c (parse_keyserver_options) - * import.c (parse_import_options) - * g10.c (check_permissions): s/ascii_memcasecmp/ascii_strncasecmp/. - -2002-09-09 David Shaw <dshaw@jabberwocky.com> - - * g10.c (add_group): Use '=' to separate group name from group - members. Use a better error message for when no = is found. - - * hkp.c (hkp_export): Use CRLF in headers. - -2002-09-03 David Shaw <dshaw@jabberwocky.com> - - * mainproc.c (print_pkenc_list): Don't increment the error counter - when printing the list of keys a message was encrypted to. This - would make gpg give a non-zero exit code even for completely valid - messages if the message was encrypted to more than one key that - the user owned. - -2002-09-02 Werner Koch <wk@gnupg.org> - - * g10.c (main): Try to set a default character set. Print the - used one in verbosity level 3. - * gpgv.c (main): Try to set a default character set. - - * status.c, status.h (STATUS_IMPORT_OK): New. - * import.c (import_one,import_secret_one): Print new status. - -2002-08-30 David Shaw <dshaw@jabberwocky.com> - - * pkclist.c (build_pk_list): Add new status code to indicate an - untrusted user. This (or a disabled key) fail with "unavailable - pubkey" (G10ERR_UNU_PUBKEY). - - * pkclist.c (build_pk_list): Fail if any recipient keys are - unusable. - - * options.skel: The PGP LDAP keyserver is back. Use MIT keyserver - as a sample rather than cryptnet as cryptnet does not support - searching yet. - - * keyedit.c (show_key_with_all_names): Fix error message - (preferences are userid/selfsig and not key specific). - -2002-08-30 Werner Koch <wk@gnupg.org> - - * pkclist.c (do_we_trust_pre): Changed the wording of a warning. - - * encode.c (encode_simple,encode_crypt): Use new style CTB for - compressssed packets when using MDC. We need to do this so that - concatenated messages are properly decrypted. Old style - compression assumes that it is the last packet; given that we - can't determine the length in advance, the uncompressor does not - know where to start. Actually we should use the new CTB always - but this would break PGP 2 compatibility. - - * parse-packet.c (parse): Special treatment for new style CTB - compressed packets. - - * build-packet.c (do_mdc): Removed. Was not used. - (do_encrypted_mdc): Count in the version number and the MDC packet. - -2002-08-28 David Shaw <dshaw@jabberwocky.com> - - * sig-check.c (do_check_messages, do_check): Show keyid in error - messages. - - * keyserver.c (print_keyinfo): More readable key listings for - --search-keys responses. - -2002-08-26 David Shaw <dshaw@jabberwocky.com> - - * hkp.c (parse_hkp_index, dehtmlize): Move HTML functionality into - new "dehtmlize" function. Remove HTML before trying to parse each - line from the keyserver. If the keyserver provides key type - information in the listing, use it. - -2002-08-23 David Shaw <dshaw@jabberwocky.com> - - * sig-check.c (do_check, do_check_messages): Emit the usual sig - warnings even for cached sigs. This also serves to protect - against missing a sig expiring while cached. - - * getkey.c (merge_selfsigs_main): Don't check UID self-sigs twice. - -2002-08-22 David Shaw <dshaw@jabberwocky.com> - - * import.c (clean_subkeys, chk_self_sigs): Merge clean_subkeys - into chk_self_sigs. This improves efficiency as the same - signatures are not checked multiple times. Clarify when a subkey - is revoked (any revocation signature, even if it is dated before - the binding signature). - - * getkey.c (merge_selfsigs_subkey): Subkey revocation comments. - - * keylist.c (list_one): Stats are only for public key listings. - - * g10.c (main), options.skel: Default should be include-revoked - for keyserver operations. - -2002-08-21 Werner Koch <wk@gnupg.org> - - * import.c (import_print_stats): Print new non_imported counter - which is currently not used because we terminate on errors. - -2002-08-20 David Shaw <dshaw@jabberwocky.com> - - * options.skel: Document no-include-attributes for - keyserver-options. - - * keylist.c, keyedit.c, keyserver.c, sign.c: Some TODOs and - comments. - - * export.c (do_export_stream): Fix noop bug in exporting sensitive - revocation keys. - - * pkclist.c (do_edit_ownertrust): Comment out the option for - showing trust paths until it can be implemented. - -2002-08-19 Werner Koch <wk@gnupg.org> - - * getkey.c (get_user_id_native): Renamed to .. - (get_user_id_printable): this. Filter out all dangerous - characters. Checked all usages. - (get_user_id_string_native): Renamed to.. - (get_user_id_string_printable): this. Filter out all dangerous - characters. Checked all usages. - * keyedit.c (show_basic_key_info): New. - * keylist.c (print_fingerprint): New mode 3. - * import.c (import_one): Use new function to display the user ID. - -2002-08-16 Timo Schulz <ts@winpt.org> - - * g10.c (main): Enable opt.interactive. - - * import.c (import_one): Ask the user if the key shall be - imported when the interactive mode is used. Useful to extract - selected keys from a file. - -2002-08-16 Werner Koch <wk@gnupg.org> - - * seckey-cert.c: Workaround to allow decryption of v3 keys created - with a bug in the mpi_get_secure_buffer. - -2002-08-14 David Shaw <dshaw@jabberwocky.com> - - * hkp.c (parse_hkp_index): Properly handle really large keys - (5 digit key length) in HKP searches. - -2002-08-13 David Shaw <dshaw@jabberwocky.com> - - * encode.c (encode_simple): Fix problem with using compression - algo 2 and symmetric compressed files. - - * encode.c (encode_simple, encode_crypt): If we are not using a - MDC, compress even if a file is already compressed. This is to - help against the chosen ciphertext attack. - - * pkclist.c (select_algo_from_prefs): Fix requested algorithm bug - so the request succeeds even if the requested algorithm is not the - first found. - - * cipher.c (write_header), encode.c (use_mdc, encode_simple, - encode_crypt, encrypt_filter), g10.c (main): Be more eager to use - a MDC. We use a MDC if the keys directly support it, if the keys - list AES (any) or TWOFISH anywhere in the prefs, or if the cipher - chosen does not have a 64 bit blocksize. - -2002-08-08 David Shaw <dshaw@jabberwocky.com> - - * options.skel: Some language tweaks, and remove the - load-extension section for random gatherers. - - * keyring.c (create_tmp_file, rename_tmp_file): Create tmp files - with user-only permissions, but restore the original permissions - if the user has something special set. - - * openfile.c (copy_options_file): Create new options file - (gpg.conf) with user-only permissions. - - * keydb.c (keydb_add_resource): Create new keyrings with user-only - permissions. - - * tdbio.c (tdbio_set_dbname): Create new trustdbs with user-only - permissions. - -2002-08-07 David Shaw <dshaw@jabberwocky.com> - - * sig-check.c (signature_check2): Sanity check that the md has a - context for the hash that the sig is expecting. This can happen - if a onepass sig header does not match the actual sig, and also if - the clearsign "Hash:" header is missing or does not match the - actual sig. - - * keyedit.c (menu_revsig): Properly show a uid is revoked without - restarting gpg. This is Debian bug 124219, though their supplied - patch will not do the right thing. - - * main.h, tdbio.c (tdbio_set_dbname), misc.c (removed - check_permissions), keydb.c (keydb_add_resource), g10.c (main, - check_permissions): Significant reworking of the permission check - mechanism. The new behavior is to check everything in the homedir - by checking the homedir itself. If the user wants to put - (possibly shared) keyrings outside the homedir, they are not - checked. The options file and any extension files are checked - wherever they are, as well as their enclosing directories. This - is Debian bug 147760. - -2002-08-06 Stefan Bellon <sbellon@sbellon.de> - - * g10.c (main): Use of EXTSEP_S in new gpg.conf string. - * openfile.c (copy_options_file): Ditto. - -2002-08-06 David Shaw <dshaw@jabberwocky.com> - - * options.h, g10.c (main), mainproc.c (proc_encrypted): - --ignore-mdc-error option to turn a MDC check error into a - warning. - - * encode.c (encode_crypt), g10.c (main), sign.c (sign_file, - clearsign_file): Use the same --pgpX warning string everywhere to - ease translations. - - * encode.c (write_pubkey_enc_from_list): Warn when using - --throw-keyid with --pgpX. Noted by Vedaal Nistar. - - * revoke.c (export_minimal_pk, gen_desig_revoke, gen_revoke): - Export a minimal pk along with the revocation cert when in --pgpX - mode so that PGP can import it. - -2002-08-06 Werner Koch <wk@gnupg.org> - - * options.skel: Changed comments. - - * g10.c (main): Try to use "gpg.conf" as default option file. - * openfile.c (copy_options_file): Changed name of created file. - -2002-08-02 Werner Koch <wk@gnupg.org> - - * Makefile.am (LDFLAGS): Removed DYNLINK_LDFLAGS. - -2002-07-30 David Shaw <dshaw@jabberwocky.com> - - * options.h, g10.c (main), mainproc.c (proc_encrypted): Return a - decryption failed error if a MDC does not verify. Warn if a MDC - is not present (can disable via --no-mdc-warning). - - * exec.c (exec_write), g10.c (main), keyserver.c - (keyserver_spawn): Use new DISABLE_KEYSERVER_PATH rather than - FIXED_EXEC_PATH. - -2002-07-28 David Shaw <dshaw@jabberwocky.com> - - * sig-check.c (do_check): Properly validate v4 sigs with no hashed - section at all. - -2002-07-25 Werner Koch <wk@gnupg.org> - - * delkey.c (do_delete_key): Always allow to delete a key in batch mode - when specified by fingerprint. Suggested by Enzo Michelangeli. - -2002-07-25 David Shaw <dshaw@jabberwocky.com> - - * keyedit.c (menu_revsig): Change "revsig" to honor selected uids - so the user can revoke sigs from particular uids only. - - * keylist.c (list_keyblock_print): Don't display expired uids in - --list-keys unless -v and not --list-sigs (just like revoked - uids). - - * exec.c, export.c, import.c, keyedit.c, keyserver.c, misc.c: - "Warning" -> "WARNING" - -2002-07-24 David Shaw <dshaw@jabberwocky.com> - - * main.h, import.c (parse_import_options, fix_hkp_corruption, - import_one, delete_inv_parts), g10.c (main): New import-option - "repair-hkp-subkey-bug", which repairs as much as possible the HKP - mangling multiple subkeys bug. It is on by default for keyserver - receives, and off by default for regular --import. - - * main.h, import.c (import, import_one, delete_inv_parts), hkp.c - (hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver - import options when doing keyserver receives. - - * options.h, exec.h, exec.c (set_exec_path, exec_write), g10.c - (main), keyserver.c (keyserver_spawn): If the user does not use - "exec-path", completely replace $PATH with GNUPG_LIBEXECDIR before - calling the keyserver helper. If the user does use "exec-path", - append GNUPG_LIBEXECDIR after the specified path. - -2002-07-23 David Shaw <dshaw@jabberwocky.com> - - * import.c (parse_import_options), export.c - (parse_export_options): Fix offset problem with reversed ("no-") - meanings. - - * import.c (delete_inv_parts): Discard subkey signatures (0x18 and - 0x28) if found in the userid section of the key. - - * sig-check.c (signature_check2): Signatures made by invalid - subkeys (bad/missing binding sig) are also invalid. - - * keylist.c (print_fingerprint): Show the primary as well as the - secondary key fingerprint in modes 1 & 2. - -2002-07-22 David Shaw <dshaw@jabberwocky.com> - - * options.h, main.h, g10.c (main), import.c - (parse_import_options, delete_inv_parts), keyserver.c - (parse_keyserver_options): add new --import-options option. The - only current flag is "allow-local-sigs". - - * g10.c (main): Don't disable MDC in pgp7 mode. - - * options.h, g10.c (main), keyserver.c (parse_keyserver_options): - Remove old keyserver-option include-attributes now that there is - an export-option for the same thing. - - * options.h, main.h, export.c (parse_export_options, - do_export_stream), g10.c (main): add new --export-options option. - Current flags are "include-non-rfc", "include-local-sigs", - "include-attributes", and "include-sensitive-revkeys". - - * options.h, hkp.c (hkp_export), keyserver.c - (parse_keyserver_options, keyserver_spawn): try passing unknown - keyserver options to export options, and if successful, use them - when doing a keyserver --send-key. - - * build-packet.c (build_sig_subpkt): We do not generate - SIGSUBPKT_PRIV_VERIFY_CACHE anymore. - - * revoke.c (gen_desig_revoke): Lots more comments about including - sensitive revkeys along with the revocation sig itself. - - * keyserver.c (parse_keyserver_options): Simpler implementation - that can skip one pass over the options. - -2002-07-18 David Shaw <dshaw@jabberwocky.com> - - * keyedit.c (keyedit_menu, menu_addrevoker): Allow specifying - "sensitive" as an argument to an addrevoker command. This sets - the 0x40 sensitive revoker flag. - - * revoke.c (gen_desig_revoke): When generating a designated - revocation, include the direct key sig that contains the - designated revoker subpacket. This allows sensitive designated - revocation subpackets to be exported. Also indicate which - revokers are sensitive in the first place. - -2002-07-17 David Shaw <dshaw@jabberwocky.com> - - * keyedit.c (show_key_with_all_names_colon): The 0x40 class bit in - a designated revoker means "sensitive", not "local". It's - exportable under the right circumstances. - - * main.h, options.h, export.c (do_export_stream), g10.c (main), - hkp.c (hkp_export), keyserver.c (keyserver_spawn: Add a flag to - skip attribute packets and their signatures while exporting. This - is to accomodate keyservers (pksd again) that choke on attributes. - Use keyserver-option "include-attributes" to control it. This - defaults to ON (i.e. don't skip). - -2002-07-09 David Shaw <dshaw@jabberwocky.com> - - * options.h, keyserver.c (parse_keyserver_uri, keyserver_spawn, - keyserver_work), hkp.c (hkp_ask_import, hkp_export, hkp_search): - Use a much more strict reading of RFC-2396 for the keyserver URIs. - Specifically, don't try and be smart about checking the value of - ":port" so long as it is all digits, and properly handle opaque - data (those scheme specific parts that do not start with "//"). - -2002-07-04 David Shaw <dshaw@jabberwocky.com> - - * photoid.c (get_default_photo_command, show_photos): Honor - FIXED_PHOTO_VIEWER and DISABLE_PHOTO_VIEWER. - - * mainproc.c (check_sig_and_print): Use --show-photos to show - photos when verifying a sig made by a key with a photo. - - * keyserver.c (parse_keyserver_uri): Properly parse a URI with no - :port section and an empty file path, but with a terminating '/'. - (keyserver_work): Honor DISABLE_KEYSERVER_HELPERS. - - * hkp.c (hkp_ask_import): Display keyserver URI as a URI, but only - if verbose. - - * exec.c, g10.c: USE_EXEC_PATH -> FIXED_EXEC_PATH - -2002-07-03 David Shaw <dshaw@jabberwocky.com> - - * exec.h, exec.c (set_exec_path, exec_write), g10.c (main): If - USE_EXEC_PATH is defined at compile time, use it to lock the - exec-path and not allow the user to change it. - -2002-07-02 David Shaw <dshaw@jabberwocky.com> - - * options.h, g10.c (main), keyserver.c (keyserver_refresh): - Maintain and use the original keyserver URI for cosmetics rather - than trying to recreate it when needed. - - * mainproc.c (check_sig_and_print): Properly disregard expired - uids. Make sure that the first uid listed is a real uid and not - an attribute (attributes should only be listed in the "aka" - section). When there are no valid textual userids, try for an - invalid textual userid before using any attribute uid. - -2002-07-01 David Shaw <dshaw@jabberwocky.com> - - * options.skel: Fix a few typos, clarify "group", and remove - sample photo viewers for Win32 since they are the defaults now. - - * parse-packet.c (make_attribute_uidname), keylist.c - (dump_attribs): Fix two typecast warnings. - - * packet.h, build-packet.c (build_attribute_subpkt), exec.c - (expand_args), mkdtemp.c (mkdtemp), photoid.c - (parse_image_header): Fix some signedness compiler warnings. - -2002-07-01 Werner Koch <wk@gnupg.org> - - * photoid.c (get_default_photo_command): Also use __MINGW32__ - instead of HAVE_DOSISH_SYSTEM. - - * encode.c (encode_symmetric): Do not use the new encryption code. - -2002-06-30 Werner Koch <wk@gnupg.org> - - * photoid.c: Use __MINGW32__ to include windows because - HAVE_DOSISH_SYSTEM is also set for OS/2 and plain DOS. Provide - constant missing in older mingw installations. - -2002-06-21 Stefan Bellon <sbellon@sbellon.de> - - * g10.c [__riscos__]: Moved RISC OS specific stuff to util/riscos.c - and include/util.h. - - * gpgv.c [__riscos__]: Likewise. - -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. "&") 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> - - * keygen.c (keygen_set_std_prefs): Put back 3DES because the RFC - says it is good form to do so. - -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. - -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. - -2002-04-02 Werner Koch <wk@gnupg.org> - - * 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. - - * 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. - * 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. - - * keydb.h: Moved KBNODE typedef and MAX_FINGERPRINT_LEN to - * global.h: this new header. - -2001-09-03 Werner Koch <wk@gnupg.org> - - * passphrase.c (agent_get_passphrase): Changed nread to size_t. - (passphrase_clear_cache): Ditto. - - * keyid.c (mk_datestr): Avoid trigraphs. - (fingerprint_from_pk): Cache the keyid in the pk. - - * 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. - - * status.c, status.h: New status INV_RECP. - * pkclist.c (build_pk_list): Issue this status. - -2001-08-31 Werner Koch <wk@gnupg.org> - - * 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. - - * keygen.c (ask_keysize): Do not print the notes about suggested - key sizes if just a DSA key is generated. - - * trustdb.c (add_ultimate_key): s/log_error/log_info/ for - duplicated inserted trusted keys. - -2001-08-07 Werner Koch <wk@gnupg.org> - - * sign.c (sleep): Redefine for W32. - - * 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. - -2001-08-03 Werner Koch <wk@gnupg.org> - - * armor.c (armor_filter): Removed the default comment string - because it could get us in trouble due to translations using non - ascii characters. - -2001-08-01 Werner Koch <wk@gnupg.org> - - * 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. - -2001-01-03 Werner Koch <wk@gnupg.org> - - * status.c, status.h : New status KEY_CREATED - * keygen.c (do_generate_keypair,generate_subkeypair): Emit it. - -2000-12-28 Werner Koch <wk@gnupg.org> - - * 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 cached passphrases. - -2000-11-15 Werner Koch <wk@gnupg.org> - - * status.c (write_status_text): Moved the big switch to ... - (get_status_string): ... new function. - (write_status_buffer): New. - - * status.c (mywrite): New and replaced all write() by this. - - * 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> - - * sign.c (clearsign_file): Use LF macro to print linefeed. - -2000-11-11 Paul Eggert <eggert@twinsun.com> - - 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". - - * 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. - - * parse-packet.c (parse): Do not use %lu to report file - offsets in error diagnostics; it's not portable. - * ringedit.c (keyring_search): Likewise. - -2000-11-09 Werner Koch <wk@gnupg.org> - - * g10.c (main): New option --enable-special-filenames. - -2000-11-07 Werner Koch <wk@gnupg.org> - - * g10.c (main): New command --pipemode. - * pipemode.c: New. - -2000-10-23 Werner Koch <wk@gnupg.org> - - * armor.c (armor_filter): Changed output of hdrlines, so that a CR - is emitted for DOS systems. - - * keygen.c (read_parameter_file): Add a cast for isspace(). - - * status.c (myread): Use SIGINT instead of SIGHUP for DOS. - -2000-10-19 Werner Koch <wk@gnupg.org> - - * g10.c: New option --ignore-crc-error - * armor.c (invalid_crc): New. - (radix64_read): Act on new option. - - * openfile.c (try_make_homedir): Klaus Singvogel fixed a stupid - error introduced on Sep 6th. - -2000-10-18 Werner Koch <wk@gnupg.org> - - * misc.c (print_cipher_algo_note): Don't print the note for AES. - Changed wording. - -2000-10-16 Werner Koch <wk@gnupg.org> - - * 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. - - * mainproc.c (check_sig_and_print): Detect multiple signatures - and don't verify them. - -2000-10-14 Werner Koch <wk@gnupg.org> - - * 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. - -2000-10-13 Werner Koch <wk@gnupg.org> - - * 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. - - * 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. - - * keyedit.c (keyedit_menu): Allow batchmode with a command_fd. - * status.c (my_read): New. - (do_get_from_fd): use it. - -2000-10-12 Werner Koch <wk@gnupg.org> - - * keygen.c (keygen_add_std_prefs): Add Rijndael to the prefs. - -2000-10-07 Werner Koch <wk@gnupg.org> - - * gpgv.c: Add more stubs for ununsed code to make the binary smaller. - -Wed Oct 4 15:50:18 CEST 2000 Werner Koch <wk@openit.de> - - * sign.c (hash_for): New arg to take packet version in account, changed - call callers. - - * gpgv.c: New. - * Makefile.am: Rearranged source files so that gpgv can be build with - at least files as possible. - -Mon Sep 18 12:13:52 CEST 2000 Werner Koch <wk@openit.de> - - * hkp.c (not_implemented): Print a notice for W32 - -Fri Sep 15 18:40:36 CEST 2000 Werner Koch <wk@openit.de> - - * keygen.c (keygen_add_std_prefs): Changed order of preferences to - twofish, cast5, blowfish. - - * pkclist.c (algo_available): Removed hack to disable Twofish. - -Thu Sep 14 17:45:11 CEST 2000 Werner Koch <wk@openit.de> - - * parse-packet.c (dump_sig_subpkt): Dump key flags. Print special - warning in case of faked ARRs. - - * getkey.c (finsih_lookup): Hack so that for v4 RSA keys the subkey - is used for encryption. - -Thu Sep 14 14:20:38 CEST 2000 Werner Koch <wk@openit.de> - - * 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. - - * g10.c (main): Don't set --quite along with --no-tty. By Frank Tobin. - - * 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. - -Wed Sep 13 18:12:34 CEST 2000 Werner Koch <wk@openit.de> - - * keyedit.c (keyedit_menu): Allow to use "debug" on the secret key. - - * ringedit.c (cmp_seckey): Fix for v4 RSA keys. - * seckey-cert.c (do_check): Workaround for PGP 7 bug. - -Wed Sep 6 17:55:47 CEST 2000 Werner Koch <wk@openit.de> - - * 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. - - * encode.c (encode_simple, encode_crypt): Fix for large files. - * sign.c (sign_file): Ditto. - -Wed Sep 6 14:59:09 CEST 2000 Werner Koch <wk@openit.de> - - * passphrase.c (hash_passphrase): Removed funny assert. Reported by - David Mathog. - - * openfile.c (try_make_homedir): Changes for non-Posix systems. - * g10.c (main): Take the default homedir from macro. - - * 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. - -Fri Aug 25 16:05:38 CEST 2000 Werner Koch <wk@openit.de> - - * 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. - -Tue Aug 1 20:06:23 CEST 2000 Werner Koch <wk@openit.de> - - * g10.c: New opttion --try-all-secrets on suggestion from Matthias Urlichs. - * pubkey-enc.c (get_session_key): Quite easy to implement here. - -Thu Jul 27 17:33:04 CEST 2000 Werner Koch <wk@openit.de> - - * 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. - -Thu Jul 27 12:01:00 CEST 2000 Werner Koch <wk@openit.de> - - * 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. - -Thu Jul 27 10:02:38 CEST 2000 Werner Koch <wk@openit.de> - - * 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> - - * helptext.c, pkclist.c: s/superseeded/superseded/ - -Mon Jul 10 16:08:57 CEST 2000 Werner Koch <wk@openit.de> - - * parse-packet.c (enum_sig_subpkt): Fixed testing on crtitical bit in case - of a NULL buffer. Reported by Peter Marschall. - -Wed Jul 5 13:28:45 CEST 2000 Werner Koch <wk@openit.de> - - * keyedit.c, keyid.c: Add some _() - - * argparse.c: Changed the flag to suppress --version handling to also - suppress --help. - -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. - - * mainproc.c (proc_tree): Fixed handling of one-pass-sig packets in textmode. - Disabled the ugly workaround for PGP 5 - let's see whether thi breaks less - cases. Found by Ted Cabeen. - - * options.h (DBG_HASHING): New. All commented md_start_debug are now - controlled by this debug option. - - * sign.c (print_status_sig_created): New and called from 2 places. - - * keygen.c (gen_rsa): New, but commented. - (ask_algo): Commented support for RSA. - - * seckey-cert.c (protect_secret_key): Started to fix the code for v4 RSA - keys - it is not solved yet. However, we have time until, Sep 20th ;) - -Wed Jun 14 12:27:09 CEST 2000 Werner Koch <wk@openit.de> - - * status.c (init_shm_coprocessing): Changed the sequence of the get,attach - to cope with the changes in newer Linux kernels. This bug has been found - by <dmitri@advantrix.com> who also proposed this solution. Hopefully - this does not break gpg on to many systems. - - * cipher.c (write_header): Protect the IV with the MDC too. - * encr-data.c (decrypt_data): Likewise. - -Fri Jun 9 10:09:52 CEST 2000 Werner Koch <wk@openit.de> - - * g10.c: New options --no-auto-key-retrieve - * options.h (auto_key_retrieve): New. - * mainproc.c (check_sig_and_print): Implemented that. - -Wed Jun 7 19:19:09 CEST 2000 Werner Koch <wk@openit.de> - - * 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> - - * cipher.c (write_header): Use plain CFB mode for MDC encrypted packets. - * encr-data.c (decrypt_data): Ditto. - -Mon Jun 5 23:41:54 CEST 2000 Werner Koch <wk@openit.de> - - * seskey.c (do_encode_md, encode_md_value): Add new arg v3compathack to work - around a bug in old versions. - * sig-check.c (do_check): use the aboved workaround when enabled. - * g10.c: New option --emulate-md-decode-bug - -Mon Jun 5 12:37:43 CEST 2000 Werner Koch <wk@openit.de> - - * build-packet.c (do_mdc): New. - (do_encrypted_mdc): Changed for the new proposal. - * parse-packet.c (parse_mdc): New. - (parse_encrypted): Fixed for the new proposal. - * packet.h (PKT_MDC): New. - * cipher.c (cipher_filter): Build the MDC packet here. - * g10.c (main): Enable --force-mdc. - * encr-data.c (mdc_decode_filter): Fixed for new MDC method - - * options.h(rfc2440): New. - * g10.c (main): Changed the selected values for --openpgp to not include - optional algorithms. - -Thu May 18 11:38:54 CEST 2000 Werner Koch <wk@openit.de> - - * keyedit.c (keyedit_menu): Add a keyword arg to the prompt. - - * status.c, status.h: Added 3 new status tokens. - * status.c (do_get_from_fd): New. - (cpr_enabled,cpr_get,cpr_get_hidden,cpr_kill_prompt, - cpr_get_answer_is_yes,cpr_get_answer_yes_no_quit): Modified to work - with the new function. - * g10.c: Add new option --command-fd. - - * status.c (progress_cb): New. - (set_status_fd): Register progress functions - -Fri May 12 14:01:20 CEST 2000 Werner Koch <wk@openit.de> - - * delkey.c (delete_key): Add 2 new status messages - * status.c, status.h (STATUS_DELETE_PROBLEM): New. - - Fixed years of copyright in all source files. - -Mon May 1 17:08:14 CEST 2000 Werner Koch <wk@openit.de> - - * trustdb.c (propagate_validity): Fixed the bug that only one uid - gets fully trusted even when all are signed by an ultimate key. - -Mon May 1 15:38:04 CEST 2000 Werner Koch <wk@openit.de> - - * getkey.c (key_byname): Always returned a defined context. Fixed - a segv for invalid user id specifications. Reported by Walter Koch. - - * getkey.c (get_user_id): I18ned "no user id" string. By Walter. - - * pkclist.c (do_show_revocation_reason): Typo fixes. - * helptext.c: Ditto. - - * armor.c (armor_filter): Fixed some CRLF issues. By Mike McEwan. - -Fri Apr 14 19:37:08 CEST 2000 Werner Koch <wk@openit.de> - - * pkclist.c (do_show_revocation_reason): New. - (show_revocation_reason): New and called at various places. - - * g10.c (main): Fixed small typo. - - * pkclist.c (do_we_trust): Act on always_trust but not for revoked - keys. Suggested by Chip Salzenberg. - - * g10.c: New option --lock-never. - - * ringedit.c (get_writable_keyblock_file): New. - * keygen.c (do_generate_keypair): Use this instead of the hardwired one. - - * keygen.c (ask_user_id): Check that the email address is in the - correct field. Suggested by Christian Kurz. - -Mon Apr 10 13:34:19 CEST 2000 Werner Koch <wk@openit.de> - - * keyedit.c (show_key_with_all_names): s/sbb/ssb/ - -Tue Mar 28 14:26:58 CEST 2000 Werner Koch <wk@openit.de> - - * trustdb.c (verify_own_keys): Do not print warning about unprotected - key when in quiet mode. - -Wed Mar 22 13:50:24 CET 2000 Werner Koch <wk@openit.de> - - * mainproc.c (print_userid): Do UTF8 conversion before printing. - * import.c (import_one): Ditto. - (import_secret_one): Ditto. - (delete_inv_parts): Ditto. - -Thu Mar 16 16:20:23 CET 2000 Werner Koch <wk@openit.de> - - * keylist.c (print_key_data): Handle a NULL pk gracefully. - - * getkey.c (merge_one_pk_and_selfsig): Fixed silly code for - getting the primary keys keyID but kept using the one from the - subkey. - * pubkey-enc.c (get_it): Print a note for expired subkeys. - - * getkey.c (has_expired): New. - (subkeys_expiretime): New. - (finish_lookup): Check for expired subkeys needed for encryption. - (merge_keys_and_selfsig): Fixed expiration date merging for subkeys. - - * keylist.c (list_keyblock): Print expiration time for "sub". - (list_one): Add missing merging for public keys. - * mainproc.c (list_node): Ditto. - -2000-03-14 13:49:38 Werner Koch (wk@habibti.openit.de) - - * keygen.c (keyedit_menu): Do not allow to use certain commands - while the secret key is selected. - -2000-03-09 12:53:09 Werner Koch (wk@habibti.openit.de) - - * keygen.c (ask_expire_interval): Movede parsig to ... - (parse_expire_string): ... this new function. And some new control - commands. - (proc_parameter_file): Add expire date parsing. - (do_generate_keypair): Allow the use of specified output files. - -2000-03-08 10:38:38 Werner Koch (wk@habibti.openit.de) - - * keygen.c (ask_algo): Removed is_v4 return value and the commented - code to create Elg keys in a v3 packet. Removed the rounding - of key sizes here. - (do_create): Likewise removed arg v4_packet. - (gen_elg): Likewise removed arg version. Now rounding keysizes here. - (gen_dsa): Rounding keysize now here. - (release_parameter_list): New - (get_parameter*): New. - (proc_parameter_file): New. - (read_parameter_file): New. - (generate_keypair): Splitted. Now uses read_parameter_file when in - batch mode. Additional argument to specify a parameter file. - (do_generate_keypair): Main bulk of above fucntion and uses the - parameter list. - (do_create): Don't print long notice in batch mode. - * g10.c (main): Allow batched key generation. - -Thu Mar 2 15:37:46 CET 2000 Werner Koch <wk@gnupg.de> - - * pubkey-enc.c (get_it): Print a note about unknown cipher algos. - - * g10.c (opts): Add a note to the help listing about the man page - and removed some options from the help listing. - - * keyedit.c (print_and_check_one_sig): Use a new function to truncate - the output of the user ID. Suggested by Jan-Benedict Glaw. - -Wed Feb 23 10:07:57 CET 2000 Werner Koch <wk@gnupg.de> - - * helptext.c: typo fix. - -Thu Feb 17 13:39:32 CET 2000 Werner Koch <wk@gnupg.de> - - * revoke.c: Removed a bunch of commented code. - - * packet.h (SIGSUBPKT_REVOC_REASON): New. - * build-packet.c (build_sig_subpkt): Support new sub packet. - * parse-packet.c (parse_one_sig_subpkt): Ditto. - (dump_sig_subpkt): Ditto. - * revoke.c (ask_revocation_reason): New. - (release_revocation_reason_info): New. - (revocation_reason_build_cb): New. - (gen_revoke): Ask for reason. - * main.h (struct revocation_reason_info): Add declaration. - * keyedit.c (menu_revsig): Add support for revocation reason. - (menu_revkey): Ditto. - (sign_uid_mk_attrib): Renamed to ... - (sign_mk_attrib): ... this, made static and add support for reasons. - -Tue Feb 15 08:48:13 CET 2000 Werner Koch <wk@gnupg.de> - - * build-packet.c (build_packet): Fixed fixing of old comment packets. - - * import.c (import_keys): Fixed importing from stdin when called with - nnames set to zero as it normally happens. - -Mon Feb 14 14:30:20 CET 2000 Werner Koch <wk@gnupg.de> - - * sig-check.c (check_key_signature2): Add new arg r_expired. - (do_signature_check): New arg to pass it down to ... - (do_check): New arg r-expire which is set when the signature - has expired. - * trustdb.c (check_sig_record): Set SIGF_EXPIRED flag and set - the expiretime to zero so that thi signature will not be checked - anymore. - -Fri Feb 11 17:44:40 CET 2000 Werner Koch <wk@gnupg.de> - - * g10.c (g10_exit): Update the random seed_file. - (main): Set the random seed file. New option --no-random-seed-file. - -Thu Feb 10 17:39:44 CET 2000 Werner Koch <wk@gnupg.de> - - * keyedit.c (menu_expire): Fixed segv due to unitialized sub_pk. - By Rémi. - -Thu Feb 10 11:39:41 CET 2000 Werner Koch <wk@gnupg.de> - - * keylist.c (list_keyblock): Don't print warnings in the middle of - regulat output lines. By Rémi. - - * sig-check.c: Include options.h - -Wed Feb 9 15:33:44 CET 2000 Werner Koch <wk@gnupg.de> - - * gpg.c: New option --ignore-time-conflict - * sig-check.c (do_check): Implemented this option. - * trustdb.c (check_trust): Ditto. - * sign.c (do_sign): Ditto. - * keygen.c (generate_subkeypair): Ditto. - - * encode.c (encode_simple): use iobuf_cancel after open failure. - Reported by Huy Le. - -Fri Jan 14 18:32:01 CET 2000 Werner Koch <wk@gnupg.de> - - * packet.h (STRING2KEY): Changed mode from byte to int. - * parse-packet.c (parse_key): Add the special GNU protection stuff - * build-packet.c (so_secret_key): Ditto. - * seckey-cert.c (do_check): Ditto. - * keyedit.c (change_passphrase): Ditto. - * export.c (export_secsubkeys): New. - (do_export_stream): Hack to export the primary key using mode 1001. - * g10.c: New command --export-secret-subkeys - -Thu Jan 13 19:31:58 CET 2000 Werner Koch <wk@gnupg.de> - - * armor.c (is_armored): Check for 1-pass-sig packets. Reported by - David Hallinan <hallinan@rtd.com>. - (armor_filter): Replaced one LF by the LF macro. Reported by - Wolfgang Redtenbacher. - -Wed Jan 5 11:51:17 CET 2000 Werner Koch <wk@gnupg.de> - - * g10.c (main): Reset new global flag opt.pgp2_workarounds - when --openpgp is used. - * mainproc.c (proc_plaintext): Do the PGP2,5 workarounds only - when the global flag is set. - (proc_tree): Ditto. - * textfilter.c (copy_clearsig_text): Ditto. - * armor.c (armor_filter): Ditto. - - * g10.c: New option --list-only - * mainproc.c (proc_tree): Don't do it if opt.list_only is active. - (proc_pubkey_enc): Implement option. - - * status.h, status.c ({BEGIN,END}_{EN,DE}CRYPTION): New. - * cipher.c (cipher_filter): New status outputs. - * mainproc.c (proc_encrypted): New status outputs. - -Fri Dec 31 14:08:15 CET 1999 Werner Koch <wk@gnupg.de> - - * armor.c (armor_filter): Made the "Comment:" header translatable. - - * hkp.c (hkp_import): Make sure that the program does not return - success when there is a connection problem. Reported by Phillip Jones. - -Sun Dec 19 15:22:26 CET 1999 Werner Koch <wk@gnupg.de> - - * armor.c (LF): Use this new macro at all places where a line LF - is needed. This way DOSish textfiles should be created when the - input data is also in dos mode. - * sign.c (LF): Ditto. - * textfilter.c (LF): Ditto. - (copy_clearsig_text): Disabled the forcing of CR,LF sequences - for DOS systems. - - * plaintext.c (handle_plaintext): Fixes for line endings on DOS. - and react on a LF in cleartext. - * armor.c (fake_packet): Restore the original line ending after - removing trailing spaces. - - * signal.c (got_fatal_signal): DOS fix. - -Thu Dec 16 10:07:58 CET 1999 Werner Koch <wk@gnupg.de> - - * mainproc.c (print_failed_pkenc): Fix for unknown algorithm. - Found by fygrave@epr0.org. - -Thu Dec 9 10:31:05 CET 1999 Werner Koch <wk@gnupg.de> - - * hkp.c: i18n the strings. - -Sat Dec 4 15:32:20 CET 1999 Werner Koch <wk@gnupg.de> - - * trustdb.c (verify_key): Shortcut for ultimately trusted keys. - -Sat Dec 4 12:30:28 CET 1999 Werner Koch <wk@gnupg.de> - - * pkclist.c (build_pk_list): Validate the trust using the namehash - if this one has been set by the key lookup. - - * g10.c: Add --delete-secret-key to the help page. - - * openfile.c (copy_options_file): Made static. - (try_make_homedir): New. - * ringedit.c (add_keyblock_resource): Use the try_make_hoemdir logic. - * tdbio.c (tdbio_set_dbname): Likewise. - - * keygen.c (generate_user_id): Use m_alloc_clear() here. We should - better use an allocation function specific to the user_id packet. - - * keygen.c (keygen_add_std_prefs): Changed symmetric preferences - to include Blowfish again. This is due to it's better speed compared - to CAST5. - - * g10.c (strusage): Print the home directory. - - * armor.c (armor_filter): Take action on the cancel control msg. - * filter.h (armor_filter_context_t): Add cancel flag. - -Mon Nov 29 21:52:11 CET 1999 Werner Koch <wk@gnupg.de> - - * g10.c: New option --fast-list-mode .. - * keylist.c (list_keyblock): .. and implemented. - * mainproc.c (list_node): Ditto. - - * import.c (mark_non_selfsigned_uids_valid): Fixed the case that there - is a uid without any packet following. - -Mon Nov 22 11:14:53 CET 1999 Werner Koch <wk@gnupg.de> - - * mainproc.c (proc_plaintext): Never enable the hash processing - when skip_verify is active. - - * armor.c (parse_header_line): Stop parsing on a WS line too. - Suggested by Aric Cyr. - - * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that - traditional cpp don't mess up the macros. Suggested by Jos Backus. - - * mainproc.c (list_node): Print the PK algo in the --with-colon mode. - * keylist.c (list_keyblock): Ditto. - - * signal.c (got_fatal_signal): Found the reason why exit(8) did not - work - it is better to set the disposition back to default before - raising the signal. Print the notice on stderr always. - -Fri Nov 12 20:33:19 CET 1999 Werner Koch <wk@gnupg.de> - - * g10.c (make_username): Swapped the logic. - * keylist.c (public_key_list): Now takes a STRLIST as arg and moved - the creation ot this list to the caller, so that he can copy with - UTF-conversion of user IDs. Changed all callers. - (secret_key_list): Likewise. - - * getkey.c (get_user_id_string_native): New and ... - * encode.c (write_pubkey_enc_from_list): ... use it here. - - * pubring.asc: Updated. - - * packet.h (PKT_PHOTO_ID): New. - * parse-packet.c (parse_photo_id): New. - * build-packet.c (do_user_id: Handle photo IDs. - (build_packet): Change CTB for photo IDs - * free-packet.c (free_user_id): Release memory used for photo IDs - * sig-check.c (hash_uid_node): Handle photo IDs too. - * trustdb.c (print_uid_from_keyblock): Hash photo ID. - (make_uid_records): Ditto. - * getkey.c (find_by_name): Ditto. - * keyedit.c (show_prefs): Ditto. - * keylist.c (list_keyblock): Ditto. - -Thu Oct 28 16:08:20 CEST 1999 Werner Koch <wk@gnupg.de> - - * keygen.c (ask_expire_interval): Print a warning for systems - with a signed 32 time_t if the exiration time is beyoind 2038. - -Fri Oct 8 20:40:50 CEST 1999 Werner Koch <wk@gnupg.de> - - * ringedit.c (enum_keyblocks): The last fix way really stupid; - reverted and set rt to Unknown. - -Fri Oct 8 20:32:01 CEST 1999 Werner Koch <wk@gnupg.de> - - * ringedit.c (enum_keyblocks): Zero the entire kbpos out on open. - - * g10.c (oEntropyDLL): Removed option. - (main): Made the warning on development versions more verbose. - - * g10.c (oHonorHttpProxy): New option. - * hkp.c (hkp_ask_import,hkp_export): Implement this option. - * options.skel: Enable this option for new installations - -Mon Oct 4 21:23:04 CEST 1999 Werner Koch <wk@gnupg.de> - - * import.c (import_keys): Changed calling interface, adjusted caller. - (import): Moved printing of stats out ... - (print_stats): New. ... to here. - (import_keys_stream): Call stats print here. - (import_keys): Print stats as totals for all files. - - * tdbio.h (DIRF_NEWKEYS): New - * tdbio.c (tdbio_dump_record): Print the new flag. - * trustdb.c (check_trust_record): New arg sigs_only. Adapted all - callers. - (do_update_trust_record): Removed recheck arg and add a new sigs_only - do we can later improve on the performance. Changed all callers too. - (check_trustdb): Evalutate the new flag and add a status output. - Do a check when the dir record has not been checked. - (build_cert_tree): Evaluate the new flag. - (check_trust): Ditto. Do a trust_record check, when the dir record - is not marked as checked. - (mark_fresh_keys): New. - (clear_lid_table): New. - (sync_trustdb): New. - * import.c (import_keys): Call sync_trustdb() after processing. - (import_keys_stream): Ditto. - * tdbdump.c (import_ownertrust): Ditto. - - * import.c (import_revoke_cert): Notify the trust DB. - (do_update_trust_record): Use |= to set the REVOKED bit and not &=; - shame on me for this bad copy+paste introduced bug. - (do_we_trust): Add trustmask to allow revoked key override to work. - Chnaged are to allow return of a mofified trustlevel. Adapted the - one caller. - - * g10.c: New options --emulate-3des-s2k-bug - * passphrase.c (hash_passphrase): Implemented above. - - * mainproc.c (proc_tree): Check for standalone signatures. - (do_check_sig): Print a notice for a standalone revocation - (check_sig_and_print): Do not print an error for unchecked standalone - revocations. - -Tue Sep 28 20:54:37 CEST 1999 Werner Koch <wk@gnupg.de> - - * 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. - - * armor.c (armor_filter): Set a flag if no OpenPGP data has been found. - * verify.c (verify_signatures): Add an error helptext. - -Thu Sep 23 19:24:30 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * openfile.c (open_outfile): Fixed the 8dot3 handling. - - * 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. - -Thu Sep 23 09:52:58 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * verify.c (print_file_status): New. - (verify_one_file): Moved status print to th new fnc. Add error status. - * status.c, status.h (STATUS_FILE_ERROR): New - -Wed Sep 22 10:14:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.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 suffiy instead of - appending it. - - * status.c, status.h: Add STATUS_FILE_{START,DONE}. - * verify.c (verify_one_file): Emit these new stati. - - * 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. - -Mon Sep 20 12:24:41 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * verify.c (verify_files, ferify_one_file): New. - * g10.c: New command --verify-files - -Fri Sep 17 12:56:42 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c: Add UK spelling as alias for armor options ;-) - - * import.c (append_uid): Fixed a SEGV when there is no selfsig and - no subkey. - (merge_sigs): Ditto. Removed the assertion. - -Wed Sep 15 16:22:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c: New option --entropy-dll-name - -Mon Sep 13 10:51:29 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * signal.c (got_fatal_signal): Print message using write(2) and - only for development versions. - -Mon Sep 6 19:59:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * tdbio.c (tdbio_set_dbname): Use mkdir macro - * ringedit.c (add_keyblock_resource): Ditto. - -Fri Sep 3 10:04:45 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (build_pk_list): Skip keys set with --encrypt-to also - when asking for a key. - - * plaintext.c (handle_plaintext): Make sure that we don't read a - second EOF in the read loop for partial length packets. - - * mainproc.c (check_sig_and_print): print user ID as utf-8. - -Thu Sep 2 16:40:55 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * import.c (merge_blocks): First add new subkeys, then merge subkey - certificates. - (merge_sigs): Don't merge subkey signatures here. - -Wed Sep 1 15:30:44 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keygen.c (ask_expire_interval): Fixed bug related to cpr_xx (tnx - Francis J. Lacoste). - -Tue Aug 31 17:20:44 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * plaintext.c (do_hash): Hash CR,LF for a single CR. - (ask_for_detached_datafile): Changed arguments to be closer to - those of hash_datafiles and cleanup the code a bit. - * mainproc.c (proc_tree): Workaround for pgp5 textmode detached - signatures. Changed behavior of asking for data file to be the same - as with provided data files. - - * keylist.c (list_keyblock): Use UTF8 print functions. - -Mon Aug 30 20:38:33 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * import.c (chk_self_sigs): some s/log_error/log_info/ so that gpg - does not return an error if a key has some invalid packets. - - * helptext.c: Fixed some typos and changed the way the - translation works. The english text is now the keyword for gettext - and not anymore the keyword supplied to the function. Done after - some discussion with Walter who thinks this is much easier for the - translators. - - * misc.c (disable_core_dumps): Don't do it for DOSish systems. - - * signal.c (signal_name): Bounds check on signum. - -Wed Aug 4 10:34:18 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pubring.asc: Updated. - - * pkclist.c (do_we_trust_pre,check_signatures_trust): Do not print - the warning about --always_trust when --quiet is used. - - * pkclist.c (fpr_info): New and called at several places. - - * parse-packet.c (dump_sig_subpkt): List revocation key contents. - -Mon Jul 26 09:34:46 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (build_pk_list): Fixed typo in format string. - - * trustdb.c (create_shadow_dir): Don't translate the error string. - - * g10.c (main): Fixed spelling of user-id. - * getkey.c (find_by_name_pk,find_by_name_sk, - find_by_keyid,find_by_keyid_sk): Ditto and translate it. - * import.c (mark_non_selfsigned_uids_valid,delete_inv_parts): Ditto. - - -Mon Jul 26 01:01:39 CEST 1999 Michael Roth <mroth@nessie.de> - - * g10.c, options.h: New options --no-literal and --set-filesize - - * encode.c (encode_simple, encode_crypt): Support for the options - --no-literal and --set-filesize. - - * sign.c (sign_file): ditto. - -Fri Jul 23 13:53:03 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * ringedit.c (enum_keyblocks): Removed annoying error message in cases - when we have no keyring at all to enum. - - * getkey.c (classify_user_id): Rewrote to relax the recognition of - keyIDs and fingerprints (Michael). - - * mainproc.c (check_sig_and_print): Print status NO_PUBKEY. - (print_failed_pkenc): Print status NO_SECKEY. - - * import.c (mark_non_selfsigned_uids_valid): New. - * g10.c: New option --allow-non-selfsigned-uid. - - * pkclist.c (print_fpr): New. - (do_we_trust_pre): Print the fpr before asking whether to use the key - anyway. - (do_edit_ownertrust): Likewise. - -Thu Jul 22 20:03:03 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * ringedit.c (enum_keyblocks): Removed annoying error message in cases - when we have no keyring at all to enum. - - * getkey.c (classify_user_id): Rewrote to relax the recognition of - keyIDs and fingerprints (Michael). - - * mainproc.c (check_sig_and_print): Print status NO_PUBKEY. - (print_failed_pkenc): Print status NO_SECKEY. - - * import.c (mark_non_selfsigned_uids_valid): New. - * g10.c: New option --allow-non-selfsigned-uid. - -Thu Jul 15 10:15:35 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c: New options --disable-{cipher,pubkey}-algo. - -Wed Jul 14 19:42:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * status.h (STATUS_IMPORTED): New. - * import.c (import): Print some status information (Holger Schurig). - - * g10.c (main): Make --no-greeting work again. Add a warning when - --force-mds is used. - -Tue Jul 13 17:39:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (do_edit_ownertrust): Changed the way help works. - (build_pk_list): Implemented default recipient stuff. - * g10.c: New options --default-recipient[-self] - (main): Suppress greeting in most cases, entering a passphrase or - a missing value is not considered to be interactive use. - Merged --print-md and --print-mds; the latter is now obsolete. - Changed the way --gen-random works and documented it. - Changed the way --gen-prime works and add a man entry. - * g10.c (MAINTAINER_OPTIONS): Removed. - -Mon Jul 12 18:45:57 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keyedit.c (keyedit_menu): Add arg sign_mode and changed callers - * g10.c (main): New command --lsign-key. - -Mon Jul 12 14:55:34 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * mainproc.c (kidlist_item): New. - (release_list): Release failed pk-enc-list. - (print_failed_pkenc): New - (proc_encrypted): Print info about failed PK enc. - - * openfile.c (make_outfile_name): s/error/info/ - - * passphrase.c (passphrase_to_dek): Return an empty passphrase when - in batch mode and don't make the warning message fatal - * seckey-cert.c (check_secret_key): Try only once when in batch mode. - - * g10.c (make_username): New. - -Thu Jul 8 16:21:27 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * packet.h (PKT_ring_trust): New - * parse-packet.c (parse_trust): Store trust value - * build-packet (build_packet): Ignore ring trust packets. - * mainproc.c (add_ring_trust): New. - (list_node): Print "rtv" records. - * g10.c: New option --with-fingerprint. - - * trustdb.c (verify_own_keys): Don't insert if we are dry running - (check_trust): Ditto. - -Wed Jul 7 13:08:40 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * Makefile.am: Support for libtool. - - * keygen.c (ask_expire_interval): Hack to allow for an expire date. - - * trustdb.c (do_update_trust_record,update_trust_record): Splitted. - (check_trust_record): New. - (check_trust,build_cert_tree): Check the dir record as needed. - (upd_pref_record): Removed. - (make_pref_record): New. - (propagate_validity): Stop as soon as we have enough validity. - - * tbdio.c (MAX_CACHE_ENTRIES_HARD): Increased the limit. - - -Fri Jul 2 11:45:54 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (g10_exit): Dump random stats. - - * sig-check.c (check_key_signature,check_key_signature2): Enhanced - version and wrapper for old function. - (do_signature_check,signature_check): Ditto. - -Thu Jul 1 12:47:31 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * keyedit.c (show_key_with_all_names): Print a notice for disabled keys. - (enable_disable_keys): Add functionality - * pkclist.c (edit_ownertrust): preserve disabled state. - (build_pk_list): Skip disabled keys. - * trustdb.c (upd_one_ownertrust): Ditto. - (build_cert_tree): Mask the ownertrust. - (trust_letter): Mask the value. - (do_check): Take disabled flag into account. - - * passphrase.c (passphrase_to_dek): Add a pubkey_algo arg and changed - all callers. - - * g10.c (utf8_strings): 2 new options. - - * trustdb.c (insert_trust_record_by_pk): New, replaces the next one. - (insert_trust_record): Now takes a keyblock as arg. Changed all - callers to use the appropritae function. - - * openfile.c (ask_outfile_name): New. - * plaintext.c (handle_plaintext): Ask for filename if there is - no valid syntax. Don't use fname varbatim but filter it. - -Tue Jun 29 21:44:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * trustdb.h (TRUST_FLAG_DISABLED): New. - - * status.c (USE_CAPABILITIES): Capabilities support (Remi). - - * tdbio.c : Added new fields to the DIR record. - (tdbio_write_record): Fixed the update of the hash tables. - (tdbio_delete_record): Drop the record from the hash tables. - (drop_from_hashtbl): New. - - * status.c (cpr_get): Special online help mode. - * helptext.c ("keyedit.cmd"): Removed. - * keyedit.c (keyedit_menu): Use only help system. - (enable_disable_key): New bit doies not yet work. - -Sat Jun 26 12:15:59 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - - * dearmor.c (enarmor_file): Fixed comment string. - * tdbdump.c (export_ownertrust): Text fix. - * tbio.c (tdbio_invalid): Ditto. - - * parse-packet.c (parse_key): Made temp buffer larger. - - * Makefile.am (install-data-local): Add missing backslashes - -Tue Jun 15 12:21:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (main): Made iterated+salted the default S2K method. - - * Makefile.am (install-data-local): Use DESTDIR. - - * passphrase.c (passphrase_to_dek): Emit missing-passphrase while in - batchmode. - - * parse-packet.c (parse_pubkeyenc): Fixed a SEGV. - -Mon Jun 14 21:18:54 CEST 1999 Michael Roth <mroth@nessie.de> - - * g10.c: New options --openpgp, --no-tty, --emit-version, - --default-comment and --lock-multiple - -Thu Jun 10 14:18:23 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * free-packet.c (free_encrypted): Fixed EOF case (Remi). - (free_plaintext): Ditto. - - * helptext.c (keyedit.delsig.unknown): New (Remi). - * keyedit.c (print_and_check_one_sig): Add arg print_without_key and - changed all callers to make use of it (Remi): - -Tue Jun 8 13:36:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keylist.c (print_key_data): New and called elsewhere. - * g10.c: New option --with-key-data - -Wed Jun 2 14:17:19 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * mainproc.c (proc_tree): Yet another bad hack to cope with - broken pgp2 created detached messages in textmode. - -Tue Jun 1 16:01:46 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * openfile.c (make_outfile_name): New. - * plaintext.c (handle_plaintext): Outputfile is now the inputfile - without the suffix. - * g10.c: New option --use-embedded-filename - -Mon May 31 19:41:10 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (main): Fix for SHM init (Michael). - - * compress.c, encr-data.c, mdfilter.c, - plaintext.c, free-packet.c: Speed patches (Rémi). - -Thu May 27 09:40:55 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * status.c (cpr_get_answer_yes_no_quit): New. - * keyedit.c (menu_delsig): New. - (check_all_keysigs): Splitted. - (print_and_check_one_sig): New. - -Wed May 26 14:36:29 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * build-packet.c (build_sig_subpkt): Support large packets. - * parse-packet.c (enum_sig_subpkt): Replaces parse_sig_subpkt. - * mainproc.c (print_notation_data): Print all notation packets. - * g10.c (add_notation_data): Add a way to specify the critical flag. - (main): Add option --set-policy-url. - (check_policy_url): Basic checks. - * sign.c (mk_notation_and_policy): Replaces mk_notation. - - * parse-packet.c (can_handle_critical): Moved decision whether we can - handle critical subpacket to an extra function. - -Tue May 25 19:50:32 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * sign.c (sign_file): Always use compression algo 1 for signed - onyl file becuase we can´ be sure the the verifier supports other - algorithms. - - * build-packet.c (build_sig_subpkt): Support for notation data. - * sign.c (sign_file,clearsign_file,make_keysig_packet): Ditto. - (mk_notation): New. - * g10.c (add_notation_data): New and add option -N - * mainproc.c (print_notation_data): New. - (check_sig_and_print): Print any notation data of the signed text. - -Sun May 23 14:20:22 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (check_signatures_trust): Print a warning and return - immediateley if opt.always_trust is true. - - * g10.c (main): Corrected handling of no-default-keyring - - * pkclist.c (algo_available): Disable Twofish until we have settled - how to do the MDC. - - * hkp.c: Disable everything for mingw32 - -Sat May 22 22:47:26 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * mainproc.c (check_sig_and_print): Add sig creation time to the - VALIDSIG status output. Add more info to the ERRSIG output. - * sig-check.c (signature_check): Add sig time after epoch to SIG_ID. - - * import.c (import_one): Merge duplicate user IDs. - (collapse_uids): New. - * kbnode.c (move_kbnode): New. - (remove_kbnode): New. - * keyedit.c (keyedit_menu): Call collapse_uids. - - * g10.c: new option --logger-fd. - - * import.c: s/log_*_f/log_*/ - -Thu May 20 14:04:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * misc.c (pull_in_libs): do the volatile only for gcc - - * sig-check (signature_check): Emit SIG_iD only for classes 0 and 1. - - * armor.c (armor_filter): Add detection of PGP2 created clearsigs. - (fake_packet): A tab is not a WS for pgp2 - handle this. - * textfilter.c (len_without_trailing_chars): New. - (copy_clearsig_text): Add pgp2mode arg. - * sign.c (clearsign_file): pass old_style to the above fnc. - - -Wed May 19 16:04:30 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c: New option --interactive. - - * mainproc.c (proc_plaintext): Add workaround for pgp2 bug - (do_check_sig): Ditto. - (proc_tree): Ditto. - * plaintext.c (do_hash): Ditto. - (hash_datafiles): Ditto, add an arg, changed all callers. - * mdfilter.c (md_filter): Add support for the alternate hash context. - -Mon May 17 21:54:43 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * parse-packet.c (parse_encrypted): Support for PKT_ENCRYPTED_MDC. - * build-packet.c (do_encrypted_mdc): Ditto. - * cipher.c (write_header): Add mdc hashing. - (cipher_filter): write out the hash. - * mainproc.c (do_proc_packets): Add PKT_ENCRYPTED_MDC. - * encr-data.c (decrypt_data): Add mdc hashing. - (mdc_decode_filter): New. - - * parse-packet.c (parse_sig_subpkt): Fixed stupid bug for subpkt - length calculation - (parse_signature): Fixed even more stupid bug. - -Sat May 8 19:28:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * build-packet.c (do_signature): Removed MDC hack. - * encode.c (encode_crypt_mdc): Removed. - * mainproc.c (do_check_sig): Removed MDC hack. - (check_sig_and_print): Ditto. - * parse-packet.c (parse_signature): Ditto. - * sig-check.c (mdc_kludge_check): Ditto. - * free-packte.c (copy_signature, free_seckey_enc): Ditto. - - * parse-packet.c (parse_signature,parse_key): Store data of - unknown algorithms with mpi_set_opaque inseatd of the old - faked data stuff. - (read_rest): Removed. - (read_rest2): Renamed to read_rest - * build-packet.c (write_fake_data): Use mpi_get_opaque. - * free-packet.c (cp_fake_data): Removed and cahnged all callers - to use mpi_copy. - (free_pubkey_enc,free_seckey_enc,release_public_key_parts, - release_secret_key_parts): Use mpi_free for opaque data. - -Thu May 6 14:18:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * trustdb.c (check_trust): Check for revoked subkeys. - * pkclist.c (do_we_trust): Handled revoked subkeys. - (do_we_trust_pre): Ditto. - (check_signatures_trust): Ditto. - - * build-packet.c (hash_public_key): Fix for ancient g10 keys. - - * mainproc.c (do_proc_packets): Return EOF if no data has been read. - * g10.c (main): Catch errors for default operation. - -Thu Apr 29 12:29:22 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * sign.c (sign_file): Fixed hashing in case of no subpackets. - (clearsign_file): Ditto. - (make_keysig_packet): Ditto. - -Wed Apr 28 13:03:03 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keyedit.c (keyedit_menu): Add new command revkey. - * (menu_revkey): New. - - -Mon Apr 26 17:48:15 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * parse-packet.c (parse_signature): Add the MDC hack. - * build-packet.c (do_signature): Ditto. - * free-packet.c (free_seckey_enc,copy_signature,cmp_signatures): Ditto. - * mainproc.c (do_check_sig): Ditto. - * sig-check.c (mdc_kludge_check): New. - * encode.c (encrypt_mdc_file): New. - - * keyedit.c (check_all_keysigs): List revocations. - * (menu_revsig): New. - * sign (make_keysig_packet): Support for class 0x30. - -Sun Apr 18 20:48:15 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (select_algo_from_prefs): Fixed the case that one key - has no preferences (Remi Guyomarch). - - keylist.c (list_keyblock): ulti_hack to propagate trust to all uids. - -Sun Apr 18 10:11:28 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * seckey-cert.c (do_check): Use real IV instead of a 0 one, so that - it works even if the length of the IV doesn't match the blocksize. - Removed the save_iv stuff. - (protect_secret_key): Likewise. Create the IV here. - * packet.h (PKT_secret_key): Increased size of IV field and add a - ivlen field. - * parse-packet.c (parse_key): Use the len protect.ivlen. - * build-packet.c (do_secret_key). Ditto. - - * getkey.c (key_byname): Close keyblocks. - - * Makefile.am (gpgm): Removed this - * g10.c: Merged gpg and gpgm - - * import.c (import): Utilize option quiet. - * tdbio.c (tdbio_set_dbname): Ditto. - * ringedit.c (add_keyblock_resource,keyring_copy): Ditto. - - * keyedit.c (sign_uids): Add some batch support. - - * g10.c (main): add call to tty_batchmode. - -Fri Apr 9 12:26:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * status.c (write_status_text): Some more status codes. - * passphrase_to_dek (passphrase_to_dek): add a status code. - * seckey_cert.c (check_secret_key): Likewise. - - * encr-data.c (decrypt_data): Reverse the last changes - * cipher.c (write_header): Ditto. - - * parse-packet.c (parse_key): Dropped kludge for ancient blowfish mode. - -Thu Apr 8 09:35:53 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * mainproc.c (proc_encrypted): Add a new status output - * passphrase.c (passphrase_to_dek): Ditto. - * status.h status.c: Add new status tokens. - -Wed Apr 7 20:51:39 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * encr-data.c (decrypt_data): Fixes for 128 bit blocksize - * cipher.c (write_header): Ditto. - * seckey-cert.c (do_check): Ditto. - (protect_secret_key). Ditto. - * misc.c (print_cipher_algo_note): Twofish is now a standard algo. - - * keygen.c (do_create): Fixed spelling (Gaël Quéri) - (ask_keysize): Only allow keysizes up to 4096 - - * ringedit.c (add_keyblock_resource): chmod newly created secrings. - - * import.c (delete_inv_parts): Fixed accidently deleted subkeys. - -Tue Apr 6 19:58:12 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c: Removed duped include (John Bley) - * mainproc.c: Ditto. - - * build-packet.c (hash_public_key): Fixed hashing of the header. - - * import.c (delete_inv_parts): Allow import of own non-exportable sigs. - -Sat Mar 20 13:59:47 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (fake_packet): Fix for not not-dash-escaped - -Sat Mar 20 11:44:21 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (main): Added command --recv-keys - * hkp.c (hkp_import): New. - -Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * trustdb.c (check_trust): add new arg add_fnc and changed all callers. - (do_check): Ditto. - (verify_key): Ditto. - (propagate_validity): Use the new add_fnc arg. - (print_user_id): Add the FILE arg. - (propagate_ownertrust): New. - * pkclist.c (add_ownertrust_cb): New and changed the add_ownertrust - logic. - - * getkey.c (get_keyblock_bylid): New. - * trustdb.c (print_uid_from_keyblock): New. - (dump_tn_tree_with_colons): New. - (list_trust_path): Add colon print mode. - - * trustdb.c (insert_trust_record): Always use the primary key. - - * encode.c (encode_simple): Added text_mode filter (Rémi Guyomarch) - (encode_crypt): Ditto. - - * mainproc.c (proc_pubkey_enc): Added status ENC_TO. - * armor.c (armor_filter): Added status NODATA. - * passphrase.c (passphrase_to_dek): Always print NEED_PASSPHRASE - * seckey_cert.c (check_secret_key): Added BAD_PASS status. - - * g10.c (main): Set g10_opt_homedir. - -Sun Mar 14 19:34:36 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keygen.c (do_create): Changed wording of the note (Hugh Daniel) - -Thu Mar 11 16:39:46 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * tdbdump.c: New - - * trustdb.c (walk_sigrecs,do_list_sigs,list_sigs, - list_records,list_trustdb,export_ownertrust,import_ownertrust): Moved - to tdbdump.c - (init_trustdb): renamed to setup_trustdb. Changed all callers. - (do_init_trustdb): renamed to init_trustdb(). - * trustdb.c (die_invalid_db): replaced by tdbio_invalid. - * tdbio.c (tdbio_invalid): New. - - * import.c (delete_inv_parts): Skip non exportable signatures. - * keyedit.c (sign_uid_mk_attrib): New. - (sign_uids): Add the local argument. - (keyedit_menu): New "lsign" command. - * trustdb.c (register_trusted_key): Removed this and all related stuff. - * g10.c (oTrustedKey): Removed option. - - * tdbio.h (dir.valcheck): New trustdb field. - * tdbio.c: Add support for this field - (tdbio_read_modify_stamp): New. - (tdbio_write_modify_stamp): New. - * trustdb.c (do_check): Check against this field. Removed cache update. - (verify_key): Add cache update. - (upd_uid_record): Some functional changes. - (upd_cert_record): Ditto - -Wed Mar 10 11:26:18 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keylist.c (list_keyblock): Fixed segv in uid. Print 'u' as - validity of sks. - -Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * getkey.c (classify_user_id): Add new mode 12 (#<lid>). - - * seckey-cert.c (check_secret_key): replaced error by info. - - * trustdb.c (query_trust_info): Add another arg, changed all callers. - (check_trust): Ditto. - (do_check): Ditto. - (verify_key): Handle namehash. - * keylist.c (list_keyblock): print trust info for user ids. - - * sig-check.c (signature_check): Add sig-created to status output. - -Tue Mar 2 16:44:57 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * textfilter.c (copy_clearsig_text): New. - (clearsign): Removed. - * sign.c (clearsign_file): does not use textfiler anymore. - - * keygen.c (ask_user_id): print a note about the used charset. - -Tue Mar 2 10:38:42 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * sig-check.c (signature_check): sig-id now works for all algos. - - * armor.c (armor_filter): Fixed armor bypassing. - -Sun Feb 28 19:11:00 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keygen.c (ask_user_id): Don't change the case of email addresses. - (has_invalid_email_chars): Adjusted. - - * keylist.c (list_one): Really list serect keys (Remi Guyomarch) - - * keyedit.c (menu_select_uid): Add some braces to make egcs happy. - (menu_select_key): Ditto. - - * mainproc.c (do_proc_packets): List sym-enc packets (Remi Guyomarch) - -Fri Feb 26 17:55:41 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (build_pk_list): Return error if there are no recipients. - - * sig-check.c (signature_check): New signature id feature. - * armor.c (make_radic64_string): New. - - * mainproc.c (proc_pubkey_enc): early check for seckey availability. - - * pkclist.c (do_we_trust_pre): print user id before asking. - - * ringedit.c (add_keyblock_resource,get_keyblock_handle): Cleaner - handling of default resource. - - -Thu Feb 25 18:47:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (algo_available): New. - (select_algo_from_prefs): Check whether algo is available. - - * ringedit.c (keyring_copy): Take care of opt.dry_run. - (do_gdbm_store): Ditto. - * openfile.c (open_outfile). Ditto. - (copy_options_file): Ditto. - * trustdb.c (update_trustdb): Ditto. - (clear_trust_checked_flag): Ditto. - (update_trust_record): Ditto. - (insert_trust_record): Ditto. - -Wed Feb 24 11:07:27 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * keylist.c (secret_key_list): Now really list the secret key. - - * trustdb.c (do_init_trustdb): New. Init is now deferred. - -Mon Feb 22 20:04:00 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * getkey.c (lookup_sk): Return G10ERR_NO_SECKEY and not x_PUBKEY. - -Fri Feb 19 15:49:15 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (select_algo_from_prefs): retrieve LID if not there. - - * armor.c (fake_packet): Replaced ugly lineending handling. - - * g10.c (oNoEncryptTo): New. - * pkclist.c (build_pk_list): Implemented this option. - - * g10.c (main): Greeting is now printed to stderr and not to tty. - Use add_to_strlist() instead of direct coding. - - * import.c (import): Use iobuf_push_filter2. - - * mainproc.c (check_sig_and_print): Print all user ids - for good signatures. - * getkey.c (get_pubkeyblock): New. - - * import.c (chk_self_sigs): Fixed SEGV for unbounded class 0x18 keys. - (delete_inv_parts): Delete special marked packets. - -Tue Feb 16 14:10:02 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (main): New option --encrypt-to - - * pkclist.c (build_pk_list): Implemented encrypt-to. - - * parse-packet.c (parse_user_id): Removed the hack to work with - utf-8 strings. - - * g10.c (main): Install lockfile cleanup handler. - * tdbio.c (cleanup): Removed: this is now handled by dotlock. - -Sat Feb 13 14:13:04 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * tdbio.c (tdbio_set_dbname): Init lockhandle for a new trustdb - -Wed Feb 10 17:15:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c (main): check for development version now in configure - - * tdbio.c (tdbio_write_record): Add uid.validity - (tdbio_read_record) : Ditto. - (tdbio_dump_record) : Ditto. - - * keygen.c (keygen_add_std_prefs): Replaced Blowfish by Twofish, - removed MD5 and Tiger. - * pubkey-enc.c (get_it): Suppress warning about missing Blowfish - in preferences in certain cases. - - * ringedit.c (lock_rentry,unlock_rentry): New. - - * getkey.c (key_byname): Pass ret_kb down to lookup_xx. - - * armor.c (armor_filter): No output of of empty comment lines. - Add option --no-version to suppress the output of the version string. - - * getkey.c: Release the getkey context for auto context variables. - -Sun Jan 24 18:16:26 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * getkey.c: Changed the internal design to allow simultaneous - lookup of multible user ids - (get_pubkey_bynames): New. - (get_seckey_bynames): New. - (get_seckey_next): New. - (get_seckey_end): New. - * keylist.c (list_one): Use the new functions. - - * keylist.c (list_keyblock): add a newline for normal listings. - - * g10.c (--recipient): New option name to replace --remote-user - - -Wed Jan 20 18:59:49 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * textfilter.c: Mostly rewritten - * plaintext.c (handle_plaintext): Use now text_filter semantics. - -Tue Jan 19 19:34:58 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * export.c (export_pubkeys_stream): New. - (do_export_stream): New. - * g10.c (aSendKeys): New command. - * hkp.c (hkp_export): New. - - * compress.c (do_uncompress): Hack for algo 1 and 1.1.3 - -Sun Jan 17 11:04:33 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * textfilter.c (text_filter): Now uses iobuf_read_line(). - (read_line): Removed. - - * armor.c (trim_trailing_spaces): Removed and replaced - by trim_trailing_ws from libutil - -Sat Jan 16 12:03:27 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * hkp.c (hkp_ask_import): Use only the short keyid - -Sat Jan 16 09:27:30 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * import.c (import_key_stream): New - (import): New, moved most of import_keys here. - * g10.c: New option --keyserver - * mainproc.c (check_sig_and_print): Hook to import a pubkey. - - * pref.c pref.h : Removed - - * hkp.c hkp.h: New - -Wed Jan 13 14:10:15 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (radix64_read): Print an error if a bad armor was detected. - -Wed Jan 13 12:49:36 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (radix64_read): Now handles malformed armors produced - by some buggy MUAs. - -Tue Jan 12 11:17:18 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * ringedit.c (find_keyblock_bysk): New. - - * skc_list.c (is_insecure): New. - (build_sk_list): usage check for insecure keys. - - * import.c (chk_self_sigs): Add handling for subkeys. - (delete_inv_parts): Skip unsigned subkeys - - * sig-check.c (do_check): Print info if the signature is older - than the key. - * keygen.c (generate_subkeypair): Fail on time warp. - * sign.c (do_sign): Ditto. - -Sun Jan 10 15:10:02 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (fake_packet): Fixed not-dash-escaped bug. - -Sat Jan 9 16:02:23 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * sig-check.c (do_check): Output time diff on error - - * status.c (STATUS_VALIDSIG): New. - (is_status_enabled): New. - * mainproc.c (check_sig_and_print): Issue that status message. - - * plaintext.c (special_md_putc): Removed - - * armor.c (armor_filter): print error for truncated lines. - - * free-packet.c (free_encrypted): Revomed call to set_block_mode. - (free_plaintext): Ditto. - -Thu Jan 7 18:00:58 CET 1999 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (add_ownertrust): Fixed return value. - - * encr-data.c (decrypt_data): Disabled iobuf_set_limit and - iobuf_pop_filter stuff. - * compress.c (handle_compressed): Disabled iobuf_pop_filter. - - * packet.h (PKT_secret_key): Add is_primary flag. - * parse-packet.c (parse_key): Set this flag. - * passphrase.c (passphrase_to_dek): Kludge to print the primary - keyid - changed the API: keyid must now hold 2 keyids. - * getkey.c (get_primary_seckey): New. - * seckey-cert.c (do_check): pass primary keyid to passphrase query - - * tbdio.c (open_db): removed the atexit - (tdbio_set_dbname): and moved it to here. - - * armor.c: Rewrote large parts. - -Tue Dec 29 19:55:38 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * revoke.c (gen_revoke): Removed compression. - - * pkclist.c (do_we_trust_pre): special check for revoked keys - - * trustdb.c (update_trust_record): Fixed revoke flag. - -Tue Dec 29 14:41:47 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * misc.c (disable_core_dumps): Check for EINVAL (Atari) - - * getkey (merge_one_pk_and_selfsig): Fixed search of expiredate. - (merge_keys_and_selfsig): Ditto. - - * free-packet.c (cmp_public_keys): cmp expire only for v3 packets - (cmp_secret_keys): Ditto. - (cmp_public_secret_key): Ditto. - -Wed Dec 23 17:12:24 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (find_header): Reset not_dashed at every header - -Wed Dec 23 13:18:14 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * pkclist.c (add_ownertrust): Refresh validity values. - - * trustdb.c (enum_cert_paths_print): New arg refresh. - - * ringedit.c: Fixed problems fix keyrings - * parse-packet.c (dbg_parse_packet): New debug functions. - - * getkey.c (getkey_disable_caches): New. - * import.c (import_keys): Disable caches. - -Thu Dec 17 18:31:15 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * misc.c (trap_unaligned): Only for glibc 1 - - * sign.c (write_dash_escaped): Now escapes "From " lines - * g10.c: New option --escape-from-lines - - * trustdb.c (sort_tsl_list): New - (list_trust_path): Now prints sorted list. - (enum_cert_paths): Likewise. - (enum_cert_paths_print): New. - (print_paths): New printing format. - * pkclist.c (add_ownertrust): New arg quit. - (edit_ownertrust): New quit selection and does not query - the recipients ownertrust anymore. - (add_ownertrust): Print the ceritficate path. - - -Mon Dec 14 21:18:49 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * parse-packet.c (parse_signature): Now checks for critical bit - (parse_sig_subpkt): Splitted. - (parse_one_sig_subpkt): New. - * sig-check.c (do_check): handle critical bit. - -Sun Dec 13 14:10:56 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * pcklist.c (select_algo_from_prefs): Preferences should - now work (lost the != ? ) - -Thu Dec 10 20:15:36 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * ringedit.c (gdbm_store): Fix for inserts - - * g10.c (main): New option --export-all - * export.c (export_pubkeys): New arg. - (do_export): Now may skip old keys. - - * status.c: Minor patches for Sun's cc - - * keygen.c (ask_algo): Disabled v3 ElGamal choice, rearranged - the numbers. Add a warning question when a sign+encrypt key - is selected. - - * g10.c (do_not_use_RSA): Removed. - * misc.c (print_pubkey_algo_note): New as replacement for the - do_not_use_RSA() and chnaged all callers. - (print_cipher_algo_note): New. - (print_hash_algo_note): New. - - * cipher.c (write_header): Add a call to print_cipher_algo_note. - * seckey-cert.c (protect_secret_key): Ditto - * sign.c (do_sign): Add a call to print_digest_algo_note. - - * getkey.c (get_long_user_id_string): New. - * mainproc.c (check_sig_and_print): Changed the format of the - status output. - - * encrypt.c (write_pubkey_enc_from_list): print used symmetric cipher. - - * pkclist.c (do_we_trust): Changed a message. - -Wed Dec 9 13:41:06 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * misc.c (trap_unaligned) [ALPHA]: Only if UAC_SIGBUS is defined. - - * sign.c (write_dash_escaped): Add the forgotten patch by Brian Moore. - - * compress.c (do_uncompress): Fixed the inflating bug. - - -Tue Dec 8 13:15:16 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * trustdb.c (upd_uid_record): Now uses the newest self-signature - (insert_trust_record): Now calls update with recheck set to true. - (register_trusted_key): New. - (verify_own_keys): Enhanced by list of trusted keys. - - * g10.c (main): Print a warning when a devel version is used. - (main): New option --trusted-key - - * import.c (merge_blocks): Fixed merging of new user ids and - added merging of subkeys. - (append_uid): Ditto. - (merge_keysig): New. - (append_key): New. - * getkey.c (merge_one_pk_and_selfsig): Get the expiration time - from the newest self-signature. - (merge_keys_and_selfsig): Ditto. - - * free-packet.c (cmp_secret_key): New. - - -Fri Nov 27 21:37:41 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * g10.c: New option --lock-once - * tdbio.c (open_db): Add an atexit - (cleanup): New. - (tdbio_sync): Add locking. - (tdbio_end_transaction): Ditto. - (put_record_into_cache): Ditto. - * ringedit.c (keyring_copy): Ditto. - (cleanup): New. - (add_keyblock_resource): Add an atexit. - -Fri Nov 27 15:30:24 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - * armor.c (find_header): Another fix for clearsigs. - -Fri Nov 27 12:39:29 CET 1998 Werner Koch <wk@isil.d.shuttle.de> - - - * status.c (display_help): Removed. - * helptext.c: New and removed the N_() from all cpr_gets. - - -Fri Nov 20 16:54:52 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): New option --not-dash-escaped - * sign.c (write_dashed_escaped): Ditto. - * armor.c (find_header): Support for NotDashEscaped header. - - * getkey.c: print "disabled cache.." only if verbose is used. - -Thu Nov 19 07:17:31 1998 Werner Koch <werner.koch@guug.de> - - * parse-packet.c (dump_sig_subpkt): Fixed expire listing - * getkey.c (merge_keys_and_selfsig): Fixed expire calculation. - (merge_one_pk_and_selfsig): Ditto. - * keyedit.c (menu_expire). Ditto. - * keygen.c (keygen_add_key_expire): Ditto. - (ask_expire_interval): New and changed all local function to use - this instead. - (keygen_add_key_expire): Opaque should now be a public key; - changed all callers. - - * parse.packet.c (parse): use skip_rest to skip packets. - - * keyedit.c (keyedit_menu): New arg for cmdline cmds. - -Wed Nov 18 20:33:50 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (check_trustdb): Now rechecks all gived userids. - (collect_paths): Some fixes. - (upd_pref_records): Skips empty items, evaluate all items. - - * parse-packet.c (dump_sig_subpkt): Better listing of prefs. - (skip_packet): Now knows about marker packet - - * g10.c: removed cmd "--edit-sig". - - * pubring.asc: Updated. - -Sat Nov 14 14:01:29 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Changed syntax of --list-trust-path - * trustdb.c (list_trust_path): Replaced max_depth by - opt.max_cert_depth - -Fri Nov 13 07:39:58 1998 Werner Koch <werner.koch@guug.de> - - * trustdb.c (collect_paths): Removed a warning message. - (enum_trust_web): Removed. - (enum_cert_paths): New. - * pkclist.c (add_ownertrust): Changed to use enum_cert_paths. - (edit_ownertrust): Now list ceritficates on request. - (show_paths): New. - -Wed Nov 11 18:05:44 1998 Werner Koch <werner.koch@guug.de> - - * g10.c (main): New option --max-cert-depth - * tdbio.h: add new fields to ver and dir record. - * tdbio.c: read/write/dump of these fields. - (tdbio_db_matches_options): New. - * trustdb.c: replaced MAC_CERT_DEPTH by opt.max_cert_depth. - (do_check): cache validity and changed other functions - to reset the cached value. - - * keylist.c (list_one): Now lists the ownertrust. - * mainproc.c (list_node): Ditto. - -Tue Nov 10 10:08:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (g10_exit): Now looks at the new g10_errors_seen. - * mainproc.c (check_sig_and_print): Sets g10_errors_seen. - - * *.c : i18n many more strings. - - * ringedit.c (locate_keyblock_by_keyid): Add HAVE_LIBGDBM - (locate_keyblock_by_fpr): Ditto. - - * g10.c (main): removed unsused "int errors". - (main): Add new option --charset. - - * g10.c (main): special message for the unix newbie. - -Mon Nov 9 07:17:42 1998 Werner Koch <werner.koch@guug.de> - - * getkey.c (finish_lookup): Kludge to prefere algo 16. - - * trustdb.c (new_lid_table): Clear cached item. - - * status.c (cpr_get_utf8): New. - * pkclist.c (build_pk_list): Uses this. - -Sun Nov 8 17:20:39 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c (check_sig_and_print): Why did I use strlen()-1 - in the printf? - This truncated the TZ. - -Sat Nov 7 15:57:28 1998 me,,, (wk@tobold) - - * getkey.c (lookup): Changes to support a read_next. - (get_pubkey): Fixed a memory leak. - - * keylist.c (list_one): Now lists all matching user IDs. - -Tue Nov 3 16:19:21 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (ask_user_id): Now converted to UTF-8 - - * g10.c (main): Kludge for pgp clearsigs and textmode. - -Fri Oct 30 16:40:39 1998 me,,, (wk@tobold) - - * signal.c (block_all_signals): New. - (unblock_all_signals): New - * tdbio.c (tdbio_end_transaction): Now blocks all signals. - - * trustdb.c (new_lid_table): Changed the representation of the - former local_lid_info stuff. - - * trustdb.c (update_trust_record): Reorganized the whole thing. - * sig-check.c (check_key_signature): Now handles class 0x28 - - -Wed Oct 28 18:56:33 1998 me,,, (wk@tobold) - - * export.c (do_export): Takes care of the exportable sig flag. - -Tue Oct 27 14:53:04 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (update_trust_record): New "fast" parameter. - -Sun Oct 25 19:32:05 1998 Werner Koch (wk@isil.d.shuttle.de) - - * openfile.c (copy_options_File): New. - * ringedit.c (add_keyblock_resource): Creates options file - * tdbio.c (tdbio_set_dbname): Ditto. - -Sat Oct 24 14:10:53 1998 brian moore <bem@cmc.net> - - * mainproc.c (proc_pubkey_enc): Don't release the DEK - (do_proc_packets): Ditto. - -Fri Oct 23 06:49:38 1998 me,,, (wk@tobold) - - * keyedit.c (keyedit_menu): Comments are now allowed - - * trustdb.c: Rewrote large parts. - - -Thu Oct 22 15:56:45 1998 Michael Roth (mroth@nessie.de) - - * encode.c: (encode_simple): Only the plain filename without - a given directory is stored in generated packets. - (encode_crypt): Ditto. - - * sign.c: (sign_file) Ditto. - - -Thu Oct 22 10:53:41 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (update_trust_record): Add new optional arg. - - * import.c (import_keys): Add statistics output - * trustdb.c (update_trustdb): Ditto. - (insert_trustdb): Ditto. - - * tdbio.c (tdbio_begin_transaction): New. - (tdbio_end_transaction): New. - (tdbio_cancel_transaction): New. - - * g10.c (main): New option --quit. - - * trustdb.c (check_hint_sig): No tests for user-id w/o sig. - This caused an assert while checking the sigs. - - * trustdb.c (upd_sig_record): Splitted into several functions. - - * import.c (import_keys): New arg "fast". - * g10.c (main): New command --fast-import. - -Wed Oct 21 18:19:36 1998 Michael Roth <mroth@nessie.de> - - * ringedit.c (add_keyblock_resource): Directory is now created. - * tdbio.c (tdbio_set_dbname): New info message. - -Wed Oct 21 11:52:04 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (update_trustdb): released keyblock in loop. - - * keylist.c (list_block): New. - (list_all): Changed to use list_block. - - * trustdb.c: Completed support for GDBM - - * sign.c (only_old_style): Changed the way force_v3 is handled - (sign_file): Ditto. - (clearsign_file): Ditto. - - * keygen.c (has_invalid_email_chars): Splitted into mailbox and - host part. - - * keylist.c (list_one): Add a merge_keys_and_selfsig. - * mainproc.c (proc_tree): Ditto. - -Sun Oct 18 11:49:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sign.c (only_old_style): Add option force_v3_sigs - (sign_file): Fixed a bug in sig->version - (clearsign_file): Ditto. - - * parse-packet.c (dump_sig_subpkt): New - - * keyedit.c (menu_expire): New. - * free-packet.c (cmp_signatures): New - - -Sat Oct 17 10:22:39 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c: changed output line length from 72 to 64. - - * keyedit.c (fix_keyblock): New. - -Fri Oct 16 10:24:47 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c: Rewrote most. - * tdbio.c: Add cache and generalized hash tables. - - * options.h (ENABLE_COMMENT_PACKETS): New but undef'ed. - * encode.c, sign.c, keygen.c: Disabled comment packets. - * export.c (do_export): Comment packets are never exported, - except for those in the secret keyring. - - * g10.c (main): Removed option do-no-export-rsa; should be - be replaced by a secpial tool. - * export.c (do_export): Removed the code for the above option. - - * armor.c (find_header): Support for new only_keyblocks. - * import.c (import_keys): Only looks for keyblock armors. - - * packet.h: replaced valid_days by expiredate and changed all users. - * build-packet.c (do_public_key): calculates valid-days - (do_secret_key): Ditto. - * parse-packet.c (parse_key): expiredate is calucated from the - valid_period in v3 packets. - * keyid.c (do_fingerprint_md): calculates valid_dates. - - * keygen.c (add_key_expire): fixed key expiration time for v4 packets. - - * armor.c (find_header): A LF in the first 28 bytes - was skipped for non-armored data. - -Thu Oct 8 11:35:51 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (is_armored): Add test on old comment packets. - - * tdbio.c (tdbio_search_dir_bypk): fixed memory leak. - - * getkey.c: Changed the caching algorithms. - -Wed Oct 7 19:33:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * kbnodes.c (unused_nodes): New. - -Wed Oct 7 11:15:36 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keyedit.c (sign_uids): Fixed a problem with SK which could caused - a save of an unprotected key. - (menu_adduid): Ditto. - - * keyedit.c (keyedit_menu): Prefs are now correctly listed for - new user ids. - - * trustdb.c (update_trust_record): New. - (insert_trust_record): Now makes use of update_trust_record. - -Tue Oct 6 16:18:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (read_record): replaces most of the tdbio_read_records. - (write_record): Ditto. - -Sat Oct 3 11:01:21 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (ask_alogo): enable ElGamal enc-only only for addmode. - -Wed Sep 30 10:15:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * import.c (import_one): Fixed update of wrong keyblock. - -Tue Sep 29 08:32:08 1998 me,,, (wk@tobold) - - * mainproc.c (proc_plaintext): Display note for special filename. - * plaintext.c (handle_plaintext): Suppress output of special file. - -Mon Sep 28 12:57:12 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (verify_own_keys): Add warning if a key is not protected. - - * passphrase (hash_passphrase): Fixed iterated+salted mode and - setup for keysizes > hashsize. - - * g10.c (main): New options: --s2k-{cipher,digest,mode}. - -Fri Sep 25 09:34:23 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c: Chnaged some help texts. - -Tue Sep 22 19:34:39 1998 Werner Koch (wk@isil.d.shuttle.de) - - * passphrase.c (read_passphrase_from_fd): fixed bug for long - passphrases. - -Mon Sep 21 11:28:05 1998 Werner Koch (wk@(none)) - - * getkey.c (lookup): Add code to use the sub key if the primary one - does not match the usage. - - * armor.c (armor_filter): New error message: no valid data found. - (radix64_read): Changes to support multiple messages. - (i18n.h): New. - * mainproc.c (add_onepass_sig): bug fix. - -Mon Sep 21 08:03:16 1998 Werner Koch (wk@isil.d.shuttle.de) - - * pkclist.c (do_we_trust): Add keyid to most messages. - - * passphrase.c (read_passphrase_from_fd): New. - (have_static_passphrase): New - (get_passphrase_fd): Removed. - (set_passphrase_fd): Removed. - * g10.c (main): passphrase is now read here. - - * keyedit.c (keyedit_menu): "help" texts should now translate fine. - -Mon Sep 21 06:40:02 1998 Werner Koch (wk@isil.d.shuttle.de) - - * encode.c (encode_simple): Now disables compression - when --rfc1991 is used. - (encode_crypt): Ditto. - -Fri Sep 18 16:50:32 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (merge_key_and_selfsig): New. - -Fri Sep 18 10:20:11 1998 Werner Koch (wk@isil.d.shuttle.de) - - * pkclist.c (select_algo_from_prefs): Removed 3DES kludge. - - * seskey.c (make_session_key): Fixed SERIOUS bug introduced - by adding the weak key detection code. - - * sign.c (sign_file): Changed aremor header in certain cases. - -Tue Sep 15 17:52:55 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c (check_sig_and_print): Replaced ascime by asctimestamp. - -Mon Sep 14 11:40:52 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seskey.c (make_session_key): Now detects weak keys. - - * trustdb (clear_trust_checked_flag): New. - - * plaintext.c (handle_plaintext): Does no anymore suppress CR from - cleartext signed messages. - -Sun Sep 13 12:54:29 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (insert_trust_record): Fixed a stupid bug in the free - liunked list loops. - -Sat Sep 12 15:49:16 1998 Werner Koch (wk@isil.d.shuttle.de) - - * status.c (remove_shmid): New. - (init_shm_comprocess): Now sets permission to the real uid. - -Wed Sep 9 11:15:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h (PKT_pubkey_enc): New flah throw_keyid, and add logic to - implement it. - * g10.c (main): New Option --throw-keyid - - * getkey.c (enum_secret_keys): Add new ar and changed all callers. - -Tue Sep 8 20:04:09 1998 Werner Koch (wk@isil.d.shuttle.de) - - * delkey.c (delete_key): Moved from keyedit.c. - -Mon Sep 7 16:37:52 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (calc_length_header): New arg new_ctb to correctly - calculate the length of new style packets. - - * armor.c (is_armored): Checks for symkey_enc packets. - - * pkclist.c (select_algo_from_prefs): 3DEs substitute is now CAST5. - -Tue Aug 11 17:54:50 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (do_secret_key): Fixed handling of old keys. - - * getkey.c (compare_name): Fixed exact and email matching - - * openfile.c (open_outfile): Changed arguments and all callers. - -Tue Aug 11 09:14:35 1998 Werner Koch (wk@isil.d.shuttle.de) - - * encode.c (encode_simple): Applied option set-filename and comment. - (encode_crypt): Ditto. - * sign.c (sign_file): Ditto. - * armor.c (armor_filter): Applied option comment. - - * encode.c (encode_crypt): Moved init_packet to the begin. - (encode_simple): add an init_packet(). - - * comment (write_comment): Now enforces a hash sign as the 1st byte. - - * import.c (import_one): Add explanation for "no user ids". - - * compress.c (do_uncompress): Applied Brian Warner's patch to support - zlib 1.1.3 etc. - - * trustdb.c (check_trust): Fixed a problem after inserting new keys. - - * getkey (lookup): do not return the primary key if usage is given - (lookup_sk): Ditto and take usage into account. - - * status.c (cpr_get_answer_is_yes): add display_help. - -Mon Aug 10 10:11:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (lookup_sk): Now always returns the primary if arg - primary is true. - (lookup): Likewise. - (get_pubkey_byname): Now returns the primary key - (get_seckey_byname): Ditto. - - -Mon Aug 10 08:34:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keyid.c (pubkey_letter): ELG_E is now a small g. - -Sat Aug 8 17:26:12 1998 Werner Koch (wk@isil.d.shuttle.de) - - * openfile (overwrite_filep): Changed semantics and all callers. - -Sat Aug 8 12:17:07 1998 Werner Koch (wk@isil.d.shuttle.de) - - * status.c (display_help): New. - -Thu Aug 6 16:30:41 1998 Werner Koch,mobil,,, (wk@tobold) - - * seskey.c (encode_session_key): Now uses get_random_bits(). - -Thu Aug 6 07:34:56 1998 Werner Koch,mobil,,, (wk@tobold) - - * ringedit.c (keyring_copy): No more backupfiles for - secret keyrings and add additional warning in case of - a failed secret keyring operation. - -Wed Aug 5 11:54:37 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (check_opts): Moved to main. Changed def_cipher_algo - semantics and chnaged all users. - - * pubkey-enc.c (get_sssion_key): New informational output - about preferences. - - * parse-packet.c (parse_symkeyenc): Fixed salted+iterated S2K - (parse_key): Ditto. - * build-packet.c (do_secret_key): Ditto. - (do_symkey_enc): Ditto. - -Tue Aug 4 08:59:10 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (enum_secret_keys): Now returns only primary keys. - - * getkey (lookup): Now sets the new namehash field. - - * parse-packet.c (parse_sig_subpkt2): New. - - * sign.c (sign_file): one-pass sigs are now emiited reverse. - Preference data is considered when selecting the compress algo. - -Wed Jul 29 12:53:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * free-packet.c (copy_signature): New. - - * keygen.c (generate_subkeypair): rewritten - * g10.c (aKeyadd): Removed option --add-key - -Mon Jul 27 10:37:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seckey-cert.c (do_check): Additional check on cipher blocksize. - (protect_secret_key): Ditto. - * encr-data.c: Support for other blocksizes. - * cipher.c (write_header): Ditto. - -Fri Jul 24 16:47:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * kbnode.c (insert_kbnode): Changed semantics and all callers. - * keyedit.c : More or less a complete rewrite - -Wed Jul 22 17:10:04 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (write_sign_packet_header): New. - -Tue Jul 21 14:37:09 1998 Werner Koch (wk@isil.d.shuttle.de) - - * import.c (import_one): Now creates a trustdb record. - - * g10.c (main): New command --check-trustdb - -Mon Jul 20 11:15:07 1998 Werner Koch (wk@isil.d.shuttle.de) - - * genkey.c (generate_keypair): Default key is now DSA with - encryption only ElGamal subkey. - -Thu Jul 16 10:58:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keyid.c (keyid_from_fingerprint): New. - * getkey.c (get_pubkey_byfprint): New. - -Tue Jul 14 18:09:51 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keyid.c (fingerprint_from_pk): Add argument and changed all callers. - (fingerprint_from_sk): Ditto. - -Tue Jul 14 10:10:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * plaintext.c (handle_plaintext): Now returns create error if - the file could not be created or the user responded not to overwrite - the file. - * mainproc.c (proc_plaintext): Tries again if the file could not - be created to check the signature without output. - - * misc.c (disable_core_dumps): New. - * g10.c (main): disable coredumps for gpg - - * g10.c (MAINTAINER_OPTIONS): New to disable some options - -Mon Jul 13 16:47:54 1998 Werner Koch (wk@isil.d.shuttle.de) - - * plaintext.c (hash_datafiles): New arg for better support of - detached sigs. Changed all callers. - * mainproc.c (proc_signature_packets): Ditto. - - * g10.c (main): New option "compress-sigs" - * sig.c (sign_file): detached signatures are not anymore compressed - unless the option --compress-sigs is used. - -Thu Jul 9 19:54:54 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c: Fixes to allow zero length cleartext signatures - -Thu Jul 9 14:52:47 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (build_list): Now drops setuid. - (main): Changed the way keyrings and algorithms are registered . - -Wed Jul 8 14:17:30 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h (PKT_public_key): Add field keyid. - * parse-packet.c (parse_key): Reset the above field. - * keyid.c (keyid_from_pk): Use above field as cache. - - * tdbio.c, tdbio.h: New - * trustdb.c: Moved some functions to tdbio.c. - (print_keyid): New. - - * pkclist.c (check_signatures_trust): New. - -Wed Jul 8 10:45:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * plaintext.c (special_md_putc): New. - (handle_plaintext): add clearsig argument - * mainproc.c (proc_plaintext): detection of clearsig - * sign.c (write_dased_escaped): Changed clearsig format - -Tue Jul 7 18:56:19 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (find_header): Now makes sure that there is only one - empty line for clearsigs, as this is what OP now says. - -Mon Jul 6 13:09:07 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): New option default-secret-key - * getkey.c (get_seckey_byname): support for this option. - -Mon Jul 6 09:03:49 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (add_keyring): Keyrings are now added to end of the - list of keyrings. The first added keyringwill be created. - (add_secret_keyring): Likewise. - - * ringedit.c (add_keyblock_resource): Files are created here. - - * g10.c (aNOP): Removed - - * getkey.c (lookup): Add checking of usage for name lookups - * packet.h (pubkey_usage): Add a field which may be used to store - usage capabilities. - * pkclist.c (build_pk_list): getkey now called with usage arg. - * skclist.c (build_sk_list): Ditto. - - * sign.c (clearsign_file): Fixed "Hash:" headers - -Sat Jul 4 13:33:31 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (list_ownertrust): New. - * g10.c (aListOwnerTrust): New. - - * g10.c (def_pubkey_algo): Removed. - - * trustdb.c (verify_private_data): Removed and also the call to it. - (sign_private_data): Removed. - -Fri Jul 3 13:26:10 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (aEditKey): was aEditSig. Changed usage msg. - - * keyedit.c: Done some i18n stuff. - - * g10.c (do_not_use_RSA): New. - * sign.c (do_sign): Add call to above function. - * encode.c (write_pubkey_enc_from_list): Ditto. - -Thu Jul 2 21:01:25 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c: Now is able sto store data of unknown - algorithms. - * free-packet.c: Support for this. - * build-packet.c: Can write data of packet with unknown algos. - -Thu Jul 2 11:46:36 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (parse): fixed 4 byte length header - -Wed Jul 1 12:36:55 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h (new_ctb): New field for some packets - * build-packet.c (build_packet): Support for new_ctb - * parse-packet.c (parse): Ditto. - -Mon Jun 29 12:54:45 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h: changed all "_cert" to "_key", "subcert" to "subkey". - - * free-packet.c (free_packet): Removed memory leak for subkeys. - -Sun Jun 28 18:32:27 1998 Werner Koch (wk@isil.d.shuttle.de) - - * import.c (import_keys): Renamed from import_pubkeys. - (import_secret_one): New. - - * g10.c (aExportSecret): New. - - * export.c (export_seckeys): New. - - * parse-packet.c (parse_certificate): Cleaned up. - (parse_packet): Trust packets are now considered as unknown. - (parse_pubkey_warning): New. - -Fri Jun 26 10:37:35 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (has_invalid_email_chars): New. - -Wed Jun 24 16:40:22 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (armor_filter): Now creates valid onepass_sig packets - with all detected hash algorithms. - * mainproc.c (proc_plaintext): Now uses the hash algos as specified - in the onepass_sig packets (if there are any) - -Mon Jun 22 11:54:08 1998 Werner Koch (wk@isil.d.shuttle.de) - - * plaintext.c (handle_plaintext): add arg to disable outout - * mainproc.c (proc_plaintext): disable output when in sigs_only mode. - -Thu Jun 18 13:17:27 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c: Removed all rsa packet stuff, chnaged defaults - for key generation. - -Sun Jun 14 21:28:31 1998 Werner Koch (wk@isil.d.shuttle.de) - - * misc.c (checksum_u16): Fixed a stupid bug which caused a - wrong checksum calculation for the secret key protection and - add a backward compatibility option. - * g10.c (main): Add option --emulate-checksum-bug. - -Thu Jun 11 13:26:44 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h: Major changes to the structure of public key material - which is now stored in an array and not anaymore in a union of - algorithm specific structures. These is needed to make the system - more extendable and makes a lot of stuff much simpler. Changed - all over the system. - - * dsa.c, rsa.c, elg.c: Removed. - -Wed Jun 10 07:22:02 1998 Werner Koch,mobil,,, (wk@tobold) - - * g10.c ("load-extension"): New option. - -Mon Jun 8 22:23:37 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seckey-cert.c (do_check): Removed cipher constants - (protect_secret_key): Ditto. - -Fri May 29 10:00:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (query_trust_info): New. - * keylist.c (list_one): Add output of trust info - * mainproc (list_node): ditto. - * g10.c (main): full trustdb init if -with-colons and any of the - key list modes. - -Thu May 28 10:34:42 1998 Werner Koch (wk@isil.d.shuttle.de) - - * status.c (STATUS_RSA_OR_IDEA): New. - * sig-check.c (check_signature): Output special status message. - * pubkey-enc.c (get_session_key): Ditto. - - * mainproc.c (check_sig_and_print): Changed format of output. - * passpharse.c (passphrase_to_dek): Likewise. - -Wed May 27 13:46:48 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (aListSecretKeys): New option --list-secret-keys - * keylist.c (std_key_list): Renamed to public_key_list. - (secret_key_list): New - (list_one, list_all): Add support for secret keys. - * getkey.c (get_secret_keyring): New. - * mainproc.c (list_node): Add option --with-colons for secret keys - - * sig-check.c (check_key_signature): detection of selfsigs - * mainproc.c (list_node): fixed listing. - - * g10.c (aListSecretKeys): New option --always-trust - * pkclist.c (do_we_trust): Override per option added - - * status.c (write_status_text): Add a prefix to every output line. - -Wed May 27 07:49:21 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10 (--compress-keys): New. - * options.h (compress_keys): New. - * export.c (export_pubkeys): Only compresses with the new option. - -Tue May 26 11:24:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * passphrase.c (get_last_passphrase): New - (set_next_passphrase): New. - (passphrase_to_dek): add support for the above functions. - * keyedit.c (make_keysig_packet): Add sigclass 0x18, - changed all callers due to a new argument. - * keygen.c (write_keybinding): New - (generate_subkeypair): Add functionality - (ask_algo, ask_keysize, ask_valid_days): Broke out of generate_keypair - (ask_user_id, ask_passphrase): Ditto. - -Thu May 21 11:26:13 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c,gpgd.c (main): Does now return an int, so that egcs does - not complain. - - * armor.c (fake_packet): Removed erro message and add a noticed - that this part should be fixed. - - * sign.c (sign_file): Compression now comes in front of encryption. - * encode.c (encode_simple): Ditto. - (encode_crypt): Ditto. - -Tue May 19 16:18:19 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (fake_packet): Changed assertion to log_error - -Sat May 16 16:02:06 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (build_packet): Add SUBKEY packets. - -Fri May 15 17:57:23 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sign.c (hash_for): New and used in all places here. - * main.h (DEFAULT_): new macros. - * g10.c (opt.def_digest_algo): Now set to 0 - - * compress.c (init_compress): Add support for algo 1 - * options.h (def_compress_algo): New - * g10.c (main): New option --compress-algo - -Fri May 15 13:23:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (print_mds): New feature to print only one hash, - chnaged formatting. - -Thu May 14 15:36:24 1998 Werner Koch (wk@isil.d.shuttle.de) - - * misc.c (trap_unaligned) [__alpha__]: New - * g10.c (trap_unaligned): Add call to this to track down SIGBUS - on Alphas (to avoid the slow emulation code). - -Wed May 13 11:48:27 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (do_signature): Support for v4 pakets. - * keyedit.c (make_keysig_packet): Ditto. - * build-packet.c (build_sig_subpkt_from_sig): New. - (build_sig_subpkt): New. - - * elg.c (g10_elg_sign): removed keyid_from_skc. - * dsa.c (g10_dsa_sign): Ditto. - * rsa.c (g10_rsa_sign): Ditto. - * keyedit.c (make_keysig_packet): Add call to keyid_from_skc - - * sign.c (clearsign_file): Support for v4 signatures. - (sign_file): Ditto. - -Wed May 6 09:31:24 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (do_parse): add support for 5 byte length leader. - (parse_subpkt): Ditto. - * build-packet.c (write_new_header): Ditto. - - * packet.h (SIGSUBPKT_): New constants. - * parse-packet.c (parse_sig_subpkt): Changed name, made global, - and arg to return packet length, chnaged all callers - - -Tue May 5 22:11:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (gen_dsa): New. - * build_packet.c (do_secret_cert): Support for DSA - -Mon May 4 19:01:25 1998 Werner Koch (wk@isil.d.shuttle.de) - - * compress.c: doubled buffer sizes - * parse-packet.c (do_plaintext): now uses iobuf_read/write. - -Mon May 4 09:35:53 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seskey.c (encode_md_value): Add optional argument hash_algo, - changed all callers. - - * passphrase.c (make_dek_from_passphrase): Removed - * (get_passhrase_hash): Changed name to passphrase_to_dek, add arg, - changed all callers. - - * all: Introduced the new ELG identifier and added support for the - encryption only one (which is okay to use by GNUPG for signatures). - -Sun May 3 17:50:26 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h (PKT_OLD_COMMENT): New name for type 16. - * parse-packet.c (parse_comment): Now uses type 61 - -Fri May 1 12:44:39 1998 Werner Koch,mobil,,, (wk@tobold) - - * packet.h (count): Chnaged s2k count from byte to u32. - * seckey-cert.c (do_check): Changed s2k algo 3 to 4, changed - reading of count. - * build-packet.c (do_secret_cert): ditto. - * parse-packet.c (parse_certificate): ditto. - - * parse-packet.c (parse_symkeyenc): New. - * build-packet.c (do_symkey_enc): New. - -Thu Apr 30 16:33:34 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sign.c (clearsign_file): Fixed "Hash: " armor line. - -Tue Apr 28 14:27:42 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (parse_subpkt): Some new types. - -Mon Apr 27 12:53:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Add option --skip-verify. - * mainproc.c (check_sig_and_print): Ditto. - - * g10.c (print_mds): Add output for Tiger. - - * sign.c (sign_file): Now uses partial length headers if used - in canonical textmode (kludge to fix a bug). - - * parse-packet.c (parse_certificate): Changed BLOWFISH id. - * pubkey-enc.c (get_session_key): Ditto. - * seskey.c (make_session_key): Ditto. - * seckey-cert.c (protect_secret_key,do_check): Add BLOWFISH160. - -Fri Apr 24 17:38:48 1998 Werner Koch,mobil,,, (wk@tobold) - - * sig-check.c (check_key_signature): Add sig-class 0x14..0x17 - * keyedit.c (sign-key): Some changes to start with support of - the above new sig-classes. - -Wed Apr 22 09:01:57 1998 Werner Koch,mobil,,, (wk@tobold) - - * getkey.c (compare_name): add email matching - -Tue Apr 21 16:17:12 1998 Werner Koch,mobil,,, (wk@tobold) - - * armor.c (armor_filter): fixed missing last LF before CSUM. - -Thu Apr 9 11:35:22 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seckey-cert.c (do_check): New; combines all the check functions - into one. - - * sign.c: removed all key management functions - * keyedit.c: New. - -Thu Apr 9 09:49:36 1998 Werner Koch (wk@isil.d.shuttle.de) - - * import.c (chk_self_sigs): Changed an error message. - -Wed Apr 8 16:19:39 1998 Werner Koch (wk@isil.d.shuttle.de) - - * packet.h: packet structs now uses structs from the pubkey, - removed all copy operations from packet to pubkey structs. - -Wed Apr 8 13:40:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (verify_own_certs): Fixed "public key not found". - - * getkey.c (key_byname): New, combines public and secret key search. - - * pkclist.c (build_pkc_list): Add new arg usage, changed all callers. - * skclist.c (build_skc_list): Likewise. - - * ringedit.c (find_keyblock, keyring_search2): Removed. - -Wed Apr 8 09:47:21 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sig-check.c (do_check): Applied small fix from Ulf Möller. - -Tue Apr 7 19:28:07 1998 Werner Koch (wk@isil.d.shuttle.de) - - * cipher.c, encr-data.c, seckey-cert.c: Now uses cipher_xxxx - functions instead of blowfish_xxx or cast_xxx - -Tue Apr 7 11:04:02 1998 Werner Koch (wk@isil.d.shuttle.de) - - * Makefile.am (g10maint.o): Changed the way it is created. - -Mon Apr 6 11:17:08 1998 Werner Koch (wk@isil.d.shuttle.de) - - * misc.c: New. - * keygen.c (checksum,checksum_u16,checksum_mpi): Moved to misc.c - * seckey-cert.c: Kludge for wrong ELG checksum implementation. - -Sat Apr 4 20:07:01 1998 Werner Koch (wk@isil.d.shuttle.de) - - * cipher.c (cipher_filter): Support for CAST5 - * encr-data.c (decode_filter): Ditto. - (decrypt_data): Ditto. - * seskey.c (make_session_key): Ditto. - * seckey-cert.c (check_elg, check_dsa): Ditto, - (protect_secret_key): Ditto. - * pubkey-enc.c (get_session_key): Ditto. - * passphrase.c (hash_passphrase): Ditto. - -Thu Apr 2 20:22:35 1998 Werner Koch (wk@isil.d.shuttle.de) - - * gpgd.c: New - -Thu Apr 2 10:38:16 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (generate_keypair): Add valid_days stuff. - * trustdb.c (check_trust): Add check for valid_days. - -Wed Apr 1 16:15:58 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (generate_keypair): Addional question whether the - selected large keysize is really needed. - -Wed Apr 1 15:56:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * seckey-cert.c (protect_secret_key): merged protect_xxx to here. - -Wed Apr 1 10:34:46 1998 Werner Koch (wk@isil.d.shuttle.de) - - * Makefile.am (g10maint.c): Changed creation rule, so that it works - on FreeBSD (missing CFLAGS). - - * parse-packet.c (parse_subkey): Removed. - -Thu Mar 19 15:22:36 1998 Werner Koch (wk@isil.d.shuttle.de) - - * ringedit.c (keyring_enum): Fixed problem with reading too - many packets. Add support to read secret keyrings. - - * getkey.c (scan_keyring): Removed - (lookup): New to replace scan_keyring. - (scan_secret_keyring): Removed. - (lookup_skc): New. - -Wed Mar 18 11:47:34 1998 Werner Koch (wk@isil.d.shuttle.de) - - * ringedit.c (enum_keyblocks): New read mode 11. - - * keyid.c (elg_fingerprint_md): New and changed all other functions - to call this if the packet version is 4 or above. - -Tue Mar 17 20:46:16 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (parse_certificate): Add listing support for subkeys. - -Tue Mar 17 20:32:22 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (is_armored): Allow marker packet. - -Thu Mar 12 13:36:49 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (check_trust): Checks timestamp of pubkey. - * sig-check. (do_check): Compares timestamps. - -Tue Mar 10 17:01:56 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Add call to init_signals. - * signal.c: New. - -Mon Mar 9 12:43:42 1998 Werner Koch (wk@isil.d.shuttle.de) - - * dsa.c: New - * packet.h, free-packet.c, parse-packet.c : Add support for DSA - * sig-check.c, getkey.c, keyid.c, ringedit.c: Ditto. - * seckey-cert.c: Ditto. - - * packet.h : Moved .digest_algo of signature packets to outer - structure. Changed all references - -Sun Mar 8 13:06:42 1998 Werner Koch (wk@isil.d.shuttle.de) - - * openfile.c : Support for stdout filename "-". - - * mainproc.c (check_sig_and_print): Enhanced status output: - * status.c (write_status_text): New. - -Fri Mar 6 16:10:54 1998 Werner Koch (wk@isil.d.shuttle.de) - - * kbnode.c (clone_kbnode): Fixed private_flag. - - * mainproc.c (list_node): Output of string "Revoked" as user-id. - -Fri Mar 6 14:26:39 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Add userids to "-kv" and cleaned up this stuff. - -Fri Mar 6 12:45:58 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Changed semantics of the list-... commands - and added a new one. Removed option "-d" - - * decrypt.c: New. - - * trustdb.c (init_trustdb): Autocreate directory only if it ends - in "/.gnupg". - -Thu Mar 5 12:12:11 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c (do_proc_packets): New. Common part of proc_packet. - (proc_signature_packets): special version to handle signature data. - * verify.c: New. - * g10.c (aVerify): New. - * plaintext.c (hash_datafiles): New. - * compress.c (handle_compressed): Add callback arg, changed caller. - -Thu Mar 5 10:20:06 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c: Is nom the common source for gpg and gpgm - * g10maint.c: Removed - * Makefile.am: Add rule to build g10maint.c - -Thu Mar 5 08:43:59 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Changed the way clear text sigs are faked. - -Wed Mar 4 19:47:37 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10maint.c (aMuttKeyList): New - * keylist.c: New. - -Wed Mar 4 17:20:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (get_pubkey_byname): Kludge to allow 0x prefix. - -Tue Mar 3 13:46:55 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10maint.c (main): New option --gen-random. - -Tue Mar 3 09:50:08 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (aDeleteSecretKey): New. - (aEditSig): Add option "--edit-key" as synonym for "--edit-sig". - (aDeleteSecretKey): New. - * getkey.c (seckey_available): New. - * sign.c (delete_key): Enhanced to delete secret keys, changed all - callers. - -Mon Mar 2 21:23:48 1998 Werner Koch (wk@isil.d.shuttle.de) - - * pkc_list.c (build_pkc_list): Add interactive input of user ID. - -Mon Mar 2 20:54:05 1998 Werner Koch (wk@isil.d.shuttle.de) - - * pkclist.c (do_we_trust_pre): New. - (add_ownertrust): Add message. - * trustdb.c (enum_trust_web): Quick fix. - -Mon Mar 2 13:50:53 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): New action aDeleteKey - * sign.c (delete_key): New. - -Sun Mar 1 16:38:58 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (do_check): No returns TRUST_UNDEFINED instead of - eof error. - -Fri Feb 27 18:14:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (find_header): Removed trailing CR on headers. - -Fri Feb 27 18:02:48 1998 Werner Koch (wk@isil.d.shuttle.de) - - * ringedit.c (keyring_search) [MINGW32]: Open and close file here - because rename does not work on open files. Chnaged callers. - -Fri Feb 27 16:43:11 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sig-check.c (do_check): Add an md_enable. - * mainproc.c (do_check_sig): Use md_open in case of detached sig - (proc_tree): Take detached sigs into account. - -Fri Feb 27 15:22:46 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): Make use of GNUPGHOME envvar. - * g10main.c (main): Ditto. - -Wed Feb 25 11:40:04 1998 Werner Koch (wk@isil.d.shuttle.de) - - * plaintext.c (ask_for_detached_datafile): add opt.verbose to - info output. - - * openfile.c (open_sigfile): Try also name ending in ".asc" - -Wed Feb 25 08:41:00 1998 Werner Koch (wk@isil.d.shuttle.de) - - * keygen.c (generate_keypair): Fixed memory overflow. - -Tue Feb 24 15:51:55 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (parse_certificate): Support for S2K. - * build-packet.c (do_secret_cert): Ditto. - * keygen.c (gen_elg): Ditto. - * seckey-cert.c (check_elg): Ditto - (protect_elg): Ditto. - * sign.c (chnage_passphrase): Ditto. - * passphrase.c (get_passphrase_hash): Support for a salt and - changed all callers. - (make_dek_from_passphrase): Ditto. - -Tue Feb 24 12:30:56 1998 Werner Koch (wk@isil.d.shuttle.de) - - * build-packet.c (hash_public_cert): Disabled debug output. - -Fri Feb 20 17:22:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (init_trustdb) [MINGW32]: Removed 2nd mkdir arg. - (keyring_copy) [MINGW32]: Add a remove prior to the renames. - -Wed Feb 18 18:39:02 1998 Werner Koch (wk@isil.d.shuttle.de) - - * Makefile.am (OMIT_DEPENDENCIES): New. - - * rsa.c: Replaced log_bug by BUG. - -Wed Feb 18 13:35:58 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c (do_check_sig): Now uses hash_public_cert. - * parse-packet.c (parse_certificate): Removed hashing. - * packet.h (public_cert): Removed hash variable. - * free-packet.c (copy_public_cert, free_public_cert): Likewise. - - * sig-check.c (check_key_signatures): Changed semantics. - -Wed Feb 18 12:11:28 1998 Werner Koch (wk@isil.d.shuttle.de) - - * trustdb.c (do_check): Add handling for revocation certificates. - (build_sigrecs): Ditto. - (check_sigs): Ditto. - -Wed Feb 18 09:31:04 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (armor_filter): Add afx->hdrlines. - * revoke.c (gen_revoke): Add comment line. - * dearmor.c (enarmor_file): Ditto. - - * sig-check.c (check_key_signature): Add handling for class 0x20. - * mainproc.c : Ditto. - -Tue Feb 17 21:24:17 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c : Add header lines "...ARMORED FILE .." - * dearmor.c (enarmor_file): New. - * g10maint.c (main): New option "--enarmor" - -Tue Feb 17 19:03:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c : Changed a lot, because the packets are now stored - a simple linlked list and not anymore in a complicatd tree structure. - -Tue Feb 17 10:14:48 1998 Werner Koch (wk@isil.d.shuttle.de) - - * free_packet.c (cmp_public_certs): New. - (cmp_user_ids): New. - - * kbnode.c (clone_kbnode): New. - (release_kbnode): Add clone support. - - * ringedit.c (find_keyblock_bypkc): New. - - * sign.c (remove_keysigs): Self signatures are now skipped, - changed arguments and all callers. - - * import.c : Add functionality. - -Tue Feb 17 09:31:40 1998 Werner Koch (wk@isil.d.shuttle.de) - - * options.h (homedir): New option. - * g10.c, g10maint.c, getkey.c, keygen.c, trustdb.c (opt.homedir): New. - - * trustdb.c (init_trustdb): mkdir for hoem directory - (sign_private_data): Renamed "sig" to "g10.sig" - -Mon Feb 16 20:02:03 1998 Werner Koch (wk@isil.d.shuttle.de) - - * kbnode.c (commit_kbnode): New. - (delete_kbnode): removed unused first arg. Changed all Callers. - - * ringedit.c (keyblock_resource_name): New. - (get_keyblock_handle): NULL for filename returns default resource. - -Mon Feb 16 19:38:48 1998 Werner Koch (wk@isil.d.shuttle.de) - - * sig-check.s (check_key_signature): Now uses the supplied - public key to check the signature and not any more the one - from the getkey.c - (do_check): New. - (check_signature): Most work moved to do_check. - -Mon Feb 16 14:48:57 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (find_header): Fixed another bug. - -Mon Feb 16 12:18:34 1998 Werner Koch (wk@isil.d.shuttle.de) - - * getkey.c (scan_keyring): Add handling of compressed keyrings. - -Mon Feb 16 10:44:51 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c, g10maint.c (strusage): Rewrote. - (build_list): New - -Mon Feb 16 08:58:41 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (use_armor): New. - -Sat Feb 14 14:30:57 1998 Werner Koch (wk@isil.d.shuttle.de) - - * mainproc.c (proc_tree): Sigclass fix. - -Sat Feb 14 14:16:33 1998 Werner Koch (wk@isil.d.shuttle.de) - - * armor.c (armor_filter): Changed version and comment string. - * encode.c, sign.c, keygen.c: Changed all comment packet strings. - -Sat Feb 14 12:39:24 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (aGenRevoke): New command. - * revoke.c: New. - * sign.c (make_keysig_packet): Add support for sigclass 0x20. - -Fri Feb 13 20:18:14 1998 Werner Koch (wk@isil.d.shuttle.de) - - * ringedit.c (enum_keyblocks, keyring_enum): New. - -Fri Feb 13 19:33:40 1998 Werner Koch (wk@isil.d.shuttle.de) - - * export.c: Add functionality. - - * keygen.c (generate_keypair): Moved the leading comment behind the - key packet. - * kbnode.c (walk_kbnode): Fixed. - - * g10.c (main): listing armored keys now work. - -Fri Feb 13 16:17:43 1998 Werner Koch (wk@isil.d.shuttle.de) - - * parse-packet.c (parse_publickey, parse_signature): Fixed calls - to mpi_read used for ELG b. - -Fri Feb 13 15:13:23 1998 Werner Koch (wk@isil.d.shuttle.de) - - * g10.c (main): changed formatting of help output. - -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 deleted file mode 100644 index d84707af8..000000000 --- a/g10/Makefile.am +++ /dev/null @@ -1,123 +0,0 @@ -# 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.. -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@ -needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a - -#noinst_PROGRAMS = gpgd -bin_PROGRAMS = gpg gpgv - -common_source = \ - global.h \ - build-packet.c \ - compress.c \ - filter.h \ - free-packet.c \ - getkey.c \ - keydb.c keydb.h \ - keyring.c keyring.h \ - seskey.c \ - kbnode.c \ - main.h \ - mainproc.c \ - armor.c \ - mdfilter.c \ - textfilter.c \ - misc.c \ - options.h \ - openfile.c \ - keyid.c \ - packet.h \ - parse-packet.c \ - comment.c \ - status.c \ - status.h \ - plaintext.c \ - sig-check.c \ - keylist.c \ - signal.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 \ - import.c \ - export.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 - - - - -#gpgd_SOURCES = gpgd.c \ -# ks-proto.h \ -# ks-proto.c \ -# ks-db.c \ -# ks-db.h \ -# $(common_source) - -LDADD = $(needed_libs) @ZLIBS@ @INTLLIBS@ -# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it -gpg_LDADD = @LIBOBJS@ $(LDADD) @EGDLIBS@ - -$(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 deleted file mode 100644 index 9c7858fe6..000000000 --- a/g10/armor.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* armor.c - Armor flter - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <ctype.h> - -#include "errors.h" -#include "iobuf.h" -#include "memory.h" -#include "util.h" -#include "filter.h" -#include "packet.h" -#include "options.h" -#include "main.h" -#include "status.h" -#include "i18n.h" - -#ifdef HAVE_DOSISH_SYSTEM - #define LF "\r\n" -#else - #define LF "\n" -#endif - -#define MAX_LINELEN 20000 - -#define CRCINIT 0xB704CE -#define CRCPOLY 0X864CFB -#define CRCUPDATE(a,c) do { \ - a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \ - a &= 0x00ffffff; \ - } while(0) -static u32 crc_table[256]; -static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; -static byte asctobin[256]; /* runtime initialized */ -static int is_initialized; - - -typedef enum { - fhdrHASArmor = 0, - fhdrNOArmor, - fhdrINIT, - fhdrINITCont, - fhdrINITSkip, - fhdrCHECKBegin, - fhdrWAITHeader, - fhdrWAITClearsig, - fhdrSKIPHeader, - fhdrCLEARSIG, - fhdrREADClearsig, - fhdrNullClearsig, - fhdrEMPTYClearsig, - fhdrCHECKClearsig, - fhdrCHECKClearsig2, - fhdrCHECKDashEscaped, - fhdrCHECKDashEscaped2, - fhdrCHECKDashEscaped3, - fhdrREADClearsigNext, - fhdrENDClearsig, - fhdrENDClearsigHelp, - fhdrTESTSpaces, - fhdrCLEARSIGSimple, - fhdrCLEARSIGSimpleNext, - fhdrTEXT, - fhdrTEXTSimple, - fhdrERROR, - fhdrERRORShow, - fhdrEOF -} fhdr_state_t; - - -/* if we encounter this armor string with this index, go - * into a mode which fakes packets and wait for the next armor */ -#define BEGIN_SIGNATURE 2 -#define BEGIN_SIGNED_MSG_IDX 3 -static char *head_strings[] = { - "BEGIN PGP MESSAGE", - "BEGIN PGP PUBLIC KEY BLOCK", - "BEGIN PGP SIGNATURE", - "BEGIN PGP SIGNED MESSAGE", - "BEGIN PGP ARMORED FILE", /* gnupg extension */ - "BEGIN PGP PRIVATE KEY BLOCK", - "BEGIN PGP SECRET KEY BLOCK", /* only used by pgp2 */ - NULL -}; -static char *tail_strings[] = { - "END PGP MESSAGE", - "END PGP PUBLIC KEY BLOCK", - "END PGP SIGNATURE", - "END dummy", - "END PGP ARMORED FILE", - "END PGP PRIVATE KEY BLOCK", - "END PGP SECRET KEY BLOCK", - NULL -}; - - - -static void -initialize(void) -{ - int i, j; - u32 t; - byte *s; - - /* init the crc lookup table */ - crc_table[0] = 0; - for(i=j=0; j < 128; j++ ) { - t = crc_table[j]; - if( t & 0x00800000 ) { - t <<= 1; - crc_table[i++] = t ^ CRCPOLY; - crc_table[i++] = t; - } - else { - t <<= 1; - crc_table[i++] = t; - crc_table[i++] = t ^ CRCPOLY; - } - } - /* build the helptable for radix64 to bin conversion */ - for(i=0; i < 256; i++ ) - asctobin[i] = 255; /* used to detect invalid characters */ - for(s=bintoasc,i=0; *s; s++,i++ ) - asctobin[*s] = i; - - is_initialized=1; -} - -/**************** - * 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 -is_armored( const byte *buf ) -{ - int ctb, pkttype; - - ctb = *buf; - if( !(ctb & 0x80) ) - return 1; /* invalid packet: assume it is armored */ - pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf); - switch( pkttype ) { - case PKT_MARKER: - case PKT_SYMKEY_ENC: - case PKT_ONEPASS_SIG: - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - case PKT_PUBKEY_ENC: - case PKT_SIGNATURE: - case PKT_COMMENT: - case PKT_OLD_COMMENT: - case PKT_PLAINTEXT: - case PKT_COMPRESSED: - case PKT_ENCRYPTED: - return 0; /* seems to be a regular packet: not armored */ - } - - return 1; -} - - -/**************** - * Try to check whether the iobuf is armored - * Returns true if this may be the case; the caller should use the - * filter to do further processing. - */ -int -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 */ - if( !n ) - return 1; /* can't check it: try armored */ - return is_armored(buf); -} - - - - -static void -invalid_armor(void) -{ - write_status(STATUS_BADARMOR); - g10_exit(1); /* stop here */ -} - - -/**************** - * check whether the armor header is valid on a signed message. - * this is for security reasons: the header lines are not included in the - * hash and by using some creative formatting rules, Mallory could fake - * any text at the beginning of a document; assuming it is read with - * a simple viewer. We only allow the Hash Header. - */ -static int -parse_hash_header( const char *line ) -{ - const char *s, *s2; - unsigned found = 0; - - if( strlen(line) < 6 || strlen(line) > 60 ) - return 0; /* too short or too long */ - if( memcmp( line, "Hash:", 5 ) ) - return 0; /* invalid header */ - s = line+5; - for(s=line+5;;s=s2) { - for(; *s && (*s==' ' || *s == '\t'); s++ ) - ; - if( !*s ) - break; - for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ ) - ; - if( !strncmp( s, "RIPEMD160", s2-s ) ) - found |= 1; - else if( !strncmp( s, "SHA1", s2-s ) ) - found |= 2; - else if( !strncmp( s, "MD5", s2-s ) ) - found |= 4; - 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; - for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ ) - ; - if( *s2 && *s2 != ',' ) - return 0; - if( *s2 ) - s2++; - } - return found; -} - - - -/**************** - * Check whether this is a armor line. - * returns: -1 if it is not a armor header or the index number of the - * armor header. - */ -static int -is_armor_header( byte *line, unsigned len ) -{ - const char *s; - byte *save_p, *p; - int save_c; - int i; - - if( len < 15 ) - return -1; /* too short */ - if( memcmp( line, "-----", 5 ) ) - return -1; /* no */ - p = strstr( line+5, "-----"); - if( !p ) - 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' ) - p++; - if( *p ) - return -1; /* garbage after dashes */ - save_c = *save_p; *save_p = 0; - p = line+5; - for(i=0; (s=head_strings[i]); i++ ) - if( !strcmp(s, p) ) - break; - *save_p = save_c; - if( !s ) - return -1; /* unknown armor line */ - - if( opt.verbose > 1 ) - log_info(_("armor: %s\n"), head_strings[i]); - return i; -} - - - -/**************** - * Parse a header lines - * Return 0: Empty line (end of header lines) - * -1: invalid header line - * >0: Good header line - */ -static int -parse_header_line( armor_filter_context_t *afx, byte *line, unsigned int len ) -{ - byte *p; - int hashes=0; - unsigned int len2; - - 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] ) { - log_error(_("invalid armor header: ")); - print_string( stderr, line, len, 0 ); - putc('\n', stderr); - return -1; - } - - if( opt.verbose ) { - log_info(_("armor header: ")); - print_string( stderr, line, len, 0 ); - putc('\n', stderr); - } - - if( afx->in_cleartext ) { - if( (hashes=parse_hash_header( line )) ) - afx->hashes |= hashes; - else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) ) - afx->not_dash_escaped = 1; - else { - log_error(_("invalid clearsig header\n")); - return -1; - } - } - return 1; -} - - - -/* figure out whether the data is armored or not */ -static int -check_input( armor_filter_context_t *afx, IOBUF a ) -{ - int rc = 0; - int i; - byte *line; - unsigned len; - unsigned maxlen; - int hdr_line = -1; - - /* read the first line to see whether this is armored data */ - maxlen = MAX_LINELEN; - len = afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - line = afx->buffer; - if( !maxlen ) { - /* line has been truncated: assume not armored */ - afx->inp_checked = 1; - afx->inp_bypass = 1; - return 0; - } - - if( !len ) { - return -1; /* eof */ - } - - /* (the line is always a C string but maybe longer) */ - if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) ) - ; - else if( !is_armored( line ) ) { - afx->inp_checked = 1; - afx->inp_bypass = 1; - return 0; - } - - /* find the armor header */ - while(len) { - i = is_armor_header( line, len ); - if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) { - hdr_line = i; - if( hdr_line == BEGIN_SIGNED_MSG_IDX ) { - if( afx->in_cleartext ) { - log_error(_("nested clear text signatures\n")); - rc = G10ERR_INVALID_ARMOR; - } - afx->in_cleartext = 1; - } - break; - } - /* read the next line (skip all truncated lines) */ - do { - maxlen = MAX_LINELEN; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - line = afx->buffer; - len = afx->buffer_len; - } while( !maxlen ); - } - - /* parse the header lines */ - while(len) { - /* read the next line (skip all truncated lines) */ - do { - maxlen = MAX_LINELEN; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - line = afx->buffer; - len = afx->buffer_len; - } while( !maxlen ); - - i = parse_header_line( afx, line, len ); - if( i <= 0 ) { - if( i ) - rc = G10ERR_INVALID_ARMOR; - break; - } - } - - - if( rc ) - invalid_armor(); - else if( afx->in_cleartext ) - afx->faked = 1; - else { - afx->inp_checked = 1; - afx->crc = CRCINIT; - afx->idx = 0; - afx->radbuf[0] = 0; - } - - return rc; -} - - - -/**************** - * Fake a literal data packet and wait for the next armor line - * fixme: empty line handling and null length clear text signature are - * not implemented/checked. - */ -static int -fake_packet( armor_filter_context_t *afx, IOBUF a, - size_t *retn, byte *buf, size_t size ) -{ - int rc = 0; - size_t len = 0; - int lastline = 0; - unsigned maxlen, n; - byte *p; - - len = 2; /* reserve 2 bytes for the length header */ - size -= 2; /* and 2 for the terminating header */ - while( !rc && len < size ) { - /* copy what we have in the line buffer */ - if( afx->faked == 1 ) - afx->faked++; /* skip the first (empty) line */ - else { - while( len < size && afx->buffer_pos < afx->buffer_len ) - buf[len++] = afx->buffer[afx->buffer_pos++]; - if( len >= size ) - continue; - } - - /* read the next line */ - maxlen = MAX_LINELEN; - afx->buffer_pos = 0; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - if( !afx->buffer_len ) { - rc = -1; /* eof (should not happen) */ - continue; - } - if( !maxlen ) - afx->truncated++; - if( !afx->not_dash_escaped ) { - int crlf; - p = afx->buffer; - n = afx->buffer_len; - crlf = n > 1 && p[n-2] == '\r' && p[n-1]=='\n'; - - /* PGP2 does not treat a tab as white space character */ - afx->buffer_len = trim_trailing_chars( p, n, - afx->pgp2mode ? " \r\n" : " \t\r\n"); - /* 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 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 - * a way to send the hash down the processing line (well, a special - * faked packet could do the job). - */ - if( crlf ) - afx->buffer[afx->buffer_len++] = '\r'; - afx->buffer[afx->buffer_len++] = '\n'; - afx->buffer[afx->buffer_len] = 0; - } - p = afx->buffer; - n = afx->buffer_len; - - if( n > 2 && *p == '-' ) { - /* check for dash escaped or armor header */ - if( p[1] == ' ' && !afx->not_dash_escaped ) { - /* issue a warning if it is not regular encoded */ - if( p[2] != '-' && !( n > 6 && !memcmp(p+2, "From ", 5))) { - log_info(_("invalid dash escaped line: ")); - print_string( stderr, p, n, 0 ); - putc('\n', stderr); - } - afx->buffer_pos = 2; /* skip */ - } - else if( n >= 15 && p[1] == '-' && p[2] == '-' && p[3] == '-' ) { - int type = is_armor_header( p, n ); - if( afx->not_dash_escaped && type != BEGIN_SIGNATURE ) - ; /* this is okay */ - else { - if( type != BEGIN_SIGNATURE ) { - log_info(_("unexpected armor:")); - print_string( stderr, p, n, 0 ); - putc('\n', stderr); - } - lastline = 1; - rc = -1; - } - } - } - } - - buf[0] = (len-2) >> 8; - buf[1] = (len-2); - if( lastline ) { /* write last (ending) length header */ - if( buf[0] || buf[1] ) { /* only if we have some text */ - buf[len++] = 0; - buf[len++] = 0; - } - rc = 0; - afx->faked = 0; - afx->in_cleartext = 0; - /* and now read the header lines */ - afx->buffer_pos = 0; - for(;;) { - int i; - - /* read the next line (skip all truncated lines) */ - do { - maxlen = MAX_LINELEN; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - } while( !maxlen ); - p = afx->buffer; - n = afx->buffer_len; - if( !n ) { - rc = -1; - break; /* eof */ - } - i = parse_header_line( afx, p , n ); - if( i <= 0 ) { - if( i ) - invalid_armor(); - break; - } - } - afx->inp_checked = 1; - afx->crc = CRCINIT; - afx->idx = 0; - afx->radbuf[0] = 0; - } - - *retn = len; - return rc; -} - - -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, - byte *buf, size_t size ) -{ - byte val; - int c=0, c2; /*init c because gcc is not clever enough for the continue*/ - int checkcrc=0; - int rc = 0; - size_t n = 0; - int idx, i; - u32 crc; - - crc = afx->crc; - idx = afx->idx; - val = afx->radbuf[0]; - for( n=0; n < size; ) { - - if( afx->buffer_pos < afx->buffer_len ) - c = afx->buffer[afx->buffer_pos++]; - else { /* read the next line */ - unsigned maxlen = MAX_LINELEN; - afx->buffer_pos = 0; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - if( !maxlen ) - afx->truncated++; - if( !afx->buffer_len ) - break; /* eof */ - continue; - } - - again: - if( c == '\n' || c == ' ' || c == '\r' || c == '\t' ) - continue; - else if( c == '=' ) { /* pad character: stop */ - /* some mailers leave quoted-printable encoded characters - * so we try to workaround this */ - if( afx->buffer_pos+2 < afx->buffer_len ) { - int cc1, cc2, cc3; - cc1 = afx->buffer[afx->buffer_pos]; - cc2 = afx->buffer[afx->buffer_pos+1]; - cc3 = afx->buffer[afx->buffer_pos+2]; - if( isxdigit(cc1) && isxdigit(cc2) - && strchr( "=\n\r\t ", cc3 )) { - /* well it seems to be the case - adjust */ - c = isdigit(cc1)? (cc1 - '0'): (ascii_toupper(cc1)-'A'+10); - c <<= 4; - c |= isdigit(cc2)? (cc2 - '0'): (ascii_toupper(cc2)-'A'+10); - afx->buffer_pos += 2; - afx->qp_detected = 1; - goto again; - } - } - - if( idx == 1 ) - buf[n++] = val; - checkcrc++; - break; - } - else if( (c = asctobin[(c2=c)]) == 255 ) { - log_error(_("invalid radix64 character %02x skipped\n"), c2); - continue; - } - switch(idx) { - case 0: val = c << 2; break; - case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break; - case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break; - case 3: val |= c&0x3f; buf[n++] = val; break; - } - idx = (idx+1) % 4; - } - - for(i=0; i < n; i++ ) - crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; - crc &= 0x00ffffff; - afx->crc = crc; - afx->idx = idx; - afx->radbuf[0] = val; - - if( checkcrc ) { - afx->any_data = 1; - afx->inp_checked=0; - afx->faked = 0; - for(;;) { /* skip lf and pad characters */ - if( afx->buffer_pos < afx->buffer_len ) - c = afx->buffer[afx->buffer_pos++]; - else { /* read the next line */ - unsigned maxlen = MAX_LINELEN; - afx->buffer_pos = 0; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, &maxlen ); - if( !maxlen ) - afx->truncated++; - if( !afx->buffer_len ) - break; /* eof */ - continue; - } - if( c == '\n' || c == ' ' || c == '\r' - || c == '\t' || c == '=' ) - continue; - break; - } - if( c == -1 ) - log_error(_("premature eof (no CRC)\n")); - else { - u32 mycrc = 0; - idx = 0; - do { - if( (c = asctobin[c]) == 255 ) - break; - switch(idx) { - case 0: val = c << 2; break; - case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break; - case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break; - case 3: val |= c&0x3f; mycrc |= val; break; - } - for(;;) { - if( afx->buffer_pos < afx->buffer_len ) - c = afx->buffer[afx->buffer_pos++]; - else { /* read the next line */ - unsigned maxlen = MAX_LINELEN; - afx->buffer_pos = 0; - afx->buffer_len = iobuf_read_line( a, &afx->buffer, - &afx->buffer_size, - &maxlen ); - if( !maxlen ) - afx->truncated++; - if( !afx->buffer_len ) - break; /* eof */ - continue; - } - break; - } - if( !afx->buffer_len ) - break; /* eof */ - } while( ++idx < 4 ); - if( c == -1 ) { - log_info(_("premature eof (in CRC)\n")); - rc = invalid_crc(); - } - else if( idx != 4 ) { - log_info(_("malformed CRC\n")); - rc = invalid_crc(); - } - else if( mycrc != afx->crc ) { - log_info (_("CRC error; %06lx - %06lx\n"), - (ulong)afx->crc, (ulong)mycrc); - 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 )*/; - if( !rc ) { - if( (c=iobuf_get(a)) == -1 ) - rc = 2; - } - } - if( rc == -1 ) - rc = 0; - else if( rc == 2 ) { - log_error(_("premature eof (in Trailer)\n")); - rc = G10ERR_INVALID_ARMOR; - } - else { - log_error(_("error in trailer line\n")); - rc = G10ERR_INVALID_ARMOR; - } - #endif - } - } - } - - if( !n ) - rc = -1; - - *retn = n; - return rc; -} - -/**************** - * This filter is used to handle the armor stuff - */ -int -armor_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) -{ - size_t size = *ret_len; - armor_filter_context_t *afx = opaque; - int rc=0, i, c; - byte radbuf[3]; - int idx, idx2; - size_t n=0; - u32 crc; - #if 0 - static FILE *fp ; - - if( !fp ) { - fp = fopen("armor.out", "w"); - assert(fp); - } - #endif - - if( DBG_FILTER ) - log_debug("armor-filter: control: %d\n", control ); - if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) { - n = 0; - if( afx->buffer_len ) { - for(; n < size && afx->buffer_pos < afx->buffer_len; n++ ) - buf[n++] = afx->buffer[afx->buffer_pos++]; - if( afx->buffer_pos >= afx->buffer_len ) - afx->buffer_len = 0; - } - for(; n < size; n++ ) { - if( (c=iobuf_get(a)) == -1 ) - break; - buf[n] = c & 0xff; - } - if( !n ) - rc = -1; - *ret_len = n; - } - else if( control == IOBUFCTRL_UNDERFLOW ) { - /* 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 ) - rc = fake_packet( afx, a, &n, buf, size ); - else if( !afx->inp_checked ) { - rc = check_input( afx, a ); - if( afx->inp_bypass ) { - for(n=0; n < size && afx->buffer_pos < afx->buffer_len; ) - buf[n++] = afx->buffer[afx->buffer_pos++]; - if( afx->buffer_pos >= afx->buffer_len ) - afx->buffer_len = 0; - if( !n ) - rc = -1; - } - else if( afx->faked ) { - 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 */ - - hashes &= 1|2|4|8; - if( !hashes ) { - hashes |= 4; /* default to MD 5 */ - if( opt.pgp2_workarounds ) - afx->pgp2mode = 1; - } - n=0; - /* 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 */ - buf[n++] = 0; /* set the length header */ - buf[n++] = 6; - buf[n++] = 't'; /* canonical text mode */ - buf[n++] = 0; /* namelength */ - memset(buf+n, 0, 4); /* timestamp */ - n += 4; - } - else if( !rc ) - rc = radix64_read( afx, a, &n, buf, size ); - } - else - rc = radix64_read( afx, a, &n, buf, size ); - #if 0 - if( n ) - if( fwrite(buf, n, 1, fp ) != 1 ) - BUG(); - #endif - *ret_len = n; - } - else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) { - if( !afx->status ) { /* write the header line */ - const char *s; - - if( afx->what >= DIM(head_strings) ) - log_bug("afx->what=%d", afx->what); - iobuf_writestr(a, "-----"); - iobuf_writestr(a, head_strings[afx->what] ); - iobuf_writestr(a, "-----" LF ); - if( !opt.no_version ) - iobuf_writestr(a, "Version: GnuPG v" VERSION " (" - PRINTABLE_OS_NAME ")" LF ); - - /* write the comment string or a default one */ - s = opt.comment_string; - if( s && *s ) { - iobuf_writestr(a, "Comment: " ); - for( ; *s; s++ ) { - if( *s == '\n' ) - iobuf_writestr(a, "\\n" ); - else if( *s == '\r' ) - iobuf_writestr(a, "\\r" ); - else if( *s == '\v' ) - iobuf_writestr(a, "\\v" ); - else - iobuf_put(a, *s ); - } - iobuf_writestr(a, LF ); - } - - 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; - afx->idx2 = 0; - afx->crc = CRCINIT; - - } - crc = afx->crc; - idx = afx->idx; - idx2 = afx->idx2; - for(i=0; i < idx; i++ ) - radbuf[i] = afx->radbuf[i]; - - for(i=0; i < size; i++ ) - crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]]; - crc &= 0x00ffffff; - - for( ; size; buf++, size-- ) { - radbuf[idx++] = *buf; - if( idx > 2 ) { - idx = 0; - c = bintoasc[(*radbuf >> 2) & 077]; - iobuf_put(a, c); - c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; - iobuf_put(a, c); - c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; - iobuf_put(a, c); - c = bintoasc[radbuf[2]&077]; - iobuf_put(a, c); - if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */ - iobuf_writestr(a, LF ); - idx2=0; - } - } - } - for(i=0; i < idx; i++ ) - afx->radbuf[i] = radbuf[i]; - afx->idx = idx; - afx->idx2 = idx2; - afx->crc = crc; - } - else if( control == IOBUFCTRL_INIT ) { - if( !is_initialized ) - initialize(); - } - else if( control == IOBUFCTRL_CANCEL ) { - afx->cancel = 1; - } - else if( control == IOBUFCTRL_FREE ) { - if( afx->cancel ) - ; - else if( afx->status ) { /* pad, write cecksum, and bottom line */ - crc = afx->crc; - idx = afx->idx; - idx2 = afx->idx2; - for(i=0; i < idx; i++ ) - radbuf[i] = afx->radbuf[i]; - if( idx ) { - c = bintoasc[(*radbuf>>2)&077]; - iobuf_put(a, c); - if( idx == 1 ) { - c = bintoasc[((*radbuf << 4) & 060) & 077]; - iobuf_put(a, c); - iobuf_put(a, '='); - iobuf_put(a, '='); - } - else { /* 2 */ - c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; - iobuf_put(a, c); - c = bintoasc[((radbuf[1] << 2) & 074) & 077]; - iobuf_put(a, c); - iobuf_put(a, '='); - } - if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */ - iobuf_writestr(a, LF ); - idx2=0; - } - } - /* may need a linefeed */ - if( idx2 ) - iobuf_writestr(a, LF ); - /* write the CRC */ - iobuf_put(a, '='); - radbuf[0] = crc >>16; - radbuf[1] = crc >> 8; - radbuf[2] = crc; - c = bintoasc[(*radbuf >> 2) & 077]; - iobuf_put(a, c); - c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; - iobuf_put(a, c); - c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; - iobuf_put(a, c); - c = bintoasc[radbuf[2]&077]; - iobuf_put(a, c); - iobuf_writestr(a, LF ); - /* and the the trailer */ - if( afx->what >= DIM(tail_strings) ) - log_bug("afx->what=%d", afx->what); - iobuf_writestr(a, "-----"); - iobuf_writestr(a, tail_strings[afx->what] ); - iobuf_writestr(a, "-----" LF ); - } - else if( !afx->any_data && !afx->inp_bypass ) { - log_error(_("no valid OpenPGP data found.\n")); - afx->no_openpgp_data = 1; - write_status_text( STATUS_NODATA, "1" ); - } - if( afx->truncated ) - log_info(_("invalid armor: line longer than %d characters\n"), - MAX_LINELEN ); - /* issue an error to enforce dissemination of correct software */ - if( afx->qp_detected ) - log_error(_("quoted printable character in armor - " - "probably a buggy MTA has been used\n") ); - m_free( afx->buffer ); - afx->buffer = NULL; - } - else if( control == IOBUFCTRL_DESC ) - *(char**)buf = "armor_filter"; - return rc; -} - - -/**************** - * create a radix64 encoded string. - */ -char * -make_radix64_string( const byte *data, size_t len ) -{ - char *buffer, *p; - - 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]; - *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077]; - *p++ = bintoasc[data[2]&077]; - } - if( len == 2 ) { - *p++ = bintoasc[(data[0] >> 2) & 077]; - *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077]; - *p++ = bintoasc[((data[1]<<2)&074)]; - } - else if( len == 1 ) { - *p++ = bintoasc[(data[0] >> 2) & 077]; - *p++ = bintoasc[(data[0] <<4)&060]; - } - *p = 0; - 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 deleted file mode 100644 index da1cbbe39..000000000 --- a/g10/build-packet.c +++ /dev/null @@ -1,1167 +0,0 @@ -/* build-packet.c - assemble packets and write them - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.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" - - -static int do_comment( IOBUF out, int ctb, PKT_comment *rem ); -static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ); -static int do_public_key( IOBUF out, int ctb, PKT_public_key *pk ); -static int do_secret_key( IOBUF out, int ctb, PKT_secret_key *pk ); -static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ); -static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ); -static u32 calc_plaintext( PKT_plaintext *pt ); -static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ); -static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ); -static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ); -static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ); -static int do_signature( IOBUF out, int ctb, PKT_signature *sig ); -static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ); - -static int calc_header_length( u32 len, int new_ctb ); -static int write_16(IOBUF inp, u16 a); -static int write_32(IOBUF inp, u32 a); -static int write_header( IOBUF out, int ctb, u32 len ); -static int write_sign_packet_header( IOBUF out, int ctb, u32 len ); -static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode ); -static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ); -static int write_version( IOBUF out, int ctb ); - -/**************** - * Build a packet and write it to INP - * Returns: 0 := okay - * >0 := error - * Note: Caller must free the packet - */ -int -build_packet( IOBUF out, PACKET *pkt ) -{ - int new_ctb=0, rc=0, ctb; - int pkttype; - - if( DBG_PACKET ) - log_debug("build_packet() type=%d\n", pkt->pkttype ); - assert( pkt->pkt.generic ); - - switch( (pkttype = pkt->pkttype) ) { - case PKT_OLD_COMMENT: pkttype = pkt->pkttype = PKT_COMMENT; break; - case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; - case PKT_ENCRYPTED: - 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->attrib_data ) - pkttype = PKT_ATTRIBUTE; - break; - default: break; - } - - if( new_ctb || pkttype > 15 ) /* new format */ - ctb = 0xc0 | (pkttype & 0x3f); - else - ctb = 0x80 | ((pkttype & 15)<<2); - switch( pkttype ) { - case PKT_ATTRIBUTE: - case PKT_USER_ID: - rc = do_user_id( out, ctb, pkt->pkt.user_id ); - break; - case PKT_COMMENT: - rc = do_comment( out, ctb, pkt->pkt.comment ); - break; - case PKT_PUBLIC_SUBKEY: - case PKT_PUBLIC_KEY: - rc = do_public_key( out, ctb, pkt->pkt.public_key ); - break; - case PKT_SECRET_SUBKEY: - case PKT_SECRET_KEY: - rc = do_secret_key( out, ctb, pkt->pkt.secret_key ); - break; - case PKT_SYMKEY_ENC: - rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc ); - break; - case PKT_PUBKEY_ENC: - rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc ); - break; - case PKT_PLAINTEXT: - rc = do_plaintext( out, ctb, pkt->pkt.plaintext ); - break; - case PKT_ENCRYPTED: - rc = do_encrypted( out, ctb, pkt->pkt.encrypted ); - break; - case PKT_ENCRYPTED_MDC: - rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted ); - break; - case PKT_COMPRESSED: - rc = do_compressed( out, ctb, pkt->pkt.compressed ); - break; - case PKT_SIGNATURE: - rc = do_signature( out, ctb, pkt->pkt.signature ); - break; - case PKT_ONEPASS_SIG: - rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig ); - break; - case PKT_RING_TRUST: - break; /* ignore it (keyring.c does write it directly)*/ - case PKT_MDC: /* we write it directly, so we should never see it here. */ - default: - log_bug("invalid packet type in build_packet()\n"); - break; - } - - return rc; -} - -/**************** - * calculate the length of a packet described by PKT - */ -u32 -calc_packet_length( PACKET *pkt ) -{ - u32 n=0; - int new_ctb = 0; - - assert( pkt->pkt.generic ); - switch( pkt->pkttype ) { - case PKT_PLAINTEXT: - n = calc_plaintext( pkt->pkt.plaintext ); - new_ctb = pkt->pkt.plaintext->new_ctb; - break; - case PKT_ATTRIBUTE: - case PKT_USER_ID: - case PKT_COMMENT: - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - case PKT_SYMKEY_ENC: - case PKT_PUBKEY_ENC: - case PKT_ENCRYPTED: - case PKT_SIGNATURE: - case PKT_ONEPASS_SIG: - case PKT_RING_TRUST: - case PKT_COMPRESSED: - default: - log_bug("invalid packet type in calc_packet_length()"); - break; - } - - n += calc_header_length(n, new_ctb); - return n; -} - -static void -write_fake_data( IOBUF out, MPI a ) -{ - if( a ) { - int i; - void *p; - - p = mpi_get_opaque( a, &i ); - iobuf_write( out, p, i ); - } -} - - -static int -do_comment( IOBUF out, int ctb, PKT_comment *rem ) -{ - if( opt.sk_comments ) { - write_header(out, ctb, rem->len); - if( iobuf_write( out, rem->data, rem->len ) ) - return G10ERR_WRITE_FILE; - } - return 0; -} - -static int -do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) -{ - 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); - if( iobuf_write( out, uid->name, uid->len ) ) - return G10ERR_WRITE_FILE; - } - return 0; -} - -static int -do_public_key( IOBUF out, int ctb, PKT_public_key *pk ) -{ - int rc = 0; - int n, i; - IOBUF a = iobuf_temp(); - - if( !pk->version ) - iobuf_put( a, 3 ); - else - iobuf_put( a, pk->version ); - write_32(a, pk->timestamp ); - if( pk->version < 4 ) { - u16 ndays; - if( pk->expiredate ) - ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L); - else - ndays = 0; - write_16(a, ndays ); - } - iobuf_put(a, pk->pubkey_algo ); - n = pubkey_get_npkey( pk->pubkey_algo ); - if( !n ) - write_fake_data( a, pk->pkey[0] ); - for(i=0; i < n; i++ ) - mpi_write(a, pk->pkey[i] ); - - write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 ); - if( iobuf_write_temp( out, a ) ) - rc = G10ERR_WRITE_FILE; - - iobuf_close(a); - return rc; -} - - -/**************** - * Make a hash value from the public key certificate - */ -void -hash_public_key( MD_HANDLE md, PKT_public_key *pk ) -{ - PACKET pkt; - int rc = 0; - int ctb; - ulong pktlen; - int c; - IOBUF a = iobuf_temp(); - #if 0 - FILE *fp = fopen("dump.pk", "a"); - int i=0; - - fprintf(fp, "\nHashing PK (v%d):\n", pk->version); - #endif - - /* build the packet */ - init_packet(&pkt); - 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", g10_errstr(rc)); - - if( !(pk->version == 3 && pk->pubkey_algo == 16) ) { - /* skip the constructed header but don't do this for our very old - * v3 ElG keys */ - ctb = iobuf_get_noeof(a); - pktlen = 0; - if( (ctb & 0x40) ) { - c = iobuf_get_noeof(a); - if( c < 192 ) - pktlen = c; - else if( c < 224 ) { - pktlen = (c - 192) * 256; - c = iobuf_get_noeof(a); - pktlen += c + 192; - } - else if( c == 255 ) { - pktlen = iobuf_get_noeof(a) << 24; - pktlen |= iobuf_get_noeof(a) << 16; - pktlen |= iobuf_get_noeof(a) << 8; - pktlen |= iobuf_get_noeof(a); - } - } - else { - int lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); - for( ; lenbytes; lenbytes-- ) { - pktlen <<= 8; - pktlen |= iobuf_get_noeof(a); - } - } - /* hash a header */ - md_putc( md, 0x99 ); - pktlen &= 0xffff; /* can't handle longer packets */ - md_putc( md, pktlen >> 8 ); - md_putc( md, pktlen & 0xff ); - } - /* hash the packet body */ - while( (c=iobuf_get(a)) != -1 ) { - #if 0 - fprintf( fp," %02x", c ); - if( (++i == 24) ) { - putc('\n', fp); - i=0; - } - #endif - md_putc( md, c ); - } - #if 0 - putc('\n', fp); - fclose(fp); - #endif - iobuf_cancel(a); -} - - -static int -do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) -{ - int rc = 0; - int i, nskey, npkey; - 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, 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 { - /* 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 ) { - /* These modes are not possible in OpenPGP, we use them - to implement our extensions, 101 can be seen 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 ); - } - else { - iobuf_put(a, sk->protect.s2k.mode ); - iobuf_put(a, sk->protect.s2k.hash_algo ); - } - if( sk->protect.s2k.mode == 1 - || 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 ); - - /* 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; - assert( mpi_is_opaque( sk->skey[npkey] ) ); - p = mpi_get_opaque( sk->skey[npkey], &i ); - iobuf_write(a, p, i ); - } - else if( sk->is_protected ) { - /* The secret key is protected te old v4 way. */ - for( ; i < nskey; i++ ) { - byte *p; - int ndata; - - assert (mpi_is_opaque (sk->skey[i])); - p = mpi_get_opaque (sk->skey[i], &ndata); - iobuf_write (a, p, ndata); - } - write_16(a, sk->csum ); - } - else { - /* 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 = G10ERR_WRITE_FILE; - - iobuf_close(a); /* close the remporary buffer */ - return rc; -} - -static int -do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) -{ - int rc = 0; - IOBUF a = iobuf_temp(); - - assert( enc->version == 4 ); - switch( enc->s2k.mode ) { - case 0: case 1: case 3: break; - default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode ); - } - iobuf_put( a, enc->version ); - iobuf_put( a, enc->cipher_algo ); - iobuf_put( a, enc->s2k.mode ); - iobuf_put( a, enc->s2k.hash_algo ); - if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) { - iobuf_write(a, enc->s2k.salt, 8 ); - if( enc->s2k.mode == 3 ) - iobuf_put(a, enc->s2k.count); - } - if( enc->seskeylen ) - iobuf_write(a, enc->seskey, enc->seskeylen ); - - write_header(out, ctb, iobuf_get_temp_length(a) ); - if( iobuf_write_temp( out, a ) ) - rc = G10ERR_WRITE_FILE; - - iobuf_close(a); - return rc; -} - - - - -static int -do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) -{ - int rc = 0; - int n, i; - IOBUF a = iobuf_temp(); - - write_version( a, ctb ); - if( enc->throw_keyid ) { - write_32(a, 0 ); /* don't tell Eve who can decrypt the message */ - write_32(a, 0 ); - } - else { - write_32(a, enc->keyid[0] ); - write_32(a, enc->keyid[1] ); - } - iobuf_put(a,enc->pubkey_algo ); - n = pubkey_get_nenc( enc->pubkey_algo ); - if( !n ) - write_fake_data( a, enc->data[0] ); - for(i=0; i < n; i++ ) - mpi_write(a, enc->data[i] ); - - write_header(out, ctb, iobuf_get_temp_length(a) ); - if( iobuf_write_temp( out, a ) ) - rc = G10ERR_WRITE_FILE; - - iobuf_close(a); - return rc; -} - - - - -static u32 -calc_plaintext( PKT_plaintext *pt ) -{ - return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0; -} - -static int -do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt ) -{ - int i, rc = 0; - u32 n; - byte buf[1000]; /* this buffer has the plaintext! */ - int nbytes; - - write_header(out, ctb, calc_plaintext( pt ) ); - iobuf_put(out, pt->mode ); - iobuf_put(out, pt->namelen ); - for(i=0; i < pt->namelen; i++ ) - iobuf_put(out, pt->name[i] ); - if( write_32(out, pt->timestamp ) ) - rc = G10ERR_WRITE_FILE; - - n = 0; - while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) { - if( iobuf_write(out, buf, nbytes) == -1 ) { - rc = G10ERR_WRITE_FILE; - break; - } - n += nbytes; - } - memset(buf,0,1000); /* at least burn the buffer */ - if( !pt->len ) - iobuf_set_block_mode(out, 0 ); /* write end marker */ - else if( n != pt->len ) - log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n", - (ulong)n, (ulong)pt->len ); - - return rc; -} - - - -static int -do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed ) -{ - int rc = 0; - u32 n; - - n = ed->len ? (ed->len + ed->extralen) : 0; - write_header(out, ctb, n ); - - /* This is all. The caller has to write the real data */ - - return rc; -} - -static int -do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) -{ - int rc = 0; - u32 n; - - assert( ed->mdc_method ); - - /* Take version number and the following MDC packet in account. */ - n = ed->len ? (ed->len + ed->extralen + 1 + 22) : 0; - write_header(out, ctb, n ); - iobuf_put(out, 1 ); /* version */ - - /* This is all. The caller has to write the real data */ - - return rc; -} - - -static int -do_compressed( IOBUF out, int ctb, PKT_compressed *cd ) -{ - int rc = 0; - - /* We must use the old convention and don't use blockmode for tyhe - sake of PGP 2 compatibility. However if the new_ctb flag was - set, CTB is already formatted as new style and write_header2 - does create a partial length encoding using new the new - style. */ - write_header2(out, ctb, 0, 0, 0 ); - iobuf_put(out, cd->algorithm ); - - /* This is all. The caller has to write the real data */ - - return rc; -} - - -/**************** - * Delete all subpackets of type REQTYPE and return a bool whether a packet - * was deleted. - */ -int -delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype ) -{ - int buflen; - sigsubpkttype_t type; - byte *buffer, *bufstart; - size_t n; - size_t unused = 0; - int okay = 0; - - if( !area ) - return 0; - buflen = area->len; - buffer = area->data; - for(;;) { - 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 += 4; - buflen -= 4; - } - else if( n >= 192 ) { - if( buflen < 2 ) - break; - n = (( n - 192 ) << 8) + *buffer + 192; - buffer++; - buflen--; - } - if( buflen < n ) - break; - - type = *buffer & 0x7f; - if( type == reqtype ) { - buffer++; - buflen--; - n--; - if( n > buflen ) - break; - buffer += n; /* point to next subpkt */ - buflen -= n; - memmove (bufstart, buffer, buflen); /* shift */ - unused += buffer - bufstart; - buffer = bufstart; - } - else { - buffer += n; buflen -=n; - } - } - - 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 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, - const byte *buffer, size_t buflen ) -{ - byte *p; - int critical, hashed; - subpktarea_t *oldarea, *newarea; - size_t nlen, n, n0; - - critical = (type & SIGSUBPKT_FLAG_CRITICAL); - type &= ~SIGSUBPKT_FLAG_CRITICAL; - - /* 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( (buflen+1) >= 8384 ) - nlen = 5; /* write 5 byte length header */ - else if( (buflen+1) >= 192 ) - nlen = 2; /* write 2 byte length header */ - else - nlen = 1; /* just a 1 byte length header */ - - switch( type ) { - case SIGSUBPKT_PRIV_VERIFY_CACHE: /*(obsolete)*/ - BUG(); - break; - case SIGSUBPKT_ISSUER: - hashed = 0; - break; - default: - hashed = 1; - break; - } - - if( critical ) - type |= SIGSUBPKT_FLAG_CRITICAL; - - 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 (oldarea) { - newarea = m_realloc (oldarea, sizeof (*newarea) + n - 1); - newarea->size = n; - /*log_debug ("reallocating area for type %d\n", type );*/ - } - else { - newarea = m_alloc (sizeof (*newarea) + n - 1); - newarea->size = n; - /*log_debug ("allocating area for type %d\n", type );*/ - } - 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 { - *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 ) -{ - u32 u; - byte buf[8]; - - u = sig->keyid[0]; - buf[0] = (u >> 24) & 0xff; - buf[1] = (u >> 16) & 0xff; - buf[2] = (u >> 8) & 0xff; - buf[3] = u & 0xff; - u = sig->keyid[1]; - buf[4] = (u >> 24) & 0xff; - buf[5] = (u >> 16) & 0xff; - buf[6] = (u >> 8) & 0xff; - buf[7] = u & 0xff; - build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 ); - - u = sig->timestamp; - buf[0] = (u >> 24) & 0xff; - buf[1] = (u >> 16) & 0xff; - 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,u32 buflen, - const void *header,u32 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 */ - - if(headerlen>0) - 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 ) -{ - int rc = 0; - int n, i; - IOBUF a = iobuf_temp(); - - if( !sig->version ) - iobuf_put( a, 3 ); - else - iobuf_put( a, sig->version ); - if( sig->version < 4 ) - iobuf_put(a, 5 ); /* constant */ - iobuf_put(a, sig->sig_class ); - if( sig->version < 4 ) { - write_32(a, sig->timestamp ); - write_32(a, sig->keyid[0] ); - write_32(a, sig->keyid[1] ); - } - iobuf_put(a, sig->pubkey_algo ); - iobuf_put(a, sig->digest_algo ); - if( sig->version >= 4 ) { - size_t nn; - /* 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? sig->hashed->len : 0; - write_16(a, nn); - if( nn ) - 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, nn ); - } - iobuf_put(a, sig->digest_start[0] ); - iobuf_put(a, sig->digest_start[1] ); - n = pubkey_get_nsig( sig->pubkey_algo ); - if( !n ) - write_fake_data( a, sig->data[0] ); - for(i=0; i < n; i++ ) - mpi_write(a, sig->data[i] ); - - if( is_RSA(sig->pubkey_algo) && sig->version < 4 ) - write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) ); - else - write_header(out, ctb, iobuf_get_temp_length(a) ); - if( iobuf_write_temp( out, a ) ) - rc = G10ERR_WRITE_FILE; - - iobuf_close(a); - return rc; -} - - -static int -do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops ) -{ - int rc = 0; - IOBUF a = iobuf_temp(); - - write_version( a, ctb ); - iobuf_put(a, ops->sig_class ); - iobuf_put(a, ops->digest_algo ); - iobuf_put(a, ops->pubkey_algo ); - write_32(a, ops->keyid[0] ); - write_32(a, ops->keyid[1] ); - iobuf_put(a, ops->last ); - - write_header(out, ctb, iobuf_get_temp_length(a) ); - if( iobuf_write_temp( out, a ) ) - rc = G10ERR_WRITE_FILE; - - iobuf_close(a); - return rc; -} - - -static int -write_16(IOBUF out, u16 a) -{ - iobuf_put(out, a>>8); - if( iobuf_put(out,a) ) - return -1; - return 0; -} - -static int -write_32(IOBUF out, u32 a) -{ - iobuf_put(out, a>> 24); - iobuf_put(out, a>> 16); - iobuf_put(out, a>> 8); - if( iobuf_put(out, a) ) - return -1; - return 0; -} - - -/**************** - * calculate the length of a header - */ -static int -calc_header_length( u32 len, int new_ctb ) -{ - if( !len ) - return 1; /* only the ctb */ - - if( new_ctb ) { - if( len < 192 ) - return 2; - if( len < 8384 ) - return 3; - else - return 6; - } - if( len < 256 ) - return 2; - if( len < 65536 ) - return 3; - - return 5; -} - -/**************** - * Write the CTB and the packet length - */ -static int -write_header( IOBUF out, int ctb, u32 len ) -{ - return write_header2( out, ctb, len, 0, 1 ); -} - - -static int -write_sign_packet_header( IOBUF out, int ctb, u32 len ) -{ - /* work around a bug in the pgp read function for signature packets, - * which are not correctly coded and silently assume at some - * point 2 byte length headers.*/ - iobuf_put(out, 0x89 ); - iobuf_put(out, len >> 8 ); - return iobuf_put(out, len ) == -1 ? -1:0; -} - -/**************** - * if HDRLEN is > 0, try to build a header of this length. - * we need this, so that we can hash packets without reading them again. - */ -static int -write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode ) -{ - if( ctb & 0x40 ) - return write_new_header( out, ctb, len, hdrlen ); - - if( hdrlen ) { - if( !len ) - ctb |= 3; - else if( hdrlen == 2 && len < 256 ) - ; - else if( hdrlen == 3 && len < 65536 ) - ctb |= 1; - else - ctb |= 2; - } - else { - if( !len ) - ctb |= 3; - else if( len < 256 ) - ; - else if( len < 65536 ) - ctb |= 1; - else - ctb |= 2; - } - if( iobuf_put(out, ctb ) ) - return -1; - if( !len ) { - if( blkmode ) - iobuf_set_block_mode(out, 8196 ); - } - else { - if( ctb & 2 ) { - iobuf_put(out, len >> 24 ); - iobuf_put(out, len >> 16 ); - } - if( ctb & 3 ) - iobuf_put(out, len >> 8 ); - if( iobuf_put(out, len ) ) - return -1; - } - return 0; -} - - -static int -write_new_header( IOBUF out, int ctb, u32 len, int hdrlen ) -{ - if( hdrlen ) - log_bug("can't cope with hdrlen yet\n"); - - if( iobuf_put(out, ctb ) ) - return -1; - if( !len ) { - iobuf_set_partial_block_mode(out, 512 ); - } - else { - if( len < 192 ) { - if( iobuf_put(out, len ) ) - return -1; - } - else if( len < 8384 ) { - len -= 192; - if( iobuf_put( out, (len / 256) + 192) ) - return -1; - if( iobuf_put( out, (len % 256) ) ) - return -1; - } - else { - if( iobuf_put( out, 0xff ) ) - return -1; - if( iobuf_put( out, (len >> 24)&0xff ) ) - return -1; - if( iobuf_put( out, (len >> 16)&0xff ) ) - return -1; - if( iobuf_put( out, (len >> 8)&0xff ) ) - return -1; - if( iobuf_put( out, len & 0xff ) ) - return -1; - } - } - return 0; -} - -static int -write_version( IOBUF out, int ctb ) -{ - if( iobuf_put( out, 3 ) ) - return -1; - return 0; -} - diff --git a/g10/cipher.c b/g10/cipher.c deleted file mode 100644 index cb9f14916..000000000 --- a/g10/cipher.c +++ /dev/null @@ -1,152 +0,0 @@ -/* cipher.c - En-/De-ciphering filter - * Copyright (C) 1998, 1999, 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 "errors.h" -#include "iobuf.h" -#include "memory.h" -#include "util.h" -#include "filter.h" -#include "packet.h" -#include "options.h" -#include "main.h" -#include "status.h" - - -#define MIN_PARTIAL_SIZE 512 - - -static void -write_header( cipher_filter_context_t *cfx, IOBUF a ) -{ - PACKET pkt; - PKT_encrypted ed; - byte temp[18]; - unsigned blocksize; - unsigned nprefix; - - blocksize = cipher_get_blocksize( cfx->dek->algo ); - if( blocksize < 8 || blocksize > 16 ) - log_fatal("unsupported blocksize %u\n", blocksize ); - - memset( &ed, 0, sizeof ed ); - ed.len = cfx->datalen; - ed.extralen = blocksize+2; - ed.new_ctb = !ed.len && !opt.rfc1991; - if( cfx->dek->use_mdc ) { - ed.mdc_method = DIGEST_ALGO_SHA1; - cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 ); - if ( DBG_HASHING ) - 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 = cfx->dek->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; - randomize_buffer( temp, nprefix, 1 ); - temp[nprefix] = temp[nprefix-2]; - temp[nprefix+1] = temp[nprefix-1]; - print_cipher_algo_note( cfx->dek->algo ); - cfx->cipher_hd = cipher_open( cfx->dek->algo, - cfx->dek->use_mdc? CIPHER_MODE_CFB - : CIPHER_MODE_AUTO_CFB, 1 ); -/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/ - 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 ) /* 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; -} - - - -/**************** - * This filter is used to en/de-cipher data with a conventional algorithm - */ -int -cipher_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) -{ - size_t size = *ret_len; - cipher_filter_context_t *cfx = opaque; - int rc=0; - - if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */ - rc = -1; /* not yet used */ - } - else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ - assert(a); - if( !cfx->header ) { - write_header( cfx, a ); - } - if( cfx->mdc_hash ) - md_write( cfx->mdc_hash, buf, size ); - cipher_encrypt( cfx->cipher_hd, buf, buf, size); - if( iobuf_write( a, buf, size ) ) - rc = G10ERR_WRITE_FILE; - } - else if( control == IOBUFCTRL_FREE ) { - if( cfx->mdc_hash ) { - byte *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; - md_putc( cfx->mdc_hash, temp[0] ); - md_putc( cfx->mdc_hash, temp[1] ); - - md_final( cfx->mdc_hash ); - hash = md_read( cfx->mdc_hash, 0 ); - memcpy(temp+2, hash, 20); - 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" ); - } - cipher_close(cfx->cipher_hd); - } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "cipher_filter"; - } - return rc; -} diff --git a/g10/compress.c b/g10/compress.c deleted file mode 100644 index 6ea84f6cd..000000000 --- a/g10/compress.c +++ /dev/null @@ -1,310 +0,0 @@ -/* compress.c - compress filter - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <assert.h> -#include <errno.h> -#include <zlib.h> - -#include "util.h" -#include "memory.h" -#include "packet.h" -#include "filter.h" -#include "main.h" -#include "options.h" - - -static void -init_compress( compress_filter_context_t *zfx, z_stream *zs ) -{ - int rc; - int level; - - if( opt.compress >= 0 && opt.compress <= 9 ) - level = opt.compress; - else if( opt.compress == -1 ) - level = Z_DEFAULT_COMPRESSION; - else if( opt.compress == 10 ) /* remove this ! */ - level = 0; - else { - log_error("invalid compression level; using default level\n"); - level = Z_DEFAULT_COMPRESSION; - } - - - if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED, - -13, 8, Z_DEFAULT_STRATEGY) - : deflateInit( zs, level ) - ) != Z_OK ) { - log_fatal("zlib problem: %s\n", zs->msg? zs->msg : - rc == Z_MEM_ERROR ? "out of core" : - rc == Z_VERSION_ERROR ? "invalid lib version" : - "unknown error" ); - } - - zfx->outbufsize = 8192; - zfx->outbuf = m_alloc( zfx->outbufsize ); -} - -static int -do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a ) -{ - int zrc; - 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", - (unsigned)zs->avail_in, (unsigned)zs->avail_out, flush ); - zrc = deflate( zs, flush ); - if( zrc == Z_STREAM_END && flush == Z_FINISH ) - ; - else if( zrc != Z_OK ) { - if( zs->msg ) - log_fatal("zlib deflate problem: %s\n", zs->msg ); - else - log_fatal("zlib deflate problem: rc=%d\n", zrc ); - } - n = zfx->outbufsize - zs->avail_out; - if( DBG_FILTER ) - log_debug("leave deflate: " - "avail_in=%u, avail_out=%u, n=%u, zrc=%d\n", - (unsigned)zs->avail_in, (unsigned)zs->avail_out, - (unsigned)n, zrc ); - - if( iobuf_write( a, zfx->outbuf, n ) ) { - log_debug("deflate: iobuf_write failed\n"); - return G10ERR_WRITE_FILE; - } - } while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) ); - return 0; -} - -static void -init_uncompress( compress_filter_context_t *zfx, z_stream *zs ) -{ - int rc; - - /**************** - * PGP uses a windowsize of 13 bits. Using a negative value for - * it forces zlib not to expect a zlib header. This is a - * undocumented feature Peter Gutmann told me about. - */ - if( (rc = zfx->algo == 1? inflateInit2( zs, -13) - : inflateInit( zs )) != Z_OK ) { - log_fatal("zlib problem: %s\n", zs->msg? zs->msg : - rc == Z_MEM_ERROR ? "out of core" : - rc == Z_VERSION_ERROR ? "invalid lib version" : - "unknown error" ); - } - - zfx->inbufsize = 2048; - zfx->inbuf = m_alloc( zfx->inbufsize ); - zs->avail_in = 0; -} - -static int -do_uncompress( compress_filter_context_t *zfx, z_stream *zs, - IOBUF a, size_t *ret_len ) -{ - int zrc; - int rc=0; - size_t n; - int nread, count; - int refill = !zs->avail_in; - - if( DBG_FILTER ) - log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n", - (unsigned)zs->avail_in, (unsigned)zs->avail_out, - (unsigned)zfx->inbufsize ); - do { - 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; - n += nread; - /* If we use the undocumented feature to suppress - * the zlib header, we have to give inflate an - * extra dummy byte to read */ - if( nread < count && zfx->algo == 1 ) { - *(zfx->inbuf + n) = 0xFF; /* is it really needed ? */ - zfx->algo1hack = 1; - n++; - } - zs->avail_in = n; - } - refill = 1; - if( DBG_FILTER ) - log_debug("enter inflate: avail_in=%u, avail_out=%u\n", - (unsigned)zs->avail_in, (unsigned)zs->avail_out); -#ifdef Z_SYNC_FLUSH - zrc = inflate( zs, Z_SYNC_FLUSH ); -#else - zrc = inflate( zs, Z_PARTIAL_FLUSH ); -#endif - if( DBG_FILTER ) - log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n", - (unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc); - if( zrc == Z_STREAM_END ) - rc = -1; /* eof */ - else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) { - if( zs->msg ) - log_fatal("zlib inflate problem: %s\n", zs->msg ); - else - log_fatal("zlib inflate problem: rc=%d\n", zrc ); - } - } while( zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR ); - *ret_len = zfx->outbufsize - zs->avail_out; - if( DBG_FILTER ) - log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len ); - return rc; -} - -int -compress_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) -{ - size_t size = *ret_len; - compress_filter_context_t *zfx = opaque; - z_stream *zs = zfx->opaque; - int rc=0; - - if( control == IOBUFCTRL_UNDERFLOW ) { - if( !zfx->status ) { - 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 ); - } - else if( control == IOBUFCTRL_FLUSH ) { - if( !zfx->status ) { - PACKET pkt; - PKT_compressed cd; - - if( !zfx->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; - init_packet( &pkt ); - pkt.pkttype = PKT_COMPRESSED; - pkt.pkt.compressed = &cd; - if( build_packet( a, &pkt )) - log_bug("build_packet(PKT_COMPRESSED) failed\n"); - 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); - m_free(zs); - zfx->opaque = 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); - m_free(zs); - zfx->opaque = 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 - */ -int -handle_compressed( void *procctx, PKT_compressed *cd, - int (*callback)(IOBUF, void *), void *passthru ) -{ - compress_filter_context_t *cfx; - int rc; - - if( cd->algorithm < 1 || cd->algorithm > 2 ) - 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); - cd->buf = NULL; - return rc; -} - diff --git a/g10/decrypt.c b/g10/decrypt.c deleted file mode 100644 index 297ee3418..000000000 --- a/g10/decrypt.c +++ /dev/null @@ -1,138 +0,0 @@ -/* decrypt.c - verify signed data - * 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 <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 "i18n.h" - - - -/**************** - * Assume that the input is an encrypted message and decrypt - * (and if signed, verify the signature on) it. - * This command differs from the default operation, as it never - * writes to the filename which is included in the file and it - * rejects files which don't begin with an encrypted message. - */ - -int -decrypt_message( const char *filename ) -{ - IOBUF fp; - armor_filter_context_t afx; - int rc; - int no_out=0; - - /* open the message file */ - fp = iobuf_open(filename); - if( !fp ) { - log_error(_("can't open `%s'\n"), print_fname_stdin(filename)); - return G10ERR_OPEN_FILE; - } - - if( !opt.no_armor ) { - if( use_armor_filter( fp ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( fp, armor_filter, &afx ); - } - } - - if( !opt.outfile ) { - no_out = 1; - opt.outfile = "-"; - } - rc = proc_encryption_packets( NULL, fp ); - if( no_out ) - opt.outfile = NULL; - iobuf_close(fp); - 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 deleted file mode 100644 index ca578a590..000000000 --- a/g10/delkey.c +++ /dev/null @@ -1,221 +0,0 @@ -/* delkey.c - delete keys - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <ctype.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 "trustdb.h" -#include "filter.h" -#include "ttyio.h" -#include "status.h" -#include "i18n.h" - - -/**************** - * 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. - */ -static int -do_delete_key( const char *username, int secret, int *r_sec_avail ) -{ - int rc = 0; - KBNODE keyblock = NULL; - KBNODE node; - 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; - int exactmatch; - - *r_sec_avail = 0; - - /* search the userid */ - classify_user_id (username, &desc); - exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR - || desc.mode == KEYDB_SEARCH_MODE_FPR16 - || desc.mode == KEYDB_SEARCH_MODE_FPR20); - 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 = G10ERR_GENERAL; - goto leave; - } - - if( secret ) { - sk = node->pkt->pkt.secret_key; - keyid_from_sk( sk, keyid ); - } - else { - pk = node->pkt->pkt.public_key; - keyid_from_pk( pk, keyid ); - rc = seckey_available( keyid ); - if( !rc ) { - *r_sec_avail = 1; - rc = -1; - goto leave; - } - else if( rc != G10ERR_NO_SECKEY ) { - log_error("%s: get secret key: %s\n", username, g10_errstr(rc) ); - } - else - rc = 0; - } - - if( rc ) - rc = 0; - else if (opt.batch && exactmatch) - okay++; - else if( opt.batch && secret ) - { - log_error(_("can't do that in batchmode\n")); - log_info (_("(unless you specify the key by fingerprint)\n")); - } - else if( opt.batch && opt.answer_yes ) - okay++; - else if( opt.batch ) - { - log_error(_("can't do that in batchmode without \"--yes\"\n")); - log_info (_("(unless you specify the key by fingerprint)\n")); - } - else { - char *p; - size_t n; - - if( secret ) - tty_printf("sec %4u%c/%08lX %s ", - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid[1], datestr_from_sk(sk) ); - else - tty_printf("pub %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"); - - yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay" - : "delete_key.okay", - _("Delete this key from the keyring? ")); - if( !cpr_enabled() && secret && yes ) { - /* I think it is not required to check a passphrase; if - * the user is so stupid as to let others access his secret keyring - * (and has no backup) - it is up him to read some very - * basic texts about security. - */ - yes = cpr_get_answer_is_yes("delete_key.secret.okay", - _("This is a secret key! - really delete? ")); - } - if( yes ) - okay++; - } - - - if( okay ) { - 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: - 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 deleted file mode 100644 index 89d94278f..000000000 --- a/g10/encode.c +++ /dev/null @@ -1,798 +0,0 @@ -/* encode.c - encode data - * 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 <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 "filter.h" -#include "trustdb.h" -#include "i18n.h" -#include "status.h" - -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 ); - - - -/**************** - * Encode FILENAME with only the symmetric cipher. Take input from - * stdin if FILENAME is NULL. - */ -int -encode_symmetric( const char *filename ) -{ - int compat = 1; - -#if 0 - /* We don't want to use it because older gnupg version can't - handle it and we can presume that a lot of scripts are running - with the expert mode set. Some time in the future we might - want to allow for it. */ - if ( opt.expert ) - compat = 0; /* PGP knows how to handle this mode. */ -#endif - return encode_simple( filename, 1, compat ); -} - -/**************** - * Encode FILENAME as a literal data packet only. Take input from - * stdin if FILENAME is NULL. - */ -int -encode_store( const char *filename ) -{ - 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; -} - -/* We try very hard to use a MDC */ -static int -use_mdc(PK_LIST pk_list,int algo) -{ - /* --force-mdc overrides --disable-mdc */ - if(opt.force_mdc) - return 1; - - if(opt.disable_mdc) - return 0; - - /* Do the keys really support MDC? */ - - if(select_mdc_from_pklist(pk_list)) - return 1; - - /* The keys don't support MDC, so now we do a bit of a hack - if any - of the AESes or TWOFISH are in the prefs, we assume that the user - can handle a MDC. This is valid for PGP 7, which can handle MDCs - though it will not generate them. 2440bis allows this, by the - way. */ - - if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, - CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES) - return 1; - - if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, - CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192) - return 1; - - if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, - CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256) - return 1; - - if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, - CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH) - return 1; - - /* Last try. Use MDC for the modern ciphers. */ - - if(cipher_get_blocksize(algo)!=8) - return 1; - - return 0; /* No MDC */ -} - -static int -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; - compress_filter_context_t zfx; - text_filter_context_t tfx; - 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); - init_packet(&pkt); - - /* prepare iobufs */ - if( !(inp = iobuf_open(filename)) ) { - log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]", - strerror(errno) ); - 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 = 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, NULL ); - if( !cfx.dek || !cfx.dek->keylen ) { - rc = G10ERR_PASSPHRASE; - m_free(cfx.dek); - m_free(s2k); - iobuf_close(inp); - log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) ); - return rc; - } - if (!compat && s2k->mode != 1 && s2k->mode != 3) { - compat = 1; - log_info (_("can't use a symmetric ESK packet " - "due to the S2K mode\n")); - } - - 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; - } - - cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); - } - - if (opt.compress == -1 && cfx.dek && cfx.dek->use_mdc && - is_file_compressed(filename, &rc)) - { - if (opt.verbose) - log_info(_("`%s' already compressed\n"), filename); - do_compress = 0; - } - - if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) { - iobuf_cancel(inp); - m_free(cfx.dek); - m_free(s2k); - return rc; - } - - 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 - if( s2k && !opt.rfc1991 ) { - 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", g10_errstr(rc) ); - m_free(enc); - } - - 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; - } - } - - /* 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 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; - cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0; - } - else - { - cfx.datalen = filesize && !do_compress ? filesize : 0; - pkt.pkttype = 0; - pkt.pkt.generic = NULL; - } - - /* register the cipher filter */ - if( mode ) - iobuf_push_filter( out, cipher_filter, &cfx ); - /* register the compress filter */ - if( do_compress ) - { - if (cfx.dek && cfx.dek->use_mdc) - zfx.new_ctb = 1; - zfx.algo=opt.def_compress_algo; - if(zfx.algo==-1) - zfx.algo=DEFAULT_COMPRESS_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", g10_errstr(rc) ); - } - else { - /* 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 = G10ERR_WRITE_FILE; - log_error("copying input to output failed: %s\n", g10_errstr(rc) ); - break; - } - memset(copy_buffer, 0, 4096); /* burn buffer */ - } - - /* finish the stuff */ - iobuf_close(inp); - if (rc) - iobuf_cancel(out); - else { - iobuf_close(out); /* fixme: check returncode */ - if (mode) - write_status( STATUS_END_ENCRYPTION ); - } - if (pt) - pt->buf = NULL; - free_packet(&pkt); - m_free(cfx.dek); - m_free(s2k); - return rc; -} - -/**************** - * Encrypt the file with the given userids (or ask if none - * is supplied). - */ -int -encode_crypt( const char *filename, STRLIST remusr ) -{ - IOBUF inp = NULL, out = NULL; - PACKET pkt; - PKT_plaintext *pt = NULL; - 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; - 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); - init_packet(&pkt); - - 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 %s\n"),"PGP 2.x"); - opt.pgp2=0; - break; - } - } - - /* prepare iobufs */ - if( !(inp = iobuf_open(filename)) ) { - log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]", - strerror(errno) ); - rc = G10ERR_OPEN_FILE; - goto leave; - } - else if( opt.verbose ) - log_info(_("reading from `%s'\n"), filename? filename: "[stdin]"); - - if( opt.textmode ) - iobuf_push_filter( inp, text_filter, &tfx ); - - if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) - goto leave; - - - 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 %s\n"),"PGP 2.x"); - 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=use_mdc(pk_list,cfx.dek->algo); - - /* Only do the is-file-already-compressed check if we are using a - MDC. This forces compressed files to be re-compressed if we do - not have a MDC to give some protection against chosen - ciphertext attacks. */ - - if (opt.compress == -1 && cfx.dek->use_mdc && - is_file_compressed(filename, &rc2) ) - { - if (opt.verbose) - log_info(_("`%s' already compressed\n"), filename); - do_compress = 0; - } - if (rc2) - { - rc = rc2; - goto leave; - } - - 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 = 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 ) - { - if (cfx.dek && cfx.dek->use_mdc) - zfx.new_ctb = 1; - 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", g10_errstr(rc) ); - } - else { - /* 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 = G10ERR_WRITE_FILE; - log_error("copying input to output failed: %s\n", - g10_errstr(rc) ); - break; - } - memset(copy_buffer, 0, 4096); /* burn buffer */ - } - - /* finish the stuff */ - leave: - iobuf_close(inp); - if( rc ) - iobuf_cancel(out); - else { - iobuf_close(out); /* fixme: check returncode */ - write_status( STATUS_END_ENCRYPTION ); - } - if( pt ) - pt->buf = NULL; - free_packet(&pkt); - m_free(cfx.dek); - release_pk_list( pk_list ); - return rc; -} - - - - -/**************** - * Filter to do a complete public key encryption. - */ -int -encrypt_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) -{ - size_t size = *ret_len; - encrypt_filter_context_t *efx = opaque; - int rc=0; - - if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */ - BUG(); /* not used */ - } - else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ - if( !efx->header_okay ) { - 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,-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; - } - - efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo); - - make_session_key( efx->cfx.dek ); - if( DBG_CIPHER ) - log_hexdump("DEK is: ", - efx->cfx.dek->key, efx->cfx.dek->keylen ); - - rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a ); - if( rc ) - return rc; - - iobuf_push_filter( a, cipher_filter, &efx->cfx ); - - efx->header_okay = 1; - } - rc = iobuf_write( a, buf, size ); - - } - else if( control == IOBUFCTRL_FREE ) { - } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "encrypt_filter"; - } - return rc; -} - - -/**************** - * Write pubkey-enc packets from the list of PKs to OUT. - */ -static int -write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ) -{ - PACKET pkt; - PKT_public_key *pk; - PKT_pubkey_enc *enc; - int rc; - - for( ; pk_list; pk_list = pk_list->next ) { - MPI frame; - - pk = pk_list->pk; - - print_pubkey_algo_note( pk->pubkey_algo ); - enc = m_alloc_clear( sizeof *enc ); - enc->pubkey_algo = pk->pubkey_algo; - keyid_from_pk( pk, enc->keyid ); - enc->throw_keyid = opt.throw_keyid; - - if(opt.throw_keyid && (opt.pgp2 || opt.pgp6 || opt.pgp7)) - { - log_info(_("you may not use %s while in %s mode\n"), - "--throw-keyid", - opt.pgp2?"--pgp2":opt.pgp6?"--pgp6":"--pgp7"); - - log_info(_("this message may not be usable by %s\n"), - opt.pgp2?"PGP 2.x":opt.pgp6?"PGP 6.x":"PGP 7.x"); - - opt.pgp2=opt.pgp6=opt.pgp7=0; - } - - /* Okay, what's going on: We have the session key somewhere in - * the structure DEK and want to encode this session key in - * an integer value of n bits. pubkey_nbits gives us the - * number of bits we have to use. We then encode the session - * key in some way and we get it back in the big intger value - * FRAME. Then we use FRAME, the public key PK->PKEY and the - * algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt - * which returns the encrypted value in the array ENC->DATA. - * This array has a size which depends on the used algorithm - * (e.g. 2 for ElGamal). We don't need frame anymore because we - * have everything now in enc->data which is the passed to - * build_packet() - */ - frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo, - pk->pkey ) ); - rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey ); - mpi_free( frame ); - if( rc ) - log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) ); - else { - if( opt.verbose ) { - char *ustr = get_user_id_string_printable (enc->keyid); - log_info(_("%s/%s encrypted for: \"%s\"\n"), - pubkey_algo_to_string(enc->pubkey_algo), - cipher_algo_to_string(dek->algo), ustr ); - m_free(ustr); - } - /* and write it */ - init_packet(&pkt); - pkt.pkttype = PKT_PUBKEY_ENC; - pkt.pkt.pubkey_enc = enc; - rc = build_packet( out, &pkt ); - if( rc ) - log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc)); - } - free_pubkey_enc(enc); - if( rc ) - return rc; - } - 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/exec.c b/g10/exec.c deleted file mode 100644 index f220dd30f..000000000 --- a/g10/exec.c +++ /dev/null @@ -1,617 +0,0 @@ -/* 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; } -int set_exec_path(const char *path,int method) { 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 - -/* method==0 to replace current $PATH, and 1 to append to current - $PATH. */ -int set_exec_path(const char *path,int method) -{ - char *p,*curpath=NULL; - size_t curlen=0; - - if(method==1 && (curpath=getenv("PATH"))) - curlen=strlen(curpath)+1; - - p=m_alloc(5+curlen+strlen(path)+1); - strcpy(p,"PATH="); - - if(curpath) - { - strcat(p,curpath); - strcat(p,":"); - } - - strcat(p,path); - - /* Notice that path is never freed. That is intentional due to the - way putenv() works. This leaks a few bytes if we call - set_exec_path multiple times. */ - - if(putenv(p)!=0) - return G10ERR_GENERAL; - else - return 0; -} - -/* 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(_("can't create directory `%s': %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; - unsigned 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) - { - size_t applen=strlen(append); - - if(applen+len>size-1) - { - if(applen<100) - applen=100; - - size+=applen; - 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(_("can't create `%s': %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 deleted file mode 100644 index 427f25810..000000000 --- a/g10/exec.h +++ /dev/null @@ -1,23 +0,0 @@ -#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); -int set_exec_path(const char *path,int method); - -#endif /* !_EXEC_H_ */ diff --git a/g10/export.c b/g10/export.c deleted file mode 100644 index 5f6eadcd5..000000000 --- a/g10/export.c +++ /dev/null @@ -1,350 +0,0 @@ -/* export.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.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" - -static int do_export( STRLIST users, int secret, unsigned int options ); -static int do_export_stream( IOBUF out, STRLIST users, - int secret, unsigned int options, int *any ); - -int -parse_export_options(char *str,unsigned int *options) -{ - char *tok; - int hit=0; - struct - { - char *name; - unsigned int bit; - } export_opts[]= - { - {"include-non-rfc",EXPORT_INCLUDE_NON_RFC}, - {"include-local-sigs",EXPORT_INCLUDE_LOCAL_SIGS}, - {"include-attributes",EXPORT_INCLUDE_ATTRIBUTES}, - {"include-sensitive-revkeys",EXPORT_INCLUDE_SENSITIVE_REVKEYS}, - {NULL,0} - /* add tags for include revoked and disabled? */ - }; - - while((tok=strsep(&str," ,"))) - { - int i,rev=0; - - if(ascii_strncasecmp("no-",tok,3)==0) - { - rev=1; - tok+=3; - } - - for(i=0;export_opts[i].name;i++) - { - if(ascii_strcasecmp(export_opts[i].name,tok)==0) - { - if(rev) - *options&=~export_opts[i].bit; - else - *options|=export_opts[i].bit; - hit=1; - break; - } - } - - if(!hit && !export_opts[i].name) - return 0; - } - - return hit; -} - -/**************** - * Export the public keys (to standard out or --output). - * Depending on opt.armor the output is armored. - * options are defined in main.h. - * If USERS is NULL, the complete ring will be exported. */ -int -export_pubkeys( STRLIST users, unsigned int options ) -{ - return do_export( users, 0, options ); -} - -/**************** - * Export to an already opened stream; return -1 if no keys have - * been exported - */ -int -export_pubkeys_stream( IOBUF out, STRLIST users, unsigned int options ) -{ - int any, rc; - - rc = do_export_stream( out, users, 0, options, &any ); - if( !rc && !any ) - rc = -1; - return rc; -} - -int -export_seckeys( STRLIST users ) -{ - return do_export( users, 1, 0 ); -} - -int -export_secsubkeys( STRLIST users ) -{ - return do_export( users, 2, 0 ); -} - -static int -do_export( STRLIST users, int secret, unsigned int options ) -{ - 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 ) - return rc; - - if( opt.armor ) { - 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, options, &any ); - - if( rc || !any ) - iobuf_cancel(out); - else - iobuf_close(out); - return rc; -} - - -static int -do_export_stream( IOBUF out, STRLIST users, int secret, - unsigned int options, int *any ) -{ - int rc = 0; - PACKET pkt; - KBNODE keyblock = NULL; - KBNODE kbctx, node; - int ndesc; - KEYDB_SEARCH_DESC *desc = NULL; - KEYDB_HANDLE kdbhd; - STRLIST sl; - - *any = 0; - init_packet( &pkt ); - kdbhd = keydb_new (secret); - - 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)); - } - - /* 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 */ - } - - - 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( !(options&EXPORT_INCLUDE_NON_RFC) && - (node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) { - PKT_public_key *pk = node->pkt->pkt.public_key; - if( pk->version == 3 && pk->pubkey_algo > 3 ) { - log_info(_("key %08lX: not a rfc2440 key - skipped\n"), - (ulong)keyid_from_pk( pk, 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 )); ) { - /* don't export any comment packets but those in the - * secret keyring */ - if( !secret && node->pkt->pkttype == PKT_COMMENT ) - continue; - /* make sure that ring_trust packets never get exported */ - if (node->pkt->pkttype == PKT_RING_TRUST) - continue; - - if( node->pkt->pkttype == PKT_SIGNATURE ) { - /* do not export packets which are marked as not exportable */ - if( !(options&EXPORT_INCLUDE_LOCAL_SIGS) && - !node->pkt->pkt.signature->flags.exportable ) - continue; /* not exportable */ - - /* Do not export packets with a "sensitive" revocation - key unless the user wants us to. Note that we do - export these when issuing the actual revocation (see - revoke.c). */ - if( !(options&EXPORT_INCLUDE_SENSITIVE_REVKEYS) && - 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) - break; - - if(i<node->pkt->pkt.signature->numrevkeys) - continue; - } - - /* delete our verification cache */ - delete_sig_subpkt (node->pkt->pkt.signature->unhashed, - SIGSUBPKT_PRIV_VERIFY_CACHE); - } - - /* Don't export attribs? */ - if( !(options&EXPORT_INCLUDE_ATTRIBUTES) && - node->pkt->pkttype == PKT_USER_ID && - node->pkt->pkt.user_id->attrib_data ) { - /* Skip until we get to something that is not an attrib - or a signature on an attrib */ - while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) { - kbctx=kbctx->next; - } - - continue; - } - - if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) { - /* we don't want to export the secret parts of the - * primary key, this is done by using GNU protection mode 1001 - */ - int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode; - node->pkt->pkt.secret_key->protect.s2k.mode = 1001; - rc = build_packet( out, node->pkt ); - 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, g10_errstr(rc) ); - rc = G10ERR_WRITE_FILE; - goto leave; - } - } - ++*any; - } - if( rc == -1 ) - rc = 0; - - leave: - m_free(desc); - keydb_release (kdbhd); - release_kbnode( keyblock ); - if( !*any ) - log_info(_("WARNING: nothing exported\n")); - return rc; -} - diff --git a/g10/filter.h b/g10/filter.h deleted file mode 100644 index c933d2383..000000000 --- a/g10/filter.h +++ /dev/null @@ -1,142 +0,0 @@ -/* filter.h - * Copyright (C) 1998, 1999, 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 - */ -#ifndef G10_FILTER_H -#define G10_FILTER_H - -#include "types.h" -#include "cipher.h" - -typedef struct { - MD_HANDLE md; /* catch all */ - MD_HANDLE md2; /* if we want to calculate an alternate hash */ - size_t maxbuf_size; -} md_filter_context_t; - -typedef struct { - /* these fields may be initialized */ - int what; /* what kind of armor headers to write */ - int only_keyblocks; /* skip all headers but ".... key block" */ - const char *hdrlines; /* write these headerlines */ - - /* these fileds must be initialized to zero */ - int no_openpgp_data; /* output flag: "No valid OpenPGP data found" */ - - /* the following fields must be initialized to zero */ - int inp_checked; /* set if the input has been checked */ - int inp_bypass; /* set if the input is not armored */ - int in_cleartext; /* clear text message */ - int not_dash_escaped; /* clear text is not dash escaped */ - int hashes; /* detected hash algorithms */ - int faked; /* we are faking a literal data packet */ - int truncated; /* number of truncated lines */ - int qp_detected; - int pgp2mode; - - byte *buffer; /* malloced buffer */ - unsigned buffer_size; /* and size of this buffer */ - unsigned buffer_len; /* used length of the buffer */ - unsigned buffer_pos; /* read position */ - - byte radbuf[4]; - int idx, idx2; - u32 crc; - - int status; /* an internal state flag */ - int cancel; - int any_data; /* any valid armored data seen */ - int pending_lf; /* used together with faked */ -} armor_filter_context_t; - -struct unarmor_pump_s; -typedef struct unarmor_pump_s *UnarmorPump; - - -struct compress_filter_context_s { - int status; - void *opaque; /* (used for z_stream) */ - byte *inbuf; - unsigned inbufsize; - byte *outbuf; - unsigned outbufsize; - int algo; /* compress algo */ - int algo1hack; - int new_ctb; - void (*release)(struct compress_filter_context_s*); -}; -typedef struct compress_filter_context_s compress_filter_context_t; - - -typedef struct { - DEK *dek; - u32 datalen; - CIPHER_HANDLE cipher_hd; - int header; - MD_HANDLE mdc_hash; - byte enchash[20]; - int create_mdc; /* flag will be set by the cipher filter */ -} cipher_filter_context_t; - - - -typedef struct { - byte *buffer; /* malloced buffer */ - unsigned buffer_size; /* and size of this buffer */ - unsigned buffer_len; /* used length of the buffer */ - unsigned buffer_pos; /* read position */ - int truncated; /* number of truncated lines */ - int not_dash_escaped; - int escape_from; - 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 ); - -/*-- armor.c --*/ -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, - IOBUF chain, byte *buf, size_t *ret_len); - -/*-- cipher.c --*/ -int cipher_filter( void *opaque, int control, - IOBUF chain, byte *buf, size_t *ret_len); - -/*-- 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, MD_HANDLE md, - int escape_dash, int escape_from, int pgp2mode ); - - - -#endif /*G10_FILTER_H*/ diff --git a/g10/free-packet.c b/g10/free-packet.c deleted file mode 100644 index e760999be..000000000 --- a/g10/free-packet.c +++ /dev/null @@ -1,547 +0,0 @@ -/* free-packet.c - cleanup stuff for packets - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "packet.h" -#include "iobuf.h" -#include "mpi.h" -#include "util.h" -#include "cipher.h" -#include "memory.h" -#include "options.h" - -void -free_symkey_enc( PKT_symkey_enc *enc ) -{ - m_free(enc); -} - -void -free_pubkey_enc( PKT_pubkey_enc *enc ) -{ - int n, i; - n = pubkey_get_nenc( enc->pubkey_algo ); - if( !n ) - mpi_free(enc->data[0]); - for(i=0; i < n; i++ ) - 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_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); -} - - - -void -release_public_key_parts( PKT_public_key *pk ) -{ - int n, i; - n = pubkey_get_npkey( pk->pubkey_algo ); - if( !n ) - mpi_free(pk->pkey[0]); - for(i=0; i < n; i++ ) { - mpi_free( pk->pkey[i] ); - pk->pkey[i] = NULL; - } - if (pk->prefs) { - m_free (pk->prefs); - pk->prefs = NULL; - } - if( 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; - } -} - - -void -free_public_key( PKT_public_key *pk ) -{ - release_public_key_parts( pk ); - m_free(pk); -} - - -static subpktarea_t * -cp_subpktarea (subpktarea_t *s ) -{ - subpktarea_t *d; - - if( !s ) - return NULL; - 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 ( PKT_public_key *d, PKT_public_key *s) -{ - int n, i; - - if( !d ) - d = m_alloc(sizeof *d); - memcpy( d, s, sizeof *d ); - 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]); - else { - 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; -} - -/**************** - * 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 - * parts somewhere and don't duplicate all the other stuff. - */ -void -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->req_usage = pk->req_usage; - sk->req_algo = pk->req_algo; - sk->has_expired = pk->has_expired; - sk->is_revoked = pk->is_revoked; - sk->is_valid = pk->is_valid; - sk->main_keyid[0]= pk->main_keyid[0]; - sk->main_keyid[1]= pk->main_keyid[1]; - sk->keyid[0] = pk->keyid[0]; - sk->keyid[1] = pk->keyid[1]; -} - -PKT_signature * -copy_signature( PKT_signature *d, PKT_signature *s ) -{ - int n, i; - - if( !d ) - d = m_alloc(sizeof *d); - memcpy( d, s, sizeof *d ); - n = pubkey_get_nsig( s->pubkey_algo ); - if( !n ) - d->data[0] = mpi_copy(s->data[0]); - else { - for(i=0; i < n; i++ ) - d->data[i] = mpi_copy( s->data[i] ); - } - 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 * -scopy_user_id (PKT_user_id *s) -{ - if (s) - s->ref++; - return s; -} - - - -void -release_secret_key_parts( PKT_secret_key *sk ) -{ - int n, i; - - n = pubkey_get_nskey( sk->pubkey_algo ); - if( !n ) - mpi_free(sk->skey[0]); - for(i=0; i < n; i++ ) { - mpi_free( sk->skey[i] ); - sk->skey[i] = NULL; - } -} - -void -free_secret_key( PKT_secret_key *sk ) -{ - release_secret_key_parts( sk ); - m_free(sk); -} - -PKT_secret_key * -copy_secret_key( PKT_secret_key *d, PKT_secret_key *s ) -{ - int n, i; - - if( !d ) - d = m_alloc(sizeof *d); - memcpy( d, s, sizeof *d ); - n = pubkey_get_nskey( s->pubkey_algo ); - if( !n ) - d->skey[0] = mpi_copy(s->skey[0]); - else { - for(i=0; i < n; i++ ) - d->skey[i] = mpi_copy( s->skey[i] ); - } - return d; -} - -void -free_comment( PKT_comment *rem ) -{ - m_free(rem); -} - -void -free_attributes(PKT_user_id *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 -free_compressed( PKT_compressed *zd ) -{ - if( zd->buf ) { /* have to skip some bytes */ - /* don't have any information about the length, so - * we assume this is the last packet */ - while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 ) - ; - } - m_free(zd); -} - -void -free_encrypted( PKT_encrypted *ed ) -{ - if( ed->buf ) { /* have to skip some bytes */ - if( iobuf_in_block_mode(ed->buf) ) { - while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 ) - ; - } - else { - while( ed->len ) { /* skip the packet */ - int n = iobuf_read( ed->buf, NULL, ed->len ); - if( n == -1 ) - ed->len = 0; - else - ed->len -= n; - } - } - } - m_free(ed); -} - - -void -free_plaintext( PKT_plaintext *pt ) -{ - if( pt->buf ) { /* have to skip some bytes */ - if( iobuf_in_block_mode(pt->buf) ) { - while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 ) - ; - } - else { - while( pt->len ) { /* skip the packet */ - int n = iobuf_read( pt->buf, NULL, pt->len ); - if( n == -1 ) - pt->len = 0; - else - pt->len -= n; - } - } - } - m_free(pt); -} - -/**************** - * Free the packet in pkt. - */ -void -free_packet( PACKET *pkt ) -{ - if( !pkt || !pkt->pkt.generic ) - return; - - if( DBG_MEMORY ) - log_debug("free_packet() type=%d\n", pkt->pkttype ); - - switch( pkt->pkttype ) { - case PKT_SIGNATURE: - free_seckey_enc( pkt->pkt.signature ); - break; - case PKT_PUBKEY_ENC: - free_pubkey_enc( pkt->pkt.pubkey_enc ); - break; - case PKT_SYMKEY_ENC: - free_symkey_enc( pkt->pkt.symkey_enc ); - break; - case PKT_PUBLIC_KEY: - case PKT_PUBLIC_SUBKEY: - free_public_key( pkt->pkt.public_key ); - break; - case PKT_SECRET_KEY: - case PKT_SECRET_SUBKEY: - free_secret_key( pkt->pkt.secret_key ); - break; - case PKT_COMMENT: - free_comment( pkt->pkt.comment ); - break; - case PKT_USER_ID: - free_user_id( pkt->pkt.user_id ); - break; - case PKT_COMPRESSED: - 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: - m_free( pkt->pkt.generic ); - break; - } - pkt->pkt.generic = NULL; -} - -/**************** - * returns 0 if they match. - */ -int -cmp_public_keys( PKT_public_key *a, PKT_public_key *b ) -{ - int n, i; - - if( a->timestamp != b->timestamp ) - return -1; - if( a->version < 4 && a->expiredate != b->expiredate ) - return -1; - if( a->pubkey_algo != b->pubkey_algo ) - return -1; - - n = pubkey_get_npkey( b->pubkey_algo ); - if( !n ) - return -1; /* can't compare due to unknown algorithm */ - for(i=0; i < n; i++ ) { - if( mpi_cmp( a->pkey[i], b->pkey[i] ) ) - return -1; - } - - return 0; -} - -/**************** - * Returns 0 if they match. - * We only compare the public parts. - */ -int -cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b ) -{ - int n, i; - - if( a->timestamp != b->timestamp ) - return -1; - if( a->version < 4 && a->expiredate != b->expiredate ) - return -1; - if( a->pubkey_algo != b->pubkey_algo ) - return -1; - - n = pubkey_get_npkey( b->pubkey_algo ); - if( !n ) - return -1; /* can't compare due to unknown algorithm */ - for(i=0; i < n; i++ ) { - if( mpi_cmp( a->skey[i], b->skey[i] ) ) - return -1; - } - - return 0; -} - -/**************** - * Returns 0 if they match. - */ -int -cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk ) -{ - int n, i; - - if( pk->timestamp != sk->timestamp ) - return -1; - if( pk->version < 4 && pk->expiredate != sk->expiredate ) - return -1; - if( pk->pubkey_algo != sk->pubkey_algo ) - return -1; - - n = pubkey_get_npkey( pk->pubkey_algo ); - if( !n ) - return -1; /* can't compare due to unknown algorithm */ - for(i=0; i < n; i++ ) { - if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) ) - return -1; - } - return 0; -} - - - -int -cmp_signatures( PKT_signature *a, PKT_signature *b ) -{ - int n, i; - - if( a->keyid[0] != b->keyid[0] ) - return -1; - if( a->keyid[1] != b->keyid[1] ) - return -1; - if( a->pubkey_algo != b->pubkey_algo ) - return -1; - - n = pubkey_get_nsig( a->pubkey_algo ); - if( !n ) - return -1; /* can't compare due to unknown algorithm */ - for(i=0; i < n; i++ ) { - if( mpi_cmp( a->data[i] , b->data[i] ) ) - return -1; - } - return 0; -} - - -/**************** - * Returns: true if the user ids do not match - */ -int -cmp_user_ids( PKT_user_id *a, PKT_user_id *b ) -{ - 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 ); - } - - return res; -} diff --git a/g10/g10.c b/g10/g10.c deleted file mode 100644 index c2e095bf9..000000000 --- a/g10/g10.c +++ /dev/null @@ -1,2816 +0,0 @@ -/* 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. - * - * 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 <assert.h> -#ifdef HAVE_DOSISH_SYSTEM - #include <fcntl.h> /* for setmode() */ -#endif -#ifdef HAVE_STAT -#include <sys/stat.h> /* for stat() */ -#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" -#include "keyserver-internal.h" -#include "exec.h" - -enum cmd_and_opt_values { aNull = 0, - oArmor = 'a', - aDetachedSign = 'b', - aSym = 'c', - aDecrypt = 'd', - aEncr = 'e', - aEncrFiles, - 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, - oSigNotation, - oCertNotation, - oShowNotation, - oNoShowNotation, - aDecryptFiles, - aClearsign, - aStore, - aKeygen, - aSignEncr, - aSignSym, - aSignKey, - aLSignKey, - aNRSignKey, - aNRLSignKey, - aListPackets, - aEditKey, - aDeleteKeys, - aDeleteSecretKeys, - aDeleteSecretAndPublicKeys, - aKMode, - aKModeC, - aImport, - aFastImport, - aVerify, - aVerifyFiles, - aListKeys, - aListSigs, - aListSecretKeys, - aSendKeys, - aRecvKeys, - aSearchKeys, - aExport, - aExportAll, - aExportSecret, - aExportSecretSub, - aCheckKeys, - aGenRevoke, - aDesigRevoke, - aPrimegen, - aPrintMD, - aPrintMDs, - aCheckTrustDB, - aUpdateTrustDB, - aFixTrustDB, - aListTrustDB, - aListTrustPath, - aExportOwnerTrust, - aImportOwnerTrust, - aDeArmor, - aEnArmor, - aGenRandom, - aPipeMode, - aRebuildKeydbCaches, - aRefreshKeys, - - oTextmode, - oExpert, - oNoExpert, - oAskSigExpire, - oNoAskSigExpire, - oAskCertExpire, - oNoAskCertExpire, - oFingerprint, - oWithFingerprint, - oAnswerYes, - oAnswerNo, - oDefCertCheckLevel, - oKeyring, - oSecretKeyring, - oShowKeyring, - oDefaultKey, - oDefRecipient, - oDefRecipientSelf, - oNoDefRecipient, - oOptions, - oDebug, - oDebugAll, - oStatusFD, -#ifdef __riscos__ - oStatusFile, -#endif /* __riscos__ */ - oAttributeFD, -#ifdef __riscos__ - oAttributeFile, -#endif /* __riscos__ */ - oSKComments, - oNoSKComments, - oNoVersion, - oEmitVersion, - oCompletesNeeded, - oMarginalsNeeded, - oMaxCertDepth, - 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, - oNoMDCWarn, - oNoArmor, - oNoDefKeyring, - oNoGreeting, - oNoTTY, - oNoOptions, - oNoBatch, - oHomedir, - oWithColons, - oWithKeyData, - oSkipVerify, - 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, - oImportOptions, - oExportOptions, - 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, - oIgnoreMDCError, - oShowSessionKey, - oOverrideSessionKey, - oNoRandomSeedFile, - oAutoKeyRetrieve, - oNoAutoKeyRetrieve, - oUseAgent, - oNoUseAgent, - oGpgAgentInfo, - oMergeOnly, - oTryAllSecrets, - oTrustedKey, - oNoExpensiveTrustChecks, - oFixedListMode, - oNoSigCache, - oNoSigCreateCheck, - oAutoCheckTrustDB, - oNoAutoCheckTrustDB, - oPreservePermissions, - oDefaultPreferenceList, - oPersonalCipherPreferences, - oPersonalDigestPreferences, - oPersonalCompressPreferences, - oEmuMDEncodeBug, - oDisplay, - oTTYname, - oTTYtype, - oLCctype, - oLCmessages, - oGroup, - oStrict, - oNoStrict, -aTest }; - - -static ARGPARSE_OPTS opts[] = { - - { 300, NULL, 0, N_("@Commands:\n ") }, - - { aSign, "sign", 256, N_("|[file]|make a signature")}, - { 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")}, - { aListKeys, "list-public-keys", 256, "@" }, - { aListSigs, "list-sigs", 256, N_("list keys and signatures")}, - { aCheckKeys, "check-sigs",256, N_("check key signatures")}, - { 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")}, - { 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, "@" }, - { aImport, "import", 256 , N_("import/merge keys")}, - { aFastImport, "fast-import", 256 , "@"}, - { aListPackets, "list-packets",256,N_("list only the sequence of packets")}, - { aExportOwnerTrust, - "export-ownertrust", 256, N_("export the ownertrust values")}, - { aImportOwnerTrust, - "import-ownertrust", 256 , N_("import ownertrust values")}, - { aUpdateTrustDB, - "update-trustdb",0 , N_("update the trust database")}, - { aCheckTrustDB, - "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")}, - { aPrimegen, "gen-prime" , 256, "@" }, - { aGenRandom, "gen-random" , 256, "@" }, - - { 301, NULL, 0, N_("@\nOptions:\n ") }, - - { oArmor, "armor", 0, N_("create ascii armored output")}, - { oArmor, "armour", 0, "@" }, - { oRecipient, "recipient", 2, N_("|NAME|encrypt for NAME")}, - { oRecipient, "remote-user", 2, "@"}, /* old option name */ - { oDefRecipient, "default-recipient" ,2, - N_("|NAME|use NAME as default recipient")}, - { 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,"@"}, - { oImportOptions, "import-options",2,"@"}, - { oExportOptions, "export-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") }, -#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|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")}, - { 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" - )}, - - { 303, NULL, 0, N_("@\nExamples:\n\n" - " -se -r Bob [file] sign and encrypt for user Bob\n" - " --clearsign [file] make a clear text signature\n" - " --detach-sign [file] make a detached signature\n" - " --list-keys [names] show keys\n" - " --fingerprint [names] show fingerprints\n" ) }, - - /* hidden options */ - { aExportOwnerTrust, "list-ownertrust",0 , "@"}, /* alias */ - { 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, "@" }, - { oNoMDCWarn, "no-mdc-warning", 0, "@" }, - { oNoArmor, "no-armor", 0, "@"}, - { oNoArmor, "no-armour", 0, "@"}, - { oNoDefKeyring, "no-default-keyring", 0, "@" }, - { oNoGreeting, "no-greeting", 0, "@" }, - { oNoOptions, "no-options", 0, "@" }, /* shortcut for --options /dev/null */ - { oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */ - { oNoBatch, "no-batch", 0, "@" }, - { oWithColons, "with-colons", 0, "@"}, - { oWithKeyData,"with-key-data", 0, "@"}, - { aListKeys, "list-key", 0, "@" }, /* alias */ - { aListSigs, "list-sig", 0, "@" }, /* alias */ - { aCheckKeys, "check-sig",0, "@" }, /* alias */ - { 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, "@" }, - { oWithFingerprint, "with-fingerprint", 0, "@" }, - { 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,"@" }, - { oIgnoreMDCError, "ignore-mdc-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, "@"}, - { 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, "@" }, - { oStrict, "strict", 0, "@" }, - { oNoStrict, "no-strict", 0, "@" }, -{0} }; - - - -int g10_errors_seen = 0; - -static int utf8_strings = 0; -static int maybe_setuid = 1; - -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 ); -static void add_notation_data( const char *string, int which ); -static void add_policy_url( const char *string, int which ); - -#ifdef __riscos__ -RISCOS_GLOBAL_STATICS("GnuPG Heap") -#endif /* __riscos__ */ - -const char * -strusage( int level ) -{ - static char *digests, *pubkeys, *ciphers, *zips; - const char *p; - switch( level ) { - case 11: p = "gpg (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: gpg [options] [files] (-h for help)"); - break; - case 41: p = - _("Syntax: gpg [options] [files]\n" - "sign, check, encrypt or decrypt\n" - "default operation depends on the input data\n"); - 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( !pubkeys ) - 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: ", '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 = default_strusage(level); - } - return p; -} - - -static char * -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, *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, ", "); - - 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 ) - p = stpcpy(p, "\n" ); - return list; -} - - -static void -i18n_init(void) -{ - #ifdef USE_SIMPLE_GETTEXT - set_gettext_file( PACKAGE ); - #else - #ifdef ENABLE_NLS - setlocale( LC_ALL, "" ); - bindtextdomain( PACKAGE, G10_LOCALEDIR ); - textdomain( PACKAGE ); - #endif - #endif -} - -static void -wrong_args( const char *text) -{ - fputs(_("usage: gpg [options] "),stderr); - fputs(text,stderr); - putc('\n',stderr); - g10_exit(2); -} - - -static char * -make_username( const char *string ) -{ - char *p; - if( utf8_strings ) - p = m_strdup(string); - else - p = native_to_utf8( string ); - return p; -} - - -static void -set_debug(void) -{ - if( opt.debug & DBG_MEMORY_VALUE ) - memory_debug_mode = 1; - if( opt.debug & DBG_MEMSTAT_VALUE ) - memory_stat_debug_mode = 1; - if( opt.debug & DBG_MPI_VALUE ) - mpi_debug_mode = 1; - if( opt.debug & DBG_CIPHER_VALUE ) - g10c_debug_mode = 1; - if( opt.debug & DBG_IOBUF_VALUE ) - iobuf_debug_mode = 1; - -} - - -/* We need the home directory also in some other directories, so make - sure that both variables are always in sync. */ -static void -set_homedir (char *dir) -{ - if (!dir) - dir = ""; - g10_opt_homedir = opt.homedir = dir; -} - - -static void -set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) -{ - enum cmd_and_opt_values cmd = *ret_cmd; - - if( !cmd || cmd == new_cmd ) - cmd = new_cmd; - else if( cmd == aSign && new_cmd == aEncr ) - 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 ) - || ( cmd == aClearsign && new_cmd == aSign ) ) - cmd = aClearsign; - else { - log_error(_("conflicting commands\n")); - 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 = sign found in group definition \"%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; -} - -/* We need to check three things. - - 0) The homedir. It must be x00, a directory, and owned by the - user. - - 1) The options file. Okay unless it or its containing directory is - group or other writable or not owned by us. disable exec in this - case. - - 2) Extensions. Same as #2. - - Returns true if the item is unsafe. */ -static int -check_permissions(const char *path,int item) -{ -#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM) - static int homedir_cache=-1; - char *tmppath,*dir; - struct stat statbuf,dirbuf; - int homedir=0,ret=0,checkonly=0; - int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0; - - if(opt.no_perm_warn) - return 0; - - assert(item==0 || item==1 || item==2); - - /* extensions may attach a path */ - if(item==2 && 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); - - /* If the item is located in the homedir, but isn't the homedir, - don't continue if we already checked the homedir itself. This is - to avoid user confusion with an extra options file warning which - could be rectified if the homedir itself had proper - permissions. */ - if(item!=0 && homedir_cache>-1 - && ascii_strncasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0) - { - ret=homedir_cache; - goto end; - } - - /* It's okay if the file or directory doesn't exist */ - if(stat(tmppath,&statbuf)!=0) - { - ret=0; - goto end; - } - - /* Now check the enclosing directory. 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,&dirbuf)!=0 || !S_ISDIR(dirbuf.st_mode)) - { - /* Weird error */ - ret=1; - goto end; - } - - m_free(dir); - - /* Assume failure */ - ret=1; - - if(item==0) - { - /* The homedir must be x00, a directory, and owned by the user. */ - - if(S_ISDIR(statbuf.st_mode)) - { - if(statbuf.st_uid==getuid()) - { - if((statbuf.st_mode & (S_IRWXG|S_IRWXO))==0) - ret=0; - else - perm=1; - } - else - own=1; - - homedir_cache=ret; - } - } - else if(item==1 || item==2) - { - /* The options or extension file. Okay unless it or its - containing directory is group or other writable or not owned - by us or root. */ - - if(S_ISREG(statbuf.st_mode)) - { - if(statbuf.st_uid==getuid() || statbuf.st_uid==0) - { - if((statbuf.st_mode & (S_IWGRP|S_IWOTH))==0) - { - /* it's not writable, so make sure the enclosing - directory is also not writable */ - if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) - { - if((dirbuf.st_mode & (S_IWGRP|S_IWOTH))==0) - ret=0; - else - enc_dir_perm=1; - } - else - enc_dir_own=1; - } - else - { - /* it's writable, so the enclosing directory had - better not let people get to it. */ - if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) - { - if((dirbuf.st_mode & (S_IRWXG|S_IRWXO))==0) - ret=0; - else - perm=enc_dir_perm=1; /* unclear which one to fix! */ - } - else - enc_dir_own=1; - } - } - else - own=1; - } - } - else - BUG(); - - if(!checkonly) - { - if(own) - { - if(item==0) - log_info(_("WARNING: unsafe ownership on " - "homedir \"%s\"\n"),tmppath); - else if(item==1) - log_info(_("WARNING: unsafe ownership on " - "configuration file \"%s\"\n"),tmppath); - else - log_info(_("WARNING: unsafe ownership on " - "extension \"%s\"\n"),tmppath); - } - if(perm) - { - if(item==0) - log_info(_("WARNING: unsafe permissions on " - "homedir \"%s\"\n"),tmppath); - else if(item==1) - log_info(_("WARNING: unsafe permissions on " - "configuration file \"%s\"\n"),tmppath); - else - log_info(_("WARNING: unsafe permissions on " - "extension \"%s\"\n"),tmppath); - } - if(enc_dir_own) - { - if(item==0) - log_info(_("WARNING: unsafe enclosing directory ownership on " - "homedir \"%s\"\n"),tmppath); - else if(item==1) - log_info(_("WARNING: unsafe enclosing directory ownership on " - "configuration file \"%s\"\n"),tmppath); - else - log_info(_("WARNING: unsafe enclosing directory ownership on " - "extension \"%s\"\n"),tmppath); - } - if(enc_dir_perm) - { - if(item==0) - log_info(_("WARNING: unsafe enclosing directory permissions on " - "homedir \"%s\"\n"),tmppath); - else if(item==1) - log_info(_("WARNING: unsafe enclosing directory permissions on " - "configuration file \"%s\"\n"),tmppath); - else - log_info(_("WARNING: unsafe enclosing directory permissions on " - "extension \"%s\"\n"),tmppath); - } - } - - end: - m_free(tmppath); - - if(homedir) - homedir_cache=ret; - - return ret; - -#endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */ - - return 0; -} - -int -main( int argc, char **argv ) -{ - ARGPARSE_ARGS pargs; - IOBUF a; - int rc=0; - int orig_argc; - char **orig_argv; - const char *fname; - char *username; - int may_coredump; - STRLIST sl, remusr= NULL, locusr=NULL; - STRLIST nrings=NULL, sec_nrings=NULL; - armor_filter_context_t afx; - int detached_sig = 0; - FILE *configfp = NULL; - char *configname = NULL; - unsigned configlineno; - int parse_debug = 0; - int default_config = 1; - int default_keyring = 1; - int greeting = 0; - int nogreeting = 0; - int use_random_seed = 1; - enum cmd_and_opt_values cmd = 0; - 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(); - 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"); - secure_random_alloc(); /* put random number into secure memory */ - may_coredump = disable_core_dumps(); - init_signals(); - create_dotlock(NULL); /* register locking cleanup */ - i18n_init(); - opt.command_fd = -1; /* no command fd */ - opt.compress = -1; /* defaults to standard compress level */ - /* note: if you change these lines, look at oOpenPGP */ - 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 = 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.force_v3_sigs = 1; - opt.escape_from = 1; - opt.import_options=0; - opt.export_options= - EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES; - opt.keyserver_options.import_options=IMPORT_REPAIR_HKP_SUBKEY_BUG; - opt.keyserver_options.export_options= - EXPORT_INCLUDE_NON_RFC|EXPORT_INCLUDE_ATTRIBUTES; - opt.keyserver_options.include_subkeys=1; - opt.keyserver_options.include_revoked=1; -#if defined (__MINGW32__) || defined (__CYGWIN32__) - set_homedir ( read_w32_registry_string( NULL, - "Software\\GNU\\GnuPG", "HomeDir" )); -#else - set_homedir ( getenv("GNUPGHOME") ); -#endif - if( !*opt.homedir ) - set_homedir ( GNUPG_HOMEDIR ); - - /* check whether we have a config file on the commandline */ - orig_argc = argc; - orig_argv = argv; - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ - while( arg_parse( &pargs, opts) ) { - if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll ) - parse_debug++; - else if( pargs.r_opt == oOptions ) { - /* yes there is one, so we do not try the default one, but - * read the option file when it is encountered at the commandline - */ - default_config = 0; - } - else if( pargs.r_opt == oNoOptions ) - default_config = 0; /* --no-options */ - else if( pargs.r_opt == oHomedir ) - set_homedir ( pargs.r.ret_str ); - else if( pargs.r_opt == oNoPermissionWarn ) - opt.no_perm_warn=1; - else if (pargs.r_opt == oStrict ) - { - opt.strict=1; - log_set_strict(1); - } - else if (pargs.r_opt == oNoStrict ) - { - opt.strict=0; - log_set_strict(0); - } - #ifdef USE_SHM_COPROCESSING - else if( pargs.r_opt == oRunAsShmCP ) { - /* does not make sense in a options file, we do it here, - * so that we are the able to drop setuid as soon as possible */ - opt.shm_coprocess = 1; - requested_shm_size = pargs.r.ret_ulong; - } - 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( iobuf_translate_file_handle (pargs.r.ret_int, 1) ); - } - #endif - } - -#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; - set_homedir (buf); - } -#endif -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) { - init_shm_coprocessing(requested_shm_size, 1 ); - } -#endif - /* initialize the secure memory. */ - secmem_init( 16384 ); - maybe_setuid = 0; - /* Okay, we are now working under our real uid */ - - set_native_charset (NULL); /* Try to auto set the character set */ - - if( default_config ) - { - configname = make_filename(opt.homedir, "gpg" EXTSEP_S "conf", NULL ); - if (!access (configname, R_OK)) - { /* Print a warning when both config files are present. */ - char *p = make_filename(opt.homedir, "options", NULL ); - if (!access (p, R_OK)) - log_info (_("NOTE: old default options file `%s' ignored\n"), p); - m_free (p); - } - else - { /* Keep on using the old default one. */ - m_free (configname); - configname = make_filename(opt.homedir, "options", NULL ); - } - } - argc = orig_argc; - argv = orig_argv; - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags= 1; /* do not remove the args */ - - /* By this point we have a homedir, and cannot change it. */ - check_permissions(opt.homedir,0); - - next_pass: - if( configname ) { - if(check_permissions(configname,1)) - { - /* 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 ) { - if( default_config ) { - if( parse_debug ) - log_info(_("NOTE: no default option file `%s'\n"), - configname ); - } - else { - log_error(_("option file `%s': %s\n"), - configname, strerror(errno) ); - g10_exit(2); - } - m_free(configname); configname = NULL; - } - if( parse_debug && configname ) - log_info(_("reading options from `%s'\n"), configname ); - default_config = 0; - } - - while( optfile_parse( configfp, configname, &configlineno, - &pargs, opts) ) { - switch( pargs.r_opt ) { - case aCheckKeys: set_cmd( &cmd, aCheckKeys); break; - case aListPackets: set_cmd( &cmd, aListPackets); break; - case aImport: set_cmd( &cmd, aImport); break; - 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 aDeleteSecretKeys: set_cmd( &cmd, aDeleteSecretKeys); - 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 aListTrustDB: set_cmd( &cmd, aListTrustDB); break; - case aCheckTrustDB: set_cmd( &cmd, aCheckTrustDB); break; - case aUpdateTrustDB: set_cmd( &cmd, aUpdateTrustDB); break; - case aFixTrustDB: set_cmd( &cmd, aFixTrustDB); break; - case aListTrustPath: set_cmd( &cmd, aListTrustPath); break; - case aDeArmor: set_cmd( &cmd, aDeArmor); break; - 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; - case oQuiet: opt.quiet = 1; break; - case oNoTTY: tty_no_terminal(1); break; - case oDryRun: opt.dry_run = 1; break; - case oInteractive: opt.interactive = 1; 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; 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( 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: - 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 ) { - 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: 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; - case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break; - case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break; - case oTrustDBName: trustdb_name = pargs.r.ret_str; break; - case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break; - case oDefRecipient: - if( *pargs.r.ret_str ) - opt.def_recipient = make_username(pargs.r.ret_str); - break; - case oDefRecipientSelf: - m_free(opt.def_recipient); opt.def_recipient = NULL; - opt.def_recipient_self = 1; - break; - case oNoDefRecipient: - m_free(opt.def_recipient); opt.def_recipient = NULL; - opt.def_recipient_self = 0; - 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; - - case oSkipVerify: opt.skip_verify=1; break; - case oCompressAlgo: opt.def_compress_algo = pargs.r.ret_int; break; - case oCompressKeys: opt.compress_keys = 1; break; - case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break; - case oAlwaysTrust: opt.always_trust = 1; break; - case oLoadExtension: -#ifndef __riscos__ -#if defined(USE_DYNAMIC_LINKING) || defined(__MINGW32__) - if(check_permissions(pargs.r.ret_str,2)) - log_info(_("cipher extension \"%s\" not loaded due to " - "unsafe permissions\n"),pargs.r.ret_str); - else - register_cipher_extension(orig_argc? *orig_argv:NULL, - pargs.r.ret_str); -#endif -#else /* __riscos__ */ - not_implemented("load-extension"); -#endif /* __riscos__ */ - break; - case oRFC1991: - opt.rfc1991 = 1; - opt.rfc2440 = 0; - opt.force_v4_certs = 0; - opt.disable_mdc = 1; - opt.escape_from = 1; - break; - case oOpenPGP: - /* TODO: When 2440bis becomes a RFC, these may need - changing. */ - opt.rfc1991 = 0; - opt.rfc2440 = 1; - opt.disable_mdc = 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; - opt.compress_keys = 0; /* not mandated but we do it */ - opt.compress_sigs = 0; /* ditto. */ - 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 = 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 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 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 = 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 ); - sl->flags = 1; - 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 = 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 oNoMDCWarn: opt.no_mdc_warn=1; break; - case oCharset: - if( set_native_charset( pargs.r.ret_str ) ) - log_error(_("%s is not a valid character set\n"), - pargs.r.ret_str); - 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; - case oLockNever: disable_dotlock(); break; - case oLockMultiple: -#ifndef __riscos__ - opt.lock_once = 0; -#else /* __riscos__ */ - not_implemented("lock-multiple"); -#endif /* __riscos__ */ - break; - case oKeyServer: - opt.keyserver_uri=m_strdup(pargs.r.ret_str); - 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 oImportOptions: - if(!parse_import_options(pargs.r.ret_str,&opt.import_options)) - { - if(configname) - log_error(_("%s:%d: invalid import options\n"), - configname,configlineno); - else - log_error(_("invalid import options\n")); - } - break; - case oExportOptions: - if(!parse_export_options(pargs.r.ret_str,&opt.export_options)) - { - if(configname) - log_error(_("%s:%d: invalid export options\n"), - configname,configlineno); - else - log_error(_("invalid export options\n")); - } - break; - case oTempDir: opt.temp_dir=pargs.r.ret_str; break; - case oExecPath: - if(set_exec_path(pargs.r.ret_str,0)) - log_error(_("unable to set exec-path to %s\n"),pargs.r.ret_str); - else - opt.exec_path_set=1; - 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: - disable_cipher_algo( string_to_cipher_algo(pargs.r.ret_str) ); - break; - 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.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 oIgnoreMDCError: opt.ignore_mdc_error = 1; break; - case oNoRandomSeedFile: use_random_seed = 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; - case oStrict: opt.strict=1; log_set_strict(1); break; - case oNoStrict: opt.strict=0; log_set_strict(0); break; - default : pargs.err = configfp? 1:2; break; - } - } - - if( configfp ) { - fclose( configfp ); - configfp = NULL; - m_free(configname); configname = NULL; - goto next_pass; - } - m_free( configname ); configname = NULL; - if( log_get_errorcount(0) ) - g10_exit(2); - if( nogreeting ) - greeting = 0; - - if( greeting ) { - fprintf(stderr, "%s %s; %s\n", - strusage(11), strusage(13), strusage(14) ); - fprintf(stderr, "%s\n", strusage(15) ); - } - #ifdef IS_DEVELOPMENT_VERSION - if( !opt.batch ) { - log_info("NOTE: THIS IS A DEVELOPMENT VERSION!\n"); - log_info("It is only intended for test purposes and should NOT be\n"); - log_info("used in a production environment or with production keys!\n"); - } - #endif - - if (opt.verbose > 2) - log_info ("using character set `%s'\n", get_native_charset ()); - - 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) - log_error(_("%s not allowed with %s!\n"), - "--textmode", "--no-literal" ); - if (opt.set_filename) - log_error(_("%s makes no sense with %s!\n"), - 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 ); - - secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */ - - set_debug(); - - /* 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) - { - /* This only sets IDEA for symmetric encryption - since it is set via select_algo_from_prefs for - pk encryption. */ - m_free(def_cipher_string); - def_cipher_string = m_strdup("idea"); - } - - /* PGP2 can't handle the output from the textmode - filter, so we disable it for anything that could - create a literal packet (only encryption and - symmetric encryption, since we disable signing - above). */ - if(!unusable) - opt.textmode=0; - } - - if(unusable) - { - log_info(_("this message may not be usable by %s\n"), - "PGP 2.x"); - 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.sk_comments=0; - opt.escape_from=1; - opt.force_v3_sigs=1; - opt.ask_sig_expire=0; - opt.def_compress_algo=1; - - if(opt.pgp6) /* pgp7 has MDC */ - { - opt.force_mdc=0; - opt.disable_mdc=1; - } - } - } - - /* must do this after dropping setuid, because string_to... - * may try to load an module */ - if( def_cipher_string ) { - 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 = 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 = 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 = 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.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 ) - log_error(_("marginals-needed must be greater than 1\n")); - if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 ) - log_error(_("max-cert-depth must be in range 1 to 255\n")); - switch( opt.s2k_mode ) { - case 0: - log_info(_("NOTE: simple S2K mode (0) is strongly discouraged\n")); - break; - case 1: case 3: break; - default: - 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) ) - g10_exit(2); - - /* set the random seed file */ - if( use_random_seed ) { - char *p = make_filename(opt.homedir, "random_seed", NULL ); - set_random_seed_file(p); - m_free(p); - } - - if( !cmd && opt.fingerprint && !with_fpr ) { - set_cmd( &cmd, aListKeys); - } - - if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */ - if( cmd == aKModeC ) { - opt.fingerprint = 1; - cmd = aKMode; - } - opt.list_sigs = 0; - if( opt.verbose > 2 ) - opt.check_sigs++; - if( opt.verbose > 1 ) - opt.list_sigs++; - - opt.verbose = opt.verbose > 1; - 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 ) - cmd = aClearsign; - - 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". 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 (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 ) - keydb_add_resource ( sl->d, 0, 0 ); - } - FREE_STRLIST(nrings); - FREE_STRLIST(sec_nrings); - - - if( pwfd != -1 ) /* read the passphrase now. */ - read_passphrase_from_fd( pwfd ); - - fname = argc? *argv : NULL; - - switch( cmd ) { - case aPrimegen: - case aPrintMD: - case aPrintMDs: - case aGenRandom: - case aDeArmor: - case aEnArmor: - case aFixTrustDB: - break; - case aKMode: - case aListKeys: - case aListSecretKeys: - case aCheckKeys: - if( opt.with_colons ) /* need this to list the trust */ - rc = setup_trustdb(1, trustdb_name ); - break; - case aExportOwnerTrust: rc = setup_trustdb( 0, trustdb_name ); break; - case aListTrustDB: rc = setup_trustdb( argc? 1:0, trustdb_name ); break; - default: rc = setup_trustdb(1, trustdb_name ); break; - } - if( 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 */ - if( argc > 1 ) - wrong_args(_("--store [filename]")); - if( (rc = encode_store(fname)) ) - log_error_f( print_fname_stdin(fname), - "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",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), 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 */ - for( ; argc; argc--, argv++ ) - add_to_strlist( &sl, *argv ); - } - else { - if( argc > 1 ) - wrong_args(_("--sign [filename]")); - if( argc ) { - 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", g10_errstr(rc) ); - free_strlist(sl); - break; - - case aSignEncr: /* sign and encrypt the given file */ - if( argc > 1 ) - wrong_args(_("--sign --encrypt [filename]")); - if( argc ) { - 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), 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), g10_errstr(rc) ); - break; - - case aVerify: - if( (rc = verify_signatures( argc, argv ) )) - 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", 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", 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 ); - m_free(username); - break; - - case aLSignKey: - if( argc != 1 ) - wrong_args(_("--lsign-key user-id")); - username = make_username( fname ); - keyedit_menu(fname, locusr, NULL, 2 ); - 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]")); - username = make_username( fname ); - if( argc > 1 ) { - sl = NULL; - for( argc--, argv++ ; argc; argc--, argv++ ) - append_to_strlist( &sl, *argv ); - keyedit_menu( username, locusr, sl, 0 ); - free_strlist(sl); - } - else - keyedit_menu(username, locusr, NULL, 0 ); - m_free(username); - break; - - 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: - opt.list_sigs = 1; - case aListKeys: - sl = NULL; - for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl ); - free_strlist(sl); - break; - case aListSecretKeys: - sl = NULL; - for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); - secret_key_list( sl ); - free_strlist(sl); - break; - - case aKMode: /* list keyring -- NOTE: This will be removed soon */ - if( argc < 2 ) { /* -kv [userid] */ - sl = NULL; - if (argc && **argv) - add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl ); - free_strlist(sl); - } - else if( argc == 2 ) { /* -kv userid keyring */ - if( access( argv[1], R_OK ) ) { - log_error(_("can't open %s: %s\n"), - print_fname_stdin(argv[1]), strerror(errno)); - } - else { - /* add keyring (default keyrings are not registered in this - * special case */ - keydb_add_resource( argv[1], 0, 0 ); - sl = NULL; - if (**argv) - add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl ); - free_strlist(sl); - } - } - else - wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") ); - break; - - case aKeygen: /* generate a key */ - if( opt.batch ) { - if( argc > 1 ) - wrong_args("--gen-key [parameterfile]"); - generate_keypair( argc? *argv : NULL ); - } - else { - if( argc ) - wrong_args("--gen-key"); - generate_keypair(NULL); - } - break; - - case aFastImport: - opt.import_options |= IMPORT_FAST_IMPORT; - case aImport: - import_keys( argc? argv:NULL, argc, NULL, opt.import_options ); - break; - - case aExport: - case aExportAll: - case aSendKeys: - case aRecvKeys: - sl = NULL; - for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); - if( cmd == aSendKeys ) - keyserver_export( sl ); - else if( cmd == aRecvKeys ) - keyserver_import( sl ); - else - export_pubkeys( sl, opt.export_options ); - 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++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); - export_seckeys( sl ); - free_strlist(sl); - break; - - case aExportSecretSub: - sl = NULL; - for( ; argc; argc--, argv++ ) - add_to_strlist2( &sl, *argv, utf8_strings ); - export_secsubkeys( sl ); - free_strlist(sl); - break; - - case aGenRevoke: - if( argc != 1 ) - wrong_args("--gen-revoke user-id"); - username = make_username(*argv); - gen_revoke( 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: - if( argc > 1 ) - wrong_args("--dearmor [file]"); - rc = dearmor_file( argc? *argv: NULL ); - if( rc ) - log_error(_("dearmoring failed: %s\n"), g10_errstr(rc)); - break; - - case aEnArmor: - if( argc > 1 ) - wrong_args("--enarmor [file]"); - rc = enarmor_file( argc? *argv: NULL ); - if( rc ) - log_error(_("enarmoring failed: %s\n"), g10_errstr(rc)); - break; - - - case aPrimegen: - { int mode = argc < 2 ? 0 : atoi(*argv); - - if( mode == 1 && argc == 2 ) { - mpi_print( stdout, generate_public_prime( atoi(argv[1]) ), 1); - } - else if( mode == 2 && argc == 3 ) { - mpi_print( stdout, generate_elg_prime( - 0, atoi(argv[1]), - atoi(argv[2]), NULL,NULL ), 1); - } - else if( mode == 3 && argc == 3 ) { - MPI *factors; - mpi_print( stdout, generate_elg_prime( - 1, atoi(argv[1]), - atoi(argv[2]), NULL,&factors ), 1); - putchar('\n'); - mpi_print( stdout, factors[0], 1 ); /* print q */ - } - else if( mode == 4 && argc == 3 ) { - MPI g = mpi_alloc(1); - mpi_print( stdout, generate_elg_prime( - 0, atoi(argv[1]), - atoi(argv[2]), g, NULL ), 1); - putchar('\n'); - mpi_print( stdout, g, 1 ); - mpi_free(g); - } - else - wrong_args("--gen-prime mode bits [qbits] "); - putchar('\n'); - } - break; - - case aGenRandom: - { - int level = argc ? atoi(*argv):0; - int count = argc > 1 ? atoi(argv[1]): 0; - int endless = !count; - - if( argc < 1 || argc > 2 || level < 0 || level > 2 || count < 0 ) - wrong_args("--gen-random 0|1|2 [count]"); - - while( endless || count ) { - byte *p; - /* 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 = get_random_bits( n*8, level, 0); - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(stdout), O_BINARY ); - #endif - 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; - - case aPrintMD: - if( argc < 1) - wrong_args("--print-md algo [files]"); - { - int all_algos = (**argv=='*' && !(*argv)[1]); - int algo = all_algos? 0 : string_to_digest_algo(*argv); - - if( !algo && !all_algos ) - log_error(_("invalid hash algorithm `%s'\n"), *argv ); - else { - argc--; argv++; - if( !argc ) - print_mds(NULL, algo); - else { - for(; argc; argc--, argv++ ) - print_mds(*argv, algo); - } - } - } - break; - - case aPrintMDs: /* old option */ - if( !argc ) - print_mds(NULL,0); - else { - for(; argc; argc--, argv++ ) - print_mds(*argv,0); - } - break; - - case aListTrustDB: - if( !argc ) - list_trustdb(NULL); - else { - for( ; argc; argc--, argv++ ) - list_trustdb( *argv ); - } - break; - - case aUpdateTrustDB: - if( argc ) - wrong_args("--update-trustdb"); - update_trustdb(); - break; - - case aCheckTrustDB: - /* Old versions allowed for arguments - ignore them */ - check_trustdb(); - break; - - case aFixTrustDB: - log_error("this command is not yet implemented.\n"); - log_error("A workaround is to use \"--export-ownertrust\", remove\n"); - log_error("the trustdb file and do an \"--import-ownertrust\".\n" ); - break; - - case aListTrustPath: - if( !argc ) - wrong_args("--list-trust-path <user-ids>"); - for( ; argc; argc--, argv++ ) { - username = make_username( *argv ); - list_trust_path( username ); - m_free(username); - } - break; - - case aExportOwnerTrust: - if( argc ) - wrong_args("--export-ownertrust"); - export_ownertrust(); - break; - - case aImportOwnerTrust: - if( argc > 1 ) - 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=2; - default: - if( argc > 1 ) - wrong_args(_("[filename]")); - /* Issue some output for the unix newbie */ - if( !fname && !opt.outfile && isatty( fileno(stdin) ) - && isatty( fileno(stdout) ) && isatty( fileno(stderr) ) ) - log_info(_("Go ahead and type your message ...\n")); - - if( !(a = iobuf_open(fname)) ) - log_error(_("can't open `%s'\n"), print_fname_stdin(fname)); - else { - - if( !opt.no_armor ) { - if( use_armor_filter( a ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( a, armor_filter, &afx ); - } - } - if( cmd == aListPackets ) { - set_packet_list_mode(1); - opt.list_packets=1; - } - rc = proc_packets(NULL, a ); - if( rc ) - log_error("processing message failed: %s\n", g10_errstr(rc) ); - iobuf_close(a); - } - break; - } - - /* cleanup */ - FREE_STRLIST(remusr); - FREE_STRLIST(locusr); - g10_exit(0); - return 8; /*NEVER REACHED*/ -} - - -void -g10_exit( int rc ) -{ - update_random_seed_file(); - if( opt.debug & DBG_MEMSTAT_VALUE ) { - m_print_stats("on exit"); - random_dump_stats(); - } - if( opt.debug ) - secmem_dump_stats(); - secmem_term(); - rc = rc? rc : log_get_errorcount(0)? 2 : - g10_errors_seen? 1 : 0; - exit(rc ); -} - - - - -static void -print_hex( byte *p, size_t n ) -{ - int i; - - if( n == 20 ) { - for(i=0; i < n ; i++, i++, p += 2 ) { - if( i ) - putchar(' '); - if( i == 10 ) - putchar(' '); - printf("%02X%02X", *p, p[1] ); - } - } - else if( n == 24 ) { - for(i=0; i < n ; i += 4, p += 4 ) { - if( i ) - putchar(' '); - if( i == 12 ) - putchar(' '); - printf("%02X%02X%02X%02X", *p, p[1], p[2], p[3] ); - } - } - else { - for(i=0; i < n ; i++, p++ ) { - if( i ) - putchar(' '); - if( i && !(i%8) ) - putchar(' '); - printf("%02X", *p ); - } - } -} - -static void -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; - MD_HANDLE md; - char *pname; - - if( !fname ) { - fp = stdin; - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(fp) , O_BINARY ); - #endif - pname = m_strdup("[stdin]: "); - } - else { - pname = m_alloc(strlen(fname)+3); - strcpy(stpcpy(pname,fname),": "); - fp = fopen( fname, "rb" ); - } - if( !fp ) { - log_error("%s%s\n", pname, strerror(errno) ); - m_free(pname); - return; - } - - md = md_open( 0, 0 ); - if( algo ) - md_enable( md, algo ); - else { - 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 ); - } - - while( (n=fread( buf, 1, DIM(buf), fp )) ) - md_write( md, buf, n ); - if( ferror(fp) ) - log_error("%s%s\n", pname, strerror(errno) ); - else { - 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'); - } - } - md_close(md); - - if( fp != stdin ) - fclose(fp); -} - - -/**************** - * Check the supplied name,value string and add it to the notation - * data to be used for signatures. which==0 for sig notations, and 1 - * for cert notations. -*/ -static void -add_notation_data( const char *string, int which ) -{ - const char *s; - 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++; - } - - 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; - } - } - /* 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) ) { - log_error(_("a notation value must not use " - "any control characters\n") ); - return; - } - else if( *s & 0x80 ) - highbit = 1; - } - - if( highbit ) /* must use UTF8 encoding */ - sl = add_to_strlist2( notation_data, string, utf8_strings ); - else - sl = add_to_strlist( notation_data, string ); - - if( critical ) - sl->flags |= 1; -} - - -static void -add_policy_url( const char *string, int which ) -{ - int i,critical=0; - STRLIST sl; - - if(*string=='!') - { - string++; - critical=1; - } - - 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 deleted file mode 100644 index 991b98d2f..000000000 --- a/g10/getkey.c +++ /dev/null @@ -1,2476 +0,0 @@ -/* getkey.c - Get a key from the database - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> -#include "util.h" -#include "packet.h" -#include "memory.h" -#include "iobuf.h" -#include "keydb.h" -#include "options.h" -#include "main.h" -#include "trustdb.h" -#include "i18n.h" - -#define MAX_PK_CACHE_ENTRIES 200 -#define MAX_UID_CACHE_ENTRIES 200 - -#if MAX_PK_CACHE_ENTRIES < 2 - #error We need the cache for key creation -#endif - - -struct getkey_ctx_s { - int exact; - KBNODE keyblock; - KBPOS kbpos; - KBNODE found_key; /* pointer into some keyblock */ - int last_rc; - int req_usage; - int req_algo; - KEYDB_HANDLE kr_handle; - int not_allocated; - int nitems; - KEYDB_SEARCH_DESC items[1]; -}; - -#if 0 -static struct { - int any; - int okay_count; - int nokey_count; - int error_count; -} lkup_stats[21]; -#endif - -typedef struct keyid_list { - struct keyid_list *next; - u32 keyid[2]; -} *keyid_list_t; - - -#if MAX_PK_CACHE_ENTRIES - typedef struct pk_cache_entry { - struct pk_cache_entry *next; - u32 keyid[2]; - PKT_public_key *pk; - } *pk_cache_entry_t; - static pk_cache_entry_t pk_cache; - static int pk_cache_entries; /* number of entries in pk cache */ - static int pk_cache_disabled; -#endif - -#if MAX_UID_CACHE_ENTRIES < 5 - #error we really need the userid cache -#endif -typedef struct user_id_db { - struct user_id_db *next; - keyid_list_t keyids; - int len; - char name[1]; -} *user_id_db_t; -static user_id_db_t user_id_db; -static int uid_cache_entries; /* number of entries in uid cache */ - -static void merge_selfsigs( KBNODE keyblock ); -static int lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode ); - -#if 0 -static void -print_stats() -{ - int i; - for(i=0; i < DIM(lkup_stats); i++ ) { - if( lkup_stats[i].any ) - fprintf(stderr, - "lookup stats: mode=%-2d ok=%-6d nokey=%-6d err=%-6d\n", - i, - lkup_stats[i].okay_count, - lkup_stats[i].nokey_count, - lkup_stats[i].error_count ); - } -} -#endif - - -void -cache_public_key( PKT_public_key *pk ) -{ - #if MAX_PK_CACHE_ENTRIES - pk_cache_entry_t ce; - u32 keyid[2]; - - if( pk_cache_disabled ) - return; - - if( pk->dont_cache ) - return; - - if( is_ELGAMAL(pk->pubkey_algo) - || pk->pubkey_algo == PUBKEY_ALGO_DSA - || is_RSA(pk->pubkey_algo) ) { - keyid_from_pk( pk, keyid ); - } - else - return; /* don't know how to get the keyid */ - - for( ce = pk_cache; ce; ce = ce->next ) - if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) { - if( DBG_CACHE ) - log_debug("cache_public_key: already in cache\n"); - return; - } - - if( pk_cache_entries >= MAX_PK_CACHE_ENTRIES ) { - /* fixme: use another algorithm to free some cache slots */ - pk_cache_disabled=1; - if( opt.verbose > 1 ) - log_info(_("too many entries in pk cache - disabled\n")); - return; - } - pk_cache_entries++; - ce = m_alloc( sizeof *ce ); - ce->next = pk_cache; - pk_cache = ce; - ce->pk = copy_public_key( NULL, pk ); - ce->keyid[0] = keyid[0]; - ce->keyid[1] = keyid[1]; - #endif -} - - -/* - * Return the user ID from the given keyblock. - * We use the primary uid flag which has been set by the merge_selfsigs - * function. The returned value is only valid as long as then given - * keyblock is not changed - */ -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; - } - } - /* 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; -} - - -static void -release_keyid_list ( keyid_list_t k ) -{ - while ( k ) { - keyid_list_t k2 = k->next; - m_free (k); - k = k2; - } -} - -/**************** - * Store the association of keyid and userid - * Feed only public keys to this function. - */ -static void -cache_user_id( KBNODE keyblock ) -{ - user_id_db_t r; - const char *uid; - size_t uidlen; - keyid_list_t keyids = NULL; - KBNODE k; - - for (k=keyblock; k; k = k->next ) { - if ( k->pkt->pkttype == PKT_PUBLIC_KEY - || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - 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 ); - /* first check for duplicates */ - for(r=user_id_db; r; r = r->next ) { - keyid_list_t b = r->keyids; - for ( b = r->keyids; b; b = b->next ) { - if( b->keyid[0] == a->keyid[0] - && b->keyid[1] == a->keyid[1] ) { - if( DBG_CACHE ) - log_debug("cache_user_id: already in cache\n"); - release_keyid_list ( keyids ); - m_free ( a ); - return; - } - } - } - /* now put it into the cache */ - a->next = keyids; - keyids = a; - } - } - if ( !keyids ) - BUG (); /* No key no fun */ - - - uid = get_primary_uid ( keyblock, &uidlen ); - - if( uid_cache_entries >= MAX_UID_CACHE_ENTRIES ) { - /* fixme: use another algorithm to free some cache slots */ - r = user_id_db; - user_id_db = r->next; - release_keyid_list ( r->keyids ); - m_free(r); - uid_cache_entries--; - } - r = m_alloc( sizeof *r + uidlen-1 ); - r->keyids = keyids; - r->len = uidlen; - memcpy(r->name, uid, r->len); - r->next = user_id_db; - user_id_db = r; - uid_cache_entries++; -} - - -void -getkey_disable_caches() -{ - #if MAX_PK_CACHE_ENTRIES - { - pk_cache_entry_t ce, ce2; - - for( ce = pk_cache; ce; ce = ce2 ) { - ce2 = ce->next; - free_public_key( ce->pk ); - m_free( ce ); - } - pk_cache_disabled=1; - pk_cache_entries = 0; - pk_cache = NULL; - } - #endif - /* fixme: disable user id cache ? */ -} - - -static void -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 ( pk, a->pkt->pkt.public_key ); -} - -static void -sk_from_block ( GETKEY_CTX ctx, - PKT_secret_key *sk, KBNODE keyblock ) -{ - KBNODE a = ctx->found_key ? ctx->found_key : keyblock; - - assert ( a->pkt->pkttype == PKT_SECRET_KEY - || a->pkt->pkttype == PKT_SECRET_SUBKEY ); - - copy_secret_key( sk, a->pkt->pkt.secret_key); -} - - -/**************** - * Get a public key and store it into the allocated pk - * can be called with PK set to NULL to just read it into some - * internal structures. - */ -int -get_pubkey( PKT_public_key *pk, u32 *keyid ) -{ - int internal = 0; - int rc = 0; - - #if MAX_PK_CACHE_ENTRIES - { /* Try to get it from the cache */ - pk_cache_entry_t ce; - for( ce = pk_cache; ce; ce = ce->next ) { - if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) { - if( pk ) - copy_public_key( pk, ce->pk ); - return 0; - } - } - } - #endif - /* more init stuff */ - if( !pk ) { - pk = m_alloc_clear( sizeof *pk ); - internal++; - } - - - /* do a lookup */ - { 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 = 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 ); - } - get_pubkey_end( &ctx ); - release_kbnode ( kb ); - } - if( !rc ) - goto leave; - - rc = G10ERR_NO_PUBKEY; - - leave: - if( !rc ) - cache_public_key( pk ); - if( internal ) - free_public_key(pk); - return rc; -} - - -/* Get a public key and store it into the allocated pk. This function - differs from get_pubkey() in that it does not do a check of the key - to avoid recursion. It should be used only in very certain cases. */ -static int -get_pubkey_direct (PKT_public_key *pk, u32 *keyid) -{ - int rc = 0; - KEYDB_HANDLE hd; - KBNODE keyblock; - - assert (pk); -#if MAX_PK_CACHE_ENTRIES - { /* Try to get it from the cache */ - pk_cache_entry_t ce; - - for (ce = pk_cache; ce; ce = ce->next) - { - if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]) - { - if (pk) - copy_public_key (pk, ce->pk); - return 0; - } - } - } -#endif - - hd = keydb_new (0); - rc = keydb_search_kid (hd, keyid); - if (rc == -1) - { - keydb_release (hd); - return G10ERR_NO_PUBKEY; - } - rc = keydb_get_keyblock (hd, &keyblock); - keydb_release (hd); - if (rc) - { - log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc)); - return G10ERR_NO_PUBKEY; - } - - assert ( keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY ); - copy_public_key (pk, keyblock->pkt->pkt.public_key ); - release_kbnode (keyblock); - - /* Not caching key here since it won't have all of the fields - properly set. */ - - return 0; -} - - - -KBNODE -get_pubkeyblock( u32 *keyid ) -{ - struct getkey_ctx_s ctx; - int rc = 0; - 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 = 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 ); - - return rc ? NULL : keyblock; -} - - - - -/**************** - * Get a secret key and store it into sk - */ -int -get_seckey( PKT_secret_key *sk, u32 *keyid ) -{ - int rc; - 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 (1); - ctx.nitems = 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 ); - if ( !rc ) { - sk_from_block ( &ctx, sk, kb ); - } - get_seckey_end( &ctx ); - release_kbnode ( kb ); - - if( !rc ) { - /* check the secret key (this may prompt for a passprase to - * unlock the secret key - */ - rc = check_secret_key( sk, 0 ); - } - - return rc; -} - - -/**************** - * 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 - * G10ERR_NO_SECKEY := not availabe - */ -int -seckey_available( u32 *keyid ) -{ - int rc; - KEYDB_HANDLE hd = keydb_new (1); - - rc = keydb_search_kid (hd, keyid); - if ( rc == -1 ) - rc = G10ERR_NO_SECKEY; - keydb_release (hd); - return rc; -} - - -/**************** - * 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 - * 3 = match an email address - * 4 = match a substring of an email address - * 5 = match an email address, but compare from end - * 6 = word match mode - * 10 = it is a short KEYID (don't care about keyid[0]) - * 11 = it is a long KEYID - * 12 = it is a trustdb index (keyid is looked up) - * 16 = it is a 16 byte fingerprint - * 20 = it is a 20 byte fingerprint - * 21 = Unified fingerprint :fpr:pk_algo: - * (We don't use pk_algo yet) - * - * 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 - * on the length a short or complete one. - * - If the username starts with 32,33,40 or 41 hex-digits (the first one - * must be in the range 0..9), this is considered a fingerprint. - * - If the username starts with a left angle, we assume it is a complete - * email address and look only at this part. - * - If the username starts with a colon we assume it is a unified - * key specfification. - * - If the username starts with a '.', we assume it is the ending - * part of an email address - * - If the username starts with an '@', we assume it is a part of an - * email address - * - If the userid start with an '=' an exact compare is done. - * - If the userid starts with a '*' a case insensitive substring search is - * done (This is the default). - * - If the userid starts with a '+' we will compare individual words - * and a match requires that all the words are in the userid. - * Words are delimited by white space or "()<>[]{}.@-+_,;/&!" - * (note that you can't search for these characters). Compare - * is not case sensitive. - */ - -static int -classify_user_id2( const char *name, - KEYDB_SEARCH_DESC *desc, - int *force_exact ) -{ - 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++ ) - ; - - switch (*s) { - case 0: /* empty string is an error */ - return 0; - - case '.': /* an email address, compare from end */ - mode = KEYDB_SEARCH_MODE_MAILEND; - s++; - desc->u.name = s; - break; - - case '<': /* an email address */ - mode = KEYDB_SEARCH_MODE_MAIL; - desc->u.name = s; - break; - - case '@': /* part of an email address */ - mode = KEYDB_SEARCH_MODE_MAILSUB; - s++; - desc->u.name = s; - break; - - case '=': /* exact compare */ - mode = KEYDB_SEARCH_MODE_EXACT; - s++; - desc->u.name = s; - break; - - case '*': /* case insensitive substring search */ - mode = KEYDB_SEARCH_MODE_SUBSTR; - s++; - desc->u.name = s; - break; - - case '+': /* compare individual words */ - mode = KEYDB_SEARCH_MODE_WORDS; - s++; - desc->u.name = s; - break; - - case '#': /* local user id */ - return 0; /* This is now obsolete and van't not be used anymore*/ - - case ':': /*Unified fingerprint */ - { - const char *se, *si; - int i; - - se = strchr( ++s,':'); - if ( !se ) - return 0; - for (i=0,si=s; si < se; si++, i++ ) { - if ( !strchr("01234567890abcdefABCDEF", *si ) ) - return 0; /* invalid digit */ - } - if (i != 32 && i != 40) - return 0; /* invalid length of fpr*/ - 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 = KEYDB_SEARCH_MODE_FPR; - } - break; - - default: - if (s[0] == '0' && s[1] == 'x') { - hexprefix = 1; - s += 2; - } - - 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])) { - if (hexprefix) /* a "0x" prefix without correct */ - return 0; /* termination is an error */ - else /* The first chars looked like */ - 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++; - 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')) { - /* complete keyid */ - char buf[9]; - if (hexlength == 17) - s++; - mem2str(buf, s, 9 ); - 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')) { - /* md5 fingerprint */ - int i; - if (hexlength == 33) - s++; - 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')) { - /* sha1/rmd160 fingerprint */ - int i; - if (hexlength == 41) - s++; - 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 */ - - *force_exact = 0; - desc->u.name = s; - mode = KEYDB_SEARCH_MODE_SUBSTR; /* default mode */ - } - } - - 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 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, 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 */ - 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 */ - for(n=0, r=namelist; r; r = r->next ) - n++; - ctx = m_alloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items ); - ctx->nitems = n; - - for(n=0, r=namelist; r; r = r->next, n++ ) { - 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( 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 ); - } - } - - release_kbnode ( help_kb ); - - if (retctx) /* caller wants the context */ - *retctx = ctx; - else { - 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 (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( NULL, namelist, pk, NULL, 0, ret_keyblock, ret_kdbhd); - free_strlist( namelist ); - return rc; -} - -int -get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk, - STRLIST names, KBNODE *ret_keyblock ) -{ - return key_byname( retctx, names, pk, NULL, 0, ret_keyblock, NULL); -} - -int -get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock ) -{ - int rc; - - rc = lookup( ctx, ret_keyblock, 0 ); - if ( !rc && pk && ret_keyblock ) - pk_from_block ( ctx, pk, *ret_keyblock ); - - return rc; -} - - -void -get_pubkey_end( GETKEY_CTX ctx ) -{ - if( ctx ) { - memset (&ctx->kbpos, 0, sizeof ctx->kbpos); - keydb_release (ctx->kr_handle); - if( !ctx->not_allocated ) - m_free( ctx ); - } -} - - - - -/**************** - * 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 -get_pubkey_byfprint( PKT_public_key *pk, - const byte *fprint, size_t fprint_len) -{ - int rc; - - if( fprint_len == 20 || fprint_len == 16 ) { - struct getkey_ctx_s ctx; - 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==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 ); - release_kbnode ( kb ); - get_pubkey_end( &ctx ); - } - else - rc = G10ERR_GENERAL; /* Oops */ - return rc; -} - -/**************** - * Search for a key with the given fingerprint and return the - * complete keyblock which may have more than only this key. - */ -int -get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint, - size_t fprint_len ) -{ - int rc; - - if( fprint_len == 20 || fprint_len == 16 ) { - struct getkey_ctx_s ctx; - - memset( &ctx, 0, sizeof ctx ); - ctx.not_allocated = 1; - ctx.kr_handle = keydb_new (0); - 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, ret_keyblock, 0 ); - get_pubkey_end( &ctx ); - } - else - rc = G10ERR_GENERAL; /* Oops */ - - return rc; -} - - -/**************** - * Get a secret key by name and store it into sk - * If NAME is NULL use the default key - */ -static int -get_seckey_byname2( GETKEY_CTX *retctx, - PKT_secret_key *sk, const char *name, int unprotect, - KBNODE *retblock ) -{ - STRLIST namelist = NULL; - int rc; - - 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, 1, retblock, NULL ); - } - else if( !name ) { /* use the first one as default key */ - struct getkey_ctx_s ctx; - KBNODE kb = NULL; - - assert (!retctx ); /* do we need this at all */ - assert (!retblock); - memset( &ctx, 0, sizeof ctx ); - ctx.not_allocated = 1; - ctx.kr_handle = keydb_new (1); - ctx.nitems = 1; - ctx.items[0].mode = KEYDB_SEARCH_MODE_FIRST; - rc = lookup( &ctx, &kb, 1 ); - if (!rc && sk ) - sk_from_block ( &ctx, sk, kb ); - release_kbnode ( kb ); - get_seckey_end( &ctx ); - } - else { - add_to_strlist( &namelist, name ); - rc = key_byname( retctx, namelist, NULL, sk, 1, retblock, NULL ); - } - - free_strlist( namelist ); - - if( !rc && unprotect ) - rc = check_secret_key( sk, 0 ); - - 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, 1, ret_keyblock, NULL ); -} - - -int -get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ) -{ - int rc; - - rc = lookup( ctx, ret_keyblock, 1 ); - if ( !rc && sk && ret_keyblock ) - sk_from_block ( ctx, sk, *ret_keyblock ); - - return rc; -} - - -void -get_seckey_end( GETKEY_CTX ctx ) -{ - get_pubkey_end( ctx ); -} - - -/**************** - * 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 -get_seckey_byfprint( PKT_secret_key *sk, - const byte *fprint, size_t fprint_len) -{ - int rc; - - if( fprint_len == 20 || fprint_len == 16 ) { - struct getkey_ctx_s ctx; - KBNODE kb = NULL; - - 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 - rc = G10ERR_GENERAL; /* Oops */ - return rc; -} - - -/************************************************ - ************* Merging stuff ******************** - ************************************************/ - -/**************** - * merge all selfsignatures with the keys. - * FIXME: replace this at least for the public key parts - * 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 ) -{ - PKT_public_key *pk = NULL; - PKT_secret_key *sk = NULL; - PKT_signature *sig; - KBNODE k; - 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 ) { - pk = k->pkt->pkt.public_key; sk = NULL; - if( pk->version < 4 ) - pk = NULL; /* not needed for old keys */ - else if( k->pkt->pkttype == PKT_PUBLIC_KEY ) - keyid_from_pk( pk, kid ); - else if( !pk->expiredate ) { /* and subkey */ - /* insert the expiration date here */ - /*FIXME!!! pk->expiredate = subkeys_expiretime( k, kid );*/ - } - sigdate = 0; - } - else if( k->pkt->pkttype == PKT_SECRET_KEY - || k->pkt->pkttype == PKT_SECRET_SUBKEY ) { - pk = NULL; sk = k->pkt->pkt.secret_key; - if( sk->version < 4 ) - sk = NULL; - else if( k->pkt->pkttype == PKT_SECRET_KEY ) - keyid_from_sk( sk, kid ); - sigdate = 0; - } - else if( (pk || sk ) && k->pkt->pkttype == PKT_SIGNATURE - && (sig=k->pkt->pkt.signature)->sig_class >= 0x10 - && sig->sig_class <= 0x30 && sig->version > 3 - && !(sig->sig_class == 0x18 || sig->sig_class == 0x28) - && sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1] ) { - /* okay this is a self-signature which can be used. - * This is not used for subkey binding signature, becuase this - * is done above. - * FIXME: We should only use this if the signature is valid - * but this is time consuming - we must provide another - * way to handle this - */ - const byte *p; - u32 ed; - - 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 ) { - pk->expiredate = ed; - sigdate = sig->timestamp; - } - } - else { - ed = p? sk->timestamp + buffer_to_u32(p):0; - if( sig->timestamp > sigdate ) { - sk->expiredate = ed; - sigdate = sig->timestamp; - } - } - } - - 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, u32 keycreated ) -{ - PKT_user_id *uid = uidnode->pkt->pkt.user_id; - PKT_signature *sig = signode->pkt->pkt.signature; - const byte *p, *sym, *hash, *zip; - size_t n, nsym, nhash, nzip; - - uid->created = 0; /* not created == invalid */ - 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; - - /* store the key flags in the helper variable for later processing */ - uid->help_key_usage = 0; - 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 |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - 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, 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 our keyblock */ - uid->is_primary = 0; - 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 - * the hased area and then later try to decide which is the better - * 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 -merge_selfsigs_main( KBNODE keyblock, int *r_revoked ) -{ - PKT_public_key *pk = NULL; - KBNODE k; - u32 kid[2]; - u32 sigdate = 0, uiddate=0, uiddate2; - 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; - 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 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_USER_ID; k = k->next ) { - if ( k->pkt->pkttype == PKT_SIGNATURE ) { - PKT_signature *sig = k->pkt->pkt.signature; - 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_KEY_REV (sig) ){ - /* key has been revoked - there is no way to override - * 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; - } - 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. - */ - PKT_signature *sig = signode->pkt->pkt.signature; - const byte *p; - size_t n; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n ); - if ( p && n ) { - /* first octet of the keyflags */ - if ( (*p & 3) ) - key_usage |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - key_usage |= PUBKEY_USAGE_ENC; - } - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); - if ( p ) { - key_expire = keytimestamp + buffer_to_u32(p); - key_expire_seen = 1; - } - - /* 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])) - { - /* Failure here means the sig did not verify, is was - not issued by a revocation key, or a revocation - key loop was broken. */ - - if(check_revocation_keys(pk,sig)==0) - *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 ) { - if ( uidnode && signode ) - fixup_uidnode ( uidnode, signode, keytimestamp ); - uidnode = k; - signode = NULL; - if ( sigdate > uiddate ) - uiddate = sigdate; - sigdate = 0; - } - 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] ) { - if ( check_key_signature( keyblock, k, NULL ) ) - ; /* signature did not verify */ - 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). - */ - 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 && signode ) { - fixup_uidnode ( uidnode, signode, keytimestamp ); - pk->is_valid = 1; - } - - /* 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)); - - /* We don't want to use the full get_pubkey to - avoid infinite recursion in certain cases. - There is no reason to check that an ultimately - trusted key is still valid - if it has been - revoked or the user should also renmove the - ultimate trust flag. */ - if(get_pubkey_direct(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. - */ - - if ( !key_usage ) { - /* find the latest user ID with key flags set */ - 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 ) { - PKT_user_id *uid = k->pkt->pkt.user_id; - if ( uid->help_key_usage && uid->created > uiddate ) { - key_usage = uid->help_key_usage; - uiddate = uid->created; - } - } - } - } - if ( !key_usage ) { /* no key flags at all: get it from the algo */ - key_usage = openpgp_pk_algo_usage ( pk->pubkey_algo ); - } - else { /* check that the usage matches the usage as given by the algo */ - int x = openpgp_pk_algo_usage ( pk->pubkey_algo ); - if ( x ) /* mask it down to the actual allowed usage */ - key_usage &= x; - } - 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 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 ) { - PKT_user_id *uid = k->pkt->pkt.user_id; - if ( uid->help_key_expire && uid->created > uiddate ) { - key_expire = uid->help_key_expire; - uiddate = uid->created; - } - } - } - } - - /* 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->pkt.user_id->attrib_data) { - PKT_user_id *uid = k->pkt->pkt.user_id; - if ( uid->is_primary && uid->created > uiddate ) { - uiddate = uid->created; - uidnode = k; - } - if ( !uid->is_primary && uid->created > uiddate2 ) { - uiddate2 = uid->created; - uidnode2 = k; - } - } - } - if ( uidnode ) { - 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) { - PKT_user_id *uid = k->pkt->pkt.user_id; - if ( k != uidnode ) - uid->is_primary = 0; - } - } - } - else if( uidnode2 ) { - /* 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; - } - } - } -} - - -static void -merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) -{ - PKT_public_key *mainpk = NULL, *subpk = NULL; - PKT_signature *sig; - KBNODE k; - u32 mainkid[2]; - u32 sigdate = 0; - KBNODE signode; - u32 curtime = make_timestamp (); - unsigned int key_usage = 0; - u32 keytimestamp = 0; - u32 key_expire = 0; - const byte *p; - size_t n; - - if ( subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY ) - BUG (); - mainpk = keyblock->pkt->pkt.public_key; - if ( mainpk->version < 4 ) - 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]; - - /* find the latest key binding self-signature. */ - signode = NULL; - sigdate = 0; /* helper to find the latest signature */ - for(k=subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; - k = k->next ) { - if ( k->pkt->pkttype == PKT_SIGNATURE ) { - sig = k->pkt->pkt.signature; - if ( sig->keyid[0] == mainkid[0] && sig->keyid[1]==mainkid[1] ) { - if ( check_key_signature( keyblock, k, NULL ) ) - ; /* signature did not verify */ - else if ( IS_SUBKEY_REV (sig) ) { - /* Note that this means that the date on a - revocation sig does not matter - even if the - binding sig is dated after the revocation sig, - the subkey is still marked as revoked. This - seems ok, as it is just as easy to make new - subkeys rather than re-sign old ones as the - problem is in the distribution. Plus, PGP (7) - does this the same way. */ - subpk->is_revoked = 1; - /* 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 ) { - if(sig->flags.expired) - ; /* signature has expired - ignore it */ - else { - sigdate = sig->timestamp; - signode = k; - } - } - } - } - } - - if ( !signode ) { - return; /* no valid key binding */ - } - - subpk->is_valid = 1; - sig = signode->pkt->pkt.signature; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n ); - if ( p && n ) { - /* first octet of the keyflags */ - if ( (*p & 3) ) - key_usage |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - 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 ); - } - else { /* check that the usage matches the usage as given by the algo */ - int x = openpgp_pk_algo_usage ( subpk->pubkey_algo ); - if ( x ) /* mask it down to the actual allowed usage */ - key_usage &= x; - } - subpk->pubkey_usage = key_usage; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); - if ( 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; -} - - - -/* - * Merge information from the self-signatures with the key, so that - * we can later use them more easy. - * The function works by first applying the self signatures to the - * primary key and the to each subkey. - * Here are the rules we use to decide which inormation from which - * self-signature is used: - * We check all self signatures or validity and ignore all invalid signatures. - * All signatures are then ordered by their creation date .... - * For the primary key: - * FIXME the docs - */ -static void -merge_selfsigs( KBNODE keyblock ) -{ - KBNODE k; - int revoked; - PKT_public_key *main_pk; - 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; - if ( revoked ) { - /* if the primary key has been revoked we better set the revoke - * flag on that key and all subkeys */ - 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; - pk->is_revoked = 1; - pk->main_keyid[0] = main_pk->main_keyid[0]; - pk->main_keyid[1] = main_pk->main_keyid[1]; - } - } - return; - } - - /* now merge in the data from each of the subkeys */ - for(k=keyblock; k; k = k->next ) { - if ( k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - 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; - } - } -} - - -/* - * Merge the secret keys from secblock into the pubblock thereby - * replacing the public (sub)keys with their secret counterparts Hmmm: - * It might be better to get away from the concept of entire secret - * keys at all and have a way to store just the real secret parts - * from the key. - */ -static void -merge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) -{ - KBNODE pub; - - assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY ); - assert ( secblock->pkt->pkttype == PKT_SECRET_KEY ); - - for (pub=pubblock; pub; pub = pub->next ) { - if ( pub->pkt->pkttype == PKT_PUBLIC_KEY ) { - PKT_public_key *pk = pub->pkt->pkt.public_key; - PKT_secret_key *sk = secblock->pkt->pkt.secret_key; - assert ( pub == pubblock ); /* only in the first node */ - /* there is nothing to compare in this case, so just replace - * some information */ - copy_public_parts_to_secret_key ( pk, sk ); - free_public_key ( pk ); - pub->pkt->pkttype = PKT_SECRET_KEY; - pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk); - } - else if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - KBNODE sec; - PKT_public_key *pk = pub->pkt->pkt.public_key; - - /* this is more complicated: it may happen that the sequence - * of the subkeys dosn't match, so we have to find the - * appropriate secret key */ - 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 ) ) { - copy_public_parts_to_secret_key ( pk, sk ); - free_public_key ( pk ); - pub->pkt->pkttype = PKT_SECRET_SUBKEY; - pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk); - break; - } - } - } - if ( !sec ) - BUG(); /* already checked in premerge */ - } - } -} - -/* This function checks that for every public subkey a corresponding - * 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. - */ -static void -premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) -{ - KBNODE last, pub; - - assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY ); - 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; - - 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 ( 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_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 */ - for (next=pub->next,ll=pub; - next && pub->pkt->pkttype != PKT_PUBLIC_SUBKEY; - ll = next, next = next->next ) - ; - /* make new link */ - last->next = next; - /* release this public subkey with all sigs */ - ll->next = NULL; - release_kbnode( pub ); - /* let the loop continue */ - pub = last; - } - } - } - /* 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); -} - - - - -/* See see whether the key fits - * our requirements and in case we do not - * 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: 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. - * 2. No usage but primary key requested - * This is the case for all functions which work on an - * entire keyblock, e.g. for editing or listing - * 3. Usage and primary key requested - * FXME - * 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 keyblock = ctx->keyblock; - KBNODE k; - 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( 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 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; - /* 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 ) { - PKT_public_key *pk; - nextk = k->next; - if ( k->pkt->pkttype != PKT_PUBLIC_SUBKEY ) - continue; - 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"); - continue; - } - if ( pk->is_revoked ) { - if (DBG_CACHE) - log_debug( "\tsubkey has been revoked\n"); - continue; - } - if ( pk->has_expired ) { - if (DBG_CACHE) - 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 ( !((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 ); - continue; - } - - if (DBG_CACHE) - log_debug( "\tsubkey looks fine\n"); - if ( pk->timestamp > latest_date ) { - latest_date = pk->timestamp; - latest_key = k; - } - } - } - - /* 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 && !req_prim ) - log_debug( "\tno suitable subkeys found - trying primary\n"); - pk = keyblock->pkt->pkt.public_key; - if ( !pk->is_valid ) { - if (DBG_CACHE) - log_debug( "\tprimary key not valid\n"); - } - else if ( pk->is_revoked ) { - if (DBG_CACHE) - log_debug( "\tprimary key has been revoked\n"); - } - else if ( pk->has_expired ) { - if (DBG_CACHE) - log_debug( "\tprimary key has expired\n"); - } - else if ( !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) { - if (DBG_CACHE) - 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->timestamp; - } - } - - if ( !latest_key ) { - if (DBG_CACHE) - log_debug("\tno suitable key found - giving up\n"); - 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 && 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), - (ulong)keyid_from_pk( keyblock->pkt->pkt.public_key, NULL) ); - } - - cache_user_id( keyblock ); - - return 1; /* found */ -} - - -static int -lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode ) -{ - int rc; - KBNODE secblock = NULL; /* helper */ - 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 ); - } - - /* 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 ) { - merge_public_with_secret ( ctx->keyblock, - secblock); - release_kbnode (secblock); - secblock = NULL; - } - 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("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 ? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY; - - if ( secmode ) { - release_kbnode( secblock ); - secblock = NULL; - } - release_kbnode( ctx->keyblock ); - ctx->keyblock = NULL; - - ctx->last_rc = rc; - return rc; -} - - - - -/**************** - * FIXME: Replace by the generic function - * It does not work as it is right now - it is used at - * 2 places: a) to get the key for an anonyous recipient - * b) to get the ultimately trusted keys. - * The a) usage might have some problems. - * - * Enumerate all primary secret keys. Caller must use these procedure: - * 1) create a void pointer and initialize it to NULL - * 2) pass this void pointer by reference to this function - * and provide space for the secret key (pass a buffer for sk) - * 3) call this function as long as it does not return -1 - * 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; - struct { - int eof; - int first; - KEYDB_HANDLE hd; - KBNODE keyblock; - KBNODE node; - } *c = *context; - - - if( !c ) { /* make a new context */ - c = m_alloc_clear( sizeof *c ); - *context = c; - c->hd = keydb_new (1); - c->first = 1; - c->keyblock = NULL; - c->node = NULL; - } - - if( !sk ) { /* free the context */ - keydb_release (c->hd); - release_kbnode (c->keyblock); - m_free( c ); - *context = NULL; - return 0; - } - - if( c->eof ) - return -1; - - 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); - - return rc; /* error */ -} - - - -/********************************************* - *********** user ID printing helpers ******* - *********************************************/ - -/**************** - * Return a string with a printable representation of the user_id. - * this string must be freed by m_free. - */ -char* -get_user_id_string( u32 *keyid ) -{ - user_id_db_t r; - char *p; - int pass=0; - /* try it two times; second pass reads from key resources */ - do { - for(r=user_id_db; r; r = r->next ) { - keyid_list_t a; - for (a=r->keyids; a; a= a->next ) { - if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) { - p = m_alloc( r->len + 10 ); - sprintf(p, "%08lX %.*s", - (ulong)keyid[1], r->len, r->name ); - return p; - } - } - } - } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = m_alloc( 15 ); - sprintf(p, "%08lX [?]", (ulong)keyid[1] ); - return p; -} - - -char* -get_user_id_string_printable ( u32 *keyid ) -{ - char *p = get_user_id_string( keyid ); - char *p2 = utf8_to_native( p, strlen(p), 0 ); - m_free(p); - p = make_printable_string (p2, strlen (p2), 0); - m_free (p2); - return p; -} - - -char* -get_long_user_id_string( u32 *keyid ) -{ - user_id_db_t r; - char *p; - int pass=0; - /* try it two times; second pass reads from key resources */ - do { - for(r=user_id_db; r; r = r->next ) { - keyid_list_t a; - for (a=r->keyids; a; a= a->next ) { - if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) { - p = m_alloc( r->len + 20 ); - sprintf(p, "%08lX%08lX %.*s", - (ulong)keyid[0], (ulong)keyid[1], - r->len, r->name ); - return p; - } - } - } - } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = m_alloc( 25 ); - sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] ); - return p; -} - -char* -get_user_id( u32 *keyid, size_t *rn ) -{ - user_id_db_t r; - char *p; - int pass=0; - - /* try it two times; second pass reads from key resources */ - do { - for(r=user_id_db; r; r = r->next ) { - keyid_list_t a; - for (a=r->keyids; a; a= a->next ) { - if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) { - p = m_alloc( r->len ); - memcpy(p, r->name, r->len ); - *rn = r->len; - return p; - } - } - } - } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = m_strdup( _("[User id not found]") ); - *rn = strlen(p); - return p; -} - -char* -get_user_id_printable( u32 *keyid ) -{ - size_t rn; - char *p = get_user_id( keyid, &rn ); - char *p2 = utf8_to_native( p, rn, 0 ); - m_free(p); - p = make_printable_string (p2, strlen (p2), 0); - m_free (p2); - return p; -} - -KEYDB_HANDLE -get_ctx_handle(GETKEY_CTX ctx) -{ - return ctx->kr_handle; -} diff --git a/g10/gpgv.c b/g10/gpgv.c deleted file mode 100644 index dcb2a9d94..000000000 --- a/g10/gpgv.c +++ /dev/null @@ -1,374 +0,0 @@ -/* 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(); - - set_native_charset (NULL); /* Try to auto set the character set */ - - 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/import.c b/g10/import.c deleted file mode 100644 index 1fa22d174..000000000 --- a/g10/import.c +++ /dev/null @@ -1,1796 +0,0 @@ -/* import.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "trustdb.h" -#include "main.h" -#include "i18n.h" -#include "ttyio.h" -#include "status.h" -#include "keyserver-internal.h" - -struct stats_s { - ulong count; - ulong no_user_id; - ulong imported; - ulong imported_rsa; - ulong n_uids; - ulong n_sigs; - ulong n_subk; - ulong unchanged; - ulong n_revoc; - ulong secret_read; - ulong secret_imported; - ulong secret_dups; - ulong skipped_new_keys; - ulong not_imported; -}; - - -static int import( IOBUF inp, const char* fname, - struct stats_s *stats, unsigned int options ); -static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ); -static void revocation_present(KBNODE keyblock); -static void remove_bad_stuff (KBNODE keyblock); -static int import_one( const char *fname, KBNODE keyblock, - struct stats_s *stats, unsigned int options); -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 int delete_inv_parts( const char *fname, KBNODE keyblock, - u32 *keyid, unsigned int options ); -static int merge_blocks( const char *fname, KBNODE keyblock_orig, - KBNODE keyblock, u32 *keyid, - int *n_uids, int *n_sigs, int *n_subk ); -static int append_uid( KBNODE keyblock, KBNODE node, int *n_sigs, - const char *fname, u32 *keyid ); -static int append_key( KBNODE keyblock, KBNODE node, int *n_sigs, - const char *fname, u32 *keyid ); -static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, - const char *fname, u32 *keyid ); -static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs, - const char *fname, u32 *keyid ); - - -int -parse_import_options(char *str,unsigned int *options) -{ - char *tok; - int hit=0; - struct - { - char *name; - unsigned int bit; - } import_opts[]= - { - {"allow-local-sigs",IMPORT_ALLOW_LOCAL_SIGS}, - {"repair-hkp-subkey-bug",IMPORT_REPAIR_HKP_SUBKEY_BUG}, - {"fast-import",IMPORT_FAST_IMPORT}, - {NULL,0} - }; - - while((tok=strsep(&str," ,"))) - { - int i,rev=0; - - if(ascii_strncasecmp("no-",tok,3)==0) - { - rev=1; - tok+=3; - } - - for(i=0;import_opts[i].name;i++) - { - if(ascii_strcasecmp(import_opts[i].name,tok)==0) - { - if(rev) - *options&=~import_opts[i].bit; - else - *options|=import_opts[i].bit; - hit=1; - break; - } - } - - if(!hit && !import_opts[i].name) - return 0; - } - - return hit; -} - -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 - * least one userid. Only user ids which are self signed will be imported. - * Other signatures are not checked. - * - * Actually this function does a merge. It works like this: - * - * - get the keyblock - * - check self-signatures and remove all userids and their signatures - * without/invalid self-signatures. - * - reject the keyblock, if we have no valid userid. - * - See whether we have this key already in one of our pubrings. - * If not, simply add it to the default keyring. - * - Compare the key and the self-signatures of the new and the one in - * our keyring. If they are different something weird is going on; - * ask what to do. - * - See whether we have only non-self-signature on one user id; if not - * ask the user what to do. - * - compare the signatures: If we already have this signature, check - * that they compare okay; if not, issue a warning and ask the user. - * (consider looking at the timestamp and use the newest?) - * - Simply add the signature. Can't verify here because we may not have - * the signature's public key yet; verification is done when putting it - * into the trustdb, which is done automagically as soon as this pubkey - * is used. - * - Proceed with next signature. - * - * Key revocation certificates have special handling. - * - */ -static int -import_keys_internal( IOBUF inp, char **fnames, int nnames, - void *stats_handle, unsigned int options ) -{ - int i, rc = 0; - struct stats_s *stats = stats_handle; - - if (!stats) - stats = import_new_stats_handle (); - - if (inp) { - rc = import( inp, "[stream]", stats, options); - } - else { - if( !fnames && !nnames ) - nnames = 1; /* Ohh what a ugly hack to jump into the loop */ - - for(i=0; i < nnames; i++ ) { - const char *fname = fnames? fnames[i] : NULL; - IOBUF inp2 = iobuf_open(fname); - if( !fname ) - fname = "[stdin]"; - if( !inp2 ) - log_error(_("can't open `%s': %s\n"), fname, strerror(errno) ); - else { - rc = import( inp2, fname, stats, options ); - iobuf_close(inp2); - if( rc ) - log_error("import from `%s' failed: %s\n", fname, - g10_errstr(rc) ); - } - if( !fname ) - break; - } - } - if (!stats_handle) { - import_print_stats (stats); - import_release_stats_handle (stats); - } - /* If no fast import and we really added new keys or merged new - user ids, signatures or revocations, then update/check the - trustdb if the user specified by setting interactive or by - not setting no-auto-check-trustdb */ - if (!(options&IMPORT_FAST_IMPORT) && - (stats->imported || stats->n_uids || - stats->n_sigs || stats->n_revoc)) { - if (opt.interactive) - update_trustdb(); - else if (!opt.no_auto_check_trustdb) - check_trustdb(); - } - return rc; -} - -void -import_keys( char **fnames, int nnames, - void *stats_handle, unsigned int options ) -{ - import_keys_internal( NULL, fnames, nnames, stats_handle, options); -} - -int -import_keys_stream( IOBUF inp, void *stats_handle, unsigned int options ) -{ - return import_keys_internal( inp, NULL, 0, stats_handle, options); -} - -static int -import( IOBUF inp, const char* fname, - struct stats_s *stats, unsigned int options ) -{ - PACKET *pending_pkt = NULL; - KBNODE keyblock; - int rc = 0; - - getkey_disable_caches(); - - if( !opt.no_armor ) { /* armored reading is not disabled */ - 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, stats, options ); - 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, stats ); - else { - log_info( _("skipping block of type %d\n"), - keyblock->pkt->pkttype ); - } - release_kbnode(keyblock); - /* fixme: we should increment the not imported counter but this - does only make sense if we keep on going despite of errors. */ - if( rc ) - break; - if( !(++stats->count % 100) && !opt.quiet ) - log_info(_("%lu keys processed so far\n"), stats->count ); - } - if( rc == -1 ) - rc = 0; - else if( rc && rc != G10ERR_INV_KEYRING ) - log_error( _("error reading `%s': %s\n"), fname, g10_errstr(rc)); - - return rc; -} - - -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(_(" 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 ); - 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->not_imported ) - log_info(_(" not imported: %lu\n"), stats->not_imported ); - } - - if( is_status_enabled() ) { - char buf[14*20]; - sprintf(buf, "%lu %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, - stats->not_imported ); - write_status_text( STATUS_IMPORT_RES, buf ); - } -} - - -/**************** - * Read the next keyblock from stream A. - * PENDING_PKT should be initialzed to NULL - * and not chnaged form the caller. - * Retunr: 0 = okay, -1 no more blocks or another errorcode. - */ -static int -read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) -{ - int rc; - PACKET *pkt; - KBNODE root = NULL; - int in_cert; - - if( *pending_pkt ) { - root = new_kbnode( *pending_pkt ); - *pending_pkt = NULL; - in_cert = 1; - } - else - in_cert = 0; - pkt = m_alloc( sizeof *pkt ); - init_packet(pkt); - while( (rc=parse_packet(a, pkt)) != -1 ) { - if( rc ) { /* ignore errors */ - 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 ); - init_packet(pkt); - continue; - } - - if( !root && pkt->pkttype == PKT_SIGNATURE - && pkt->pkt.signature->sig_class == 0x20 ) { - /* this is a revocation certificate which is handled - * in a special way */ - root = new_kbnode( pkt ); - pkt = NULL; - goto ready; - } - - /* make a linked list of all packets */ - switch( pkt->pkttype ) { - case PKT_COMPRESSED: - if( pkt->pkt.compressed->algorithm < 1 - || pkt->pkt.compressed->algorithm > 2 ) { - rc = G10ERR_COMPR_ALGO; - goto ready; - } - { - 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 ); - } - free_packet( pkt ); - 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: - if( in_cert ) { /* store this packet */ - *pending_pkt = pkt; - pkt = NULL; - goto ready; - } - in_cert = 1; - default: - if( in_cert ) { - if( !root ) - root = new_kbnode( pkt ); - else - add_kbnode( root, new_kbnode( pkt ) ); - pkt = m_alloc( 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 ); - 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); - } - } -} - -/* Walk through the subkeys on a pk to find if we have the HKP - disease: multiple subkeys with their binding sigs stripped, and the - sig for the first subkey placed after the last subkey. That is, - instead of "pk uid sig sub1 bind1 sub2 bind2 sub3 bind3" we have - "pk uid sig sub1 sub2 sub3 bind1". We can't do anything about sub2 - and sub3, as they are already lost, but we can try and rescue sub1 - by reordering the keyblock so that it reads "pk uid sig sub1 bind1 - sub2 sub3". Returns TRUE if the keyblock was modified. */ - -static int -fix_hkp_corruption(KBNODE keyblock) -{ - int changed=0,keycount=0; - KBNODE node,last=NULL,sknode=NULL; - - /* First determine if we have the problem at all. Look for 2 or - more subkeys in a row, followed by a single binding sig. */ - for(node=keyblock;node;last=node,node=node->next) - { - if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY) - { - keycount++; - if(!sknode) - sknode=node; - } - else if(node->pkt->pkttype==PKT_SIGNATURE && - node->pkt->pkt.signature->sig_class==0x18 && - keycount>=2 && node->next==NULL) - { - /* We might have the problem, as this key has two subkeys in - a row without any intervening packets. */ - - /* Sanity check */ - if(last==NULL) - break; - - /* Temporarily attach node to sknode. */ - node->next=sknode->next; - sknode->next=node; - last->next=NULL; - - if(check_key_signature(keyblock,node,NULL)) - { - /* Not a match, so undo the changes. */ - sknode->next=node->next; - last->next=node; - node->next=NULL; - break; - } - else - { - sknode->flag |= 1; /* Mark it good so we don't need to - check it again */ - changed=1; - break; - } - } - else - keycount=0; - } - - return changed; -} - - -static void -print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason) -{ - byte array[MAX_FINGERPRINT_LEN], *s; - char buf[MAX_FINGERPRINT_LEN*2+30], *p; - size_t i, n; - - sprintf (buf, "%u ", reason); - p = buf + strlen (buf); - - if (pk) - fingerprint_from_pk (pk, array, &n); - else - fingerprint_from_sk (sk, array, &n); - s = array; - for (i=0; i < n ; i++, s++, p += 2) - sprintf (p, "%02X", *s); - - write_status_text (STATUS_IMPORT_OK, buf); -} - - -/**************** - * 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 g10. - */ -static int -import_one( const char *fname, KBNODE keyblock, - struct stats_s *stats, unsigned int options ) -{ - PKT_public_key *pk; - PKT_public_key *pk_orig; - KBNODE node, uidnode; - KBNODE keyblock_orig = NULL; - u32 keyid[2]; - int rc = 0; - int new_key = 0; - int mod_key = 0; - - /* get the key and print some info about it */ - node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); - if( !node ) - BUG(); - - pk = node->pkt->pkt.public_key; - keyid_from_pk( pk, keyid ); - uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); - - if( opt.verbose ) { - log_info( "pub %4u%c/%08lX %s ", - nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), - (ulong)keyid[1], datestr_from_pk(pk) ); - if( uidnode ) - print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name, - uidnode->pkt->pkt.user_id->len ); - putc('\n', stderr); - } - if( !uidnode ) { - log_error( _("key %08lX: no user ID\n"), (ulong)keyid[1]); - return 0; - } - - if (opt.interactive) { - tty_printf ("\n"); - show_basic_key_info (keyblock); - tty_printf ("\n"); - if (!cpr_get_answer_is_yes ("import.okay", - "Do you want to import this key? (y/N) ")) - return 0; - } - - clear_kbnode_flags( keyblock ); - - if((options&IMPORT_REPAIR_HKP_SUBKEY_BUG) && fix_hkp_corruption(keyblock)) - log_info(_("key %08lX: HKP subkey corruption repaired\n"), - (ulong)keyid[1]); - - rc = chk_self_sigs( fname, keyblock , pk, keyid ); - if( rc ) - return rc== -1? 0:rc; - - /* If we allow such a thing, mark unsigned uids as valid */ - if( opt.allow_non_selfsigned_uid ) - 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, options ) ) { - if( !opt.quiet ) { - log_info( _("key %08lX: no valid user IDs\n"), - (ulong)keyid[1]); - log_info(_("this may be caused by a missing self-signature\n")); - } - stats->no_user_id++; - return 0; - } - - /* do we have this key already in one of our pubrings ? */ - pk_orig = m_alloc_clear( sizeof *pk_orig ); - rc = get_pubkey( pk_orig, keyid ); - if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY ) { - log_error( _("key %08lX: public key not found: %s\n"), - (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; - stats->skipped_new_keys++; - } - else if( rc ) { /* insert this key */ - 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"), keydb_get_resource_name (hd) ); - 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 - { - /* This should not be possible since we delete the - ownertrust when a key is deleted, but it can happen if - the keyring and trustdb are out of sync. It can also - be made to happen with the trusted-key command. */ - - clear_ownertrust (pk); - revalidation_mark (); - } - keydb_release (hd); - - /* we are ready */ - if( !opt.quiet ) { - char *p=get_user_id_printable (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 ); - m_free(us); - print_import_ok (pk,NULL, 1); - } - stats->imported++; - if( is_RSA( pk->pubkey_algo ) ) - 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 - * weird is going on */ - if( cmp_public_keys( pk_orig, pk ) ) { - log_error( _("key %08lX: doesn't match our copy\n"), - (ulong)keyid[1]); - goto leave; - } - - /* now read the original keyblock */ - 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], 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; - } - - collapse_uids( &keyblock ); - /* and try to merge the block */ - clear_kbnode_flags( keyblock_orig ); - clear_kbnode_flags( keyblock ); - n_uids = n_sigs = n_subk = 0; - rc = merge_blocks( fname, keyblock_orig, keyblock, - keyid, &n_uids, &n_sigs, &n_subk ); - if( rc ) { - keydb_release (hd); - goto leave; - } - if( n_uids || n_sigs || n_subk ) { - mod_key = 1; - /* keyblock_orig has been updated; write */ - 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_printable(keyid); - if( n_uids == 1 ) - log_info( _("key %08lX: \"%s\" 1 new user ID\n"), - (ulong)keyid[1], p); - else if( 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: \"%s\" 1 new signature\n"), - (ulong)keyid[1], p); - else if( 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: \"%s\" 1 new subkey\n"), - (ulong)keyid[1], p); - else if( 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; - - if (is_status_enabled ()) - print_import_ok (pk, NULL, - ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); - } - else { - if (is_status_enabled ()) - print_import_ok (pk, NULL, 0); - - if( !opt.quiet ) { - char *p=get_user_id_printable(keyid); - log_info( _("key %08lX: \"%s\" not changed\n"), - (ulong)keyid[1],p); - m_free(p); - } - stats->unchanged++; - } - 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, - struct stats_s *stats) -{ - PKT_secret_key *sk; - KBNODE node, uidnode; - u32 keyid[2]; - int rc = 0; - - /* get the key and print some info about it */ - node = find_kbnode( keyblock, PKT_SECRET_KEY ); - if( !node ) - BUG(); - - sk = node->pkt->pkt.secret_key; - keyid_from_sk( sk, keyid ); - uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); - - if( opt.verbose ) { - log_info( "sec %4u%c/%08lX %s ", - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid[1], datestr_from_sk(sk) ); - if( uidnode ) - print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name, - uidnode->pkt->pkt.user_id->len ); - putc('\n', stderr); - } - stats->secret_read++; - - if( !uidnode ) { - log_error( _("key %08lX: no user ID\n"), (ulong)keyid[1]); - return 0; - } - - if(sk->protect.algo>110) - { - log_error(_("key %08lX: secret key with invalid cipher %d " - "- skipped\n"),(ulong)keyid[1],sk->protect.algo); - return 0; - } - - clear_kbnode_flags( keyblock ); - - /* do we have this key already in one of our secrings ? */ - rc = seckey_available( keyid ); - 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++; - if (is_status_enabled ()) - print_import_ok (NULL, sk, 1|16); - } - else if( !rc ) { /* we can't merge secret keys */ - log_error( _("key %08lX: already in secret keyring\n"), - (ulong)keyid[1]); - stats->secret_dups++; - if (is_status_enabled ()) - print_import_ok (NULL, sk, 16); - } - else - log_error( _("key %08lX: secret key not found: %s\n"), - (ulong)keyid[1], g10_errstr(rc)); - - return rc; -} - - -/**************** - * Import a revocation certificate; this is a single signature packet. - */ -static int -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; - - assert( !node->next ); - assert( node->pkt->pkttype == PKT_SIGNATURE ); - assert( node->pkt->pkt.signature->sig_class == 0x20 ); - - keyid[0] = node->pkt->pkt.signature->keyid[0]; - keyid[1] = node->pkt->pkt.signature->keyid[1]; - - pk = m_alloc_clear( sizeof *pk ); - rc = get_pubkey( pk, keyid ); - if( rc == G10ERR_NO_PUBKEY ) { - log_info( _("key %08lX: no public key - " - "can't apply revocation certificate\n"), (ulong)keyid[1]); - rc = 0; - goto leave; - } - else if( rc ) { - log_error( _("key %08lX: public key not found: %s\n"), - (ulong)keyid[1], g10_errstr(rc)); - goto leave; - } - - /* read the original keyblock */ - 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; - } - - - /* it is okay, that node is not in keyblock because - * check_key_signature works fine for sig_class 0x20 in this - * special case. */ - rc = check_key_signature( keyblock, node, NULL); - if( rc ) { - log_error( _("key %08lX: invalid revocation certificate" - ": %s - rejected\n"), (ulong)keyid[1], g10_errstr(rc)); - goto leave; - } - - - /* check whether we already have this */ - for(onode=keyblock->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 == 0x20 - && keyid[0] == onode->pkt->pkt.signature->keyid[0] - && keyid[1] == onode->pkt->pkt.signature->keyid[1] ) { - rc = 0; - goto leave; /* yes, we already know about it */ - } - } - - - /* insert it */ - insert_kbnode( keyblock, clone_kbnode(node), 0 ); - - /* and write the keyblock back */ - 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 ) { - char *p=get_user_id_printable (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; -} - - -/**************** - * loop over the keyblock and check all self signatures. - * Mark all user-ids with a self-signature by setting flag bit 0. - * Mark all user-ids with an invalid self-signature by setting bit 1. - * This works also for subkeys, here the subkey is marked. Invalid or - * extra subkey sigs (binding or revocation) are marked for deletion. - */ -static int -chk_self_sigs( const char *fname, KBNODE keyblock, - PKT_public_key *pk, u32 *keyid ) -{ - KBNODE n,knode=NULL; - PKT_signature *sig; - int rc; - u32 bsdate=0,rsdate=0; - KBNODE bsnode=NULL,rsnode=NULL; - - for( n=keyblock; (n = find_next_kbnode(n, 0)); ) { - if(n->pkt->pkttype==PKT_PUBLIC_SUBKEY) - { - knode=n; - bsdate=0; - rsdate=0; - bsnode=NULL; - rsnode=NULL; - } - else if( n->pkt->pkttype != PKT_SIGNATURE ) - continue; - sig = n->pkt->pkt.signature; - if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) { - if( (sig->sig_class&~3) == 0x10 ) { - KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID ); - if( !unode ) { - log_error( _("key %08lX: no user ID for signature\n"), - (ulong)keyid[1]); - return -1; /* the complete keyblock is 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 */ - } - } - else if( sig->sig_class == 0x18 ) { - /* Note that this works based solely on the timestamps - like the rest of gpg. If the standard gets - revocation targets, this may need to be revised. */ - - if( !knode ) { - log_info( _("key %08lX: no subkey for subkey " - "binding signature\n"),(ulong)keyid[1]); - n->flag |= 4; /* delete this */ - } - else { - rc = check_key_signature( keyblock, n, NULL); - if( rc ) { - log_info( rc == G10ERR_PUBKEY_ALGO ? - _("key %08lX: unsupported public key algorithm\n"): - _("key %08lX: invalid subkey binding\n"), - (ulong)keyid[1]); - n->flag|=4; - } - else { - /* It's valid, so is it newer? */ - if(sig->timestamp>=bsdate) { - knode->flag |= 1; /* the subkey is valid */ - if(bsnode) { - bsnode->flag|=4; /* Delete the last binding - sig since this one is - newer */ - log_info(_("key %08lX: removed multiple subkey " - "binding\n"),(ulong)keyid[1]); - } - - bsnode=n; - bsdate=sig->timestamp; - } - else - n->flag|=4; /* older */ - } - } - } - else if( sig->sig_class == 0x28 ) { - /* We don't actually mark the subkey as revoked right - now, so just check that the revocation sig is the - most recent valid one. Note that we don't care if - the binding sig is newer than the revocation sig. - See the comment in getkey.c:merge_selfsigs_subkey for - more */ - if( !knode ) { - log_info( _("key %08lX: no subkey for subkey " - "revocation signature\n"),(ulong)keyid[1]); - n->flag |= 4; /* delete this */ - } - else { - rc = check_key_signature( keyblock, n, NULL); - if( rc ) { - log_info( rc == G10ERR_PUBKEY_ALGO ? - _("key %08lX: unsupported public key algorithm\n"): - _("key %08lX: invalid subkey revocation\n"), - (ulong)keyid[1]); - n->flag|=4; - } - else { - /* It's valid, so is it newer? */ - if(sig->timestamp>=rsdate) { - if(rsnode) { - rsnode->flag|=4; /* Delete the last revocation - sig since this one is - newer */ - log_info(_("key %08lX: removed multiple subkey " - "revocation signatures\n"),(ulong)keyid[1]); - } - - rsnode=n; - rsdate=sig->timestamp; - } - else - n->flag|=4; /* older */ - } - } - } - } - } - - return 0; -} - -/**************** - * delete all parts which are invalid and those signatures whose - * public key algorithm is not available in this implemenation; - * but consider RSA as valid, because parse/build_packets knows - * about it. - * returns: true if at least one valid user-id is left over. - */ -static int -delete_inv_parts( const char *fname, KBNODE keyblock, - u32 *keyid, unsigned int options) -{ - KBNODE node; - int nvalid=0, uid_seen=0, subkey_seen=0; - - for(node=keyblock->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - uid_seen = 1; - if( (node->flag & 2) || !(node->flag & 1) ) { - if( opt.verbose ) { - log_info( _("key %08lX: skipped user ID '"), - (ulong)keyid[1]); - print_utf8_string( stderr, node->pkt->pkt.user_id->name, - node->pkt->pkt.user_id->len ); - fputs("'\n", stderr ); - } - delete_kbnode( node ); /* the user-id */ - /* and all following packets up to the next user-id */ - while( node->next - && node->next->pkt->pkttype != PKT_USER_ID - && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY - && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ){ - delete_kbnode( node->next ); - node = node->next; - } - } - else - nvalid++; - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - if( (node->flag & 2) || !(node->flag & 1) ) { - if( opt.verbose ) { - log_info( _("key %08lX: skipped subkey\n"), - (ulong)keyid[1]); - } - delete_kbnode( node ); /* the subkey */ - /* and all following signature packets */ - while( node->next - && node->next->pkt->pkttype == PKT_SIGNATURE ) { - delete_kbnode( node->next ); - node = node->next; - } - } - else - subkey_seen = 1; - } - else if( node->pkt->pkttype == PKT_SIGNATURE - && 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 && - !node->pkt->pkt.signature->flags.exportable && - !(options&IMPORT_ALLOW_LOCAL_SIGS) && - 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 - * seems that this makes sense */ - log_info( _("key %08lX: non exportable signature " - "(class %02x) - skipped\n"), - (ulong)keyid[1], - node->pkt->pkt.signature->sig_class ); - delete_kbnode( node ); - } - else if( node->pkt->pkttype == PKT_SIGNATURE - && node->pkt->pkt.signature->sig_class == 0x20 ) { - if( uid_seen ) { - log_error( _("key %08lX: revocation certificate " - "at wrong place - skipped\n"), - (ulong)keyid[1]); - delete_kbnode( node ); - } - else { - /* 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 ); - } - } - } - } - else if( node->pkt->pkttype == PKT_SIGNATURE && - (node->pkt->pkt.signature->sig_class == 0x18 || - node->pkt->pkt.signature->sig_class == 0x28) && - !subkey_seen ) { - log_error( _("key %08lX: subkey signature " - "in wrong place - skipped\n"), - (ulong)keyid[1]); - delete_kbnode( node ); - } - else if( (node->flag & 4) ) /* marked for deletion */ - delete_kbnode( node ); - } - - /* note: because keyblock is the public key, it is never marked - * for deletion and so keyblock cannot change */ - commit_kbnode( &keyblock ); - return nvalid; -} - - -/**************** - * It may happen that the imported keyblock has duplicated user IDs. - * We check this here and collapse those user IDs together with their - * sigs into one. - * Returns: True if the keyblock hash changed. - */ -int -collapse_uids( KBNODE *keyblock ) -{ - KBNODE n, n2; - int in_uid; - int any=0; - u32 kid1; - - restart: - for( n = *keyblock; n; n = n->next ) { - if( n->pkt->pkttype != PKT_USER_ID ) - continue; - for( n2 = n->next; n2; n2 = n2->next ) { - if( n2->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids( n->pkt->pkt.user_id, - n2->pkt->pkt.user_id ) ) { - /* found a duplicate */ - any = 1; - if( !n2->next - || n2->next->pkt->pkttype == PKT_USER_ID - || n2->next->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n2->next->pkt->pkttype == PKT_SECRET_SUBKEY ) { - /* no more signatures: delete the user ID - * and start over */ - remove_kbnode( keyblock, n2 ); - } - else { - /* The simple approach: Move one signature and - * then start over to delete the next one :-( */ - move_kbnode( keyblock, n2->next, n->next ); - } - goto restart; - } - } - } - if( !any ) - return 0; - - restart_sig: - /* now we may have duplicate signatures on one user ID: fix this */ - for( in_uid = 0, n = *keyblock; n; n = n->next ) { - if( n->pkt->pkttype == PKT_USER_ID ) - in_uid = 1; - else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n->pkt->pkttype == PKT_SECRET_SUBKEY ) - in_uid = 0; - else if( in_uid ) { - n2 = n; - do { - KBNODE ncmp = NULL; - for( ; n2; n2 = n2->next ) { - if( n2->pkt->pkttype == PKT_USER_ID - || n2->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n2->pkt->pkttype == PKT_SECRET_SUBKEY ) - break; - if( n2->pkt->pkttype != PKT_SIGNATURE ) - ; - else if( !ncmp ) - ncmp = n2; - else if( !cmp_signatures( ncmp->pkt->pkt.signature, - n2->pkt->pkt.signature )) { - remove_kbnode( keyblock, n2 ); - goto restart_sig; - } - } - n2 = ncmp? ncmp->next : NULL; - } while( n2 ); - } - } - - if( (n = find_kbnode( *keyblock, PKT_PUBLIC_KEY )) ) - kid1 = keyid_from_pk( n->pkt->pkt.public_key, NULL ); - else if( (n = find_kbnode( *keyblock, PKT_SECRET_KEY )) ) - kid1 = keyid_from_sk( n->pkt->pkt.secret_key, NULL ); - else - kid1 = 0; - log_info(_("key %08lX: duplicated user ID detected - merged\n"), - (ulong)kid1); - - 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 - * - * o compare the signatures: If we already have this signature, check - * that they compare okay; if not, issue a warning and ask the user. - * o Simply add the signature. Can't verify here because we may not have - * the signature's public key yet; verification is done when putting it - * into the trustdb, which is done automagically as soon as this pubkey - * is used. - * Note: We indicate newly inserted packets with flag bit 0 - */ -static int -merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock, - u32 *keyid, int *n_uids, int *n_sigs, int *n_subk ) -{ - KBNODE onode, node; - int rc, found; - - /* 1st: handle revocation certificates */ - 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 == 0x20 ) { - /* 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 == 0x20 - && node->pkt->pkt.signature->keyid[0] - == onode->pkt->pkt.signature->keyid[0] - && node->pkt->pkt.signature->keyid[1] - == onode->pkt->pkt.signature->keyid[1] ) { - found = 1; - break; - } - } - if( !found ) { - char *p=get_user_id_printable (keyid); - KBNODE n2 = clone_kbnode(node); - insert_kbnode( keyblock_orig, n2, 0 ); - n2->flag |= 1; - ++*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]); - } - } - } - - /* 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 */ - for(node=keyblock->next; node; node=node->next ) - if( node->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids( onode->pkt->pkt.user_id, - node->pkt->pkt.user_id ) ) - break; - if( node ) { /* found: merge */ - rc = merge_sigs( onode, node, n_sigs, fname, keyid ); - if( rc ) - return rc; - } - } - } - - /* 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 */ - for(onode=keyblock_orig->next; onode; onode=onode->next ) - if( onode->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids( onode->pkt->pkt.user_id, - node->pkt->pkt.user_id ) ) - break; - if( !onode ) { /* this is a new user id: append */ - rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid); - if( rc ) - return rc; - ++*n_uids; - } - } - } - - /* 5th: add new subkeys */ - for(node=keyblock->next; node; node=node->next ) { - onode = NULL; - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - /* do we have this in the original keyblock? */ - for(onode=keyblock_orig->next; onode; onode=onode->next ) - if( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY - && !cmp_public_keys( onode->pkt->pkt.public_key, - node->pkt->pkt.public_key ) ) - break; - if( !onode ) { /* this is a new subkey: append */ - rc = append_key( keyblock_orig, node, n_sigs, fname, keyid); - if( rc ) - return rc; - ++*n_subk; - } - } - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - /* do we have this in the original keyblock? */ - for(onode=keyblock_orig->next; onode; onode=onode->next ) - if( onode->pkt->pkttype == PKT_SECRET_SUBKEY - && !cmp_secret_keys( onode->pkt->pkt.secret_key, - node->pkt->pkt.secret_key ) ) - break; - if( !onode ) { /* this is a new subkey: append */ - rc = append_key( keyblock_orig, node, n_sigs, fname, keyid); - if( rc ) - return rc; - ++*n_subk; - } - } - } - - /* 6th: merge subkey certificates */ - for(onode=keyblock_orig->next; onode; onode=onode->next ) { - if( !(onode->flag & 1) - && ( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY - || onode->pkt->pkttype == PKT_SECRET_SUBKEY) ) { - /* find the subkey in the imported keyblock */ - for(node=keyblock->next; node; node=node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - && !cmp_public_keys( onode->pkt->pkt.public_key, - node->pkt->pkt.public_key ) ) - break; - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY - && !cmp_secret_keys( onode->pkt->pkt.secret_key, - node->pkt->pkt.secret_key ) ) - break; - } - if( node ) { /* found: merge */ - rc = merge_keysigs( onode, node, n_sigs, fname, keyid ); - if( rc ) - return rc; - } - } - } - - - return 0; -} - - -/**************** - * append the userid starting with NODE and all signatures to KEYBLOCK. - */ -static int -append_uid( KBNODE keyblock, KBNODE node, int *n_sigs, - const char *fname, u32 *keyid ) -{ - KBNODE n, n_where=NULL; - - assert(node->pkt->pkttype == PKT_USER_ID ); - - /* find the position */ - for( n = keyblock; n; n_where = n, n = n->next ) { - if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n->pkt->pkttype == PKT_SECRET_SUBKEY ) - break; - } - if( !n ) - n_where = NULL; - - /* and append/insert */ - while( node ) { - /* we add a clone to the original keyblock, because this - * one is released first */ - n = clone_kbnode(node); - if( n_where ) { - insert_kbnode( n_where, n, 0 ); - n_where = n; - } - else - add_kbnode( keyblock, n ); - n->flag |= 1; - node->flag |= 1; - if( n->pkt->pkttype == PKT_SIGNATURE ) - ++*n_sigs; - - node = node->next; - if( node && node->pkt->pkttype != PKT_SIGNATURE ) - break; - } - - return 0; -} - - -/**************** - * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID. - * (how should we handle comment packets here?) - */ -static int -merge_sigs( KBNODE dst, KBNODE src, int *n_sigs, - const char *fname, u32 *keyid ) -{ - KBNODE n, n2; - int found=0; - - assert(dst->pkt->pkttype == PKT_USER_ID ); - assert(src->pkt->pkttype == PKT_USER_ID ); - - for(n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next ) { - if( n->pkt->pkttype != PKT_SIGNATURE ) - continue; - if( n->pkt->pkt.signature->sig_class == 0x18 - || n->pkt->pkt.signature->sig_class == 0x28 ) - continue; /* skip signatures which are only valid on subkeys */ - found = 0; - for(n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next){ - if( n2->pkt->pkttype == PKT_SIGNATURE - && n->pkt->pkt.signature->keyid[0] - == n2->pkt->pkt.signature->keyid[0] - && n->pkt->pkt.signature->keyid[1] - == n2->pkt->pkt.signature->keyid[1] - && n->pkt->pkt.signature->timestamp - <= n2->pkt->pkt.signature->timestamp - && n->pkt->pkt.signature->sig_class - == n2->pkt->pkt.signature->sig_class ) { - found++; - break; - } - } - if( !found ) { - /* This signature is new or newer, append N to DST. - * We add a clone to the original keyblock, because this - * one is released first */ - n2 = clone_kbnode(n); - insert_kbnode( dst, n2, PKT_SIGNATURE ); - n2->flag |= 1; - n->flag |= 1; - ++*n_sigs; - } - } - - return 0; -} - -/**************** - * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY. - */ -static int -merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs, - const char *fname, u32 *keyid ) -{ - KBNODE n, n2; - int found=0; - - assert( dst->pkt->pkttype == PKT_PUBLIC_SUBKEY - || dst->pkt->pkttype == PKT_SECRET_SUBKEY ); - - for(n=src->next; n ; n = n->next ) { - if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n->pkt->pkttype == PKT_PUBLIC_KEY ) - break; - if( n->pkt->pkttype != PKT_SIGNATURE ) - continue; - found = 0; - for(n2=dst->next; n2; n2 = n2->next){ - if( n2->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n2->pkt->pkttype == PKT_PUBLIC_KEY ) - break; - if( n2->pkt->pkttype == PKT_SIGNATURE - && n->pkt->pkt.signature->keyid[0] - == n2->pkt->pkt.signature->keyid[0] - && n->pkt->pkt.signature->keyid[1] - == n2->pkt->pkt.signature->keyid[1] - && n->pkt->pkt.signature->timestamp - <= n2->pkt->pkt.signature->timestamp - && n->pkt->pkt.signature->sig_class - == n2->pkt->pkt.signature->sig_class ) { - found++; - break; - } - } - if( !found ) { - /* This signature is new or newer, append N to DST. - * We add a clone to the original keyblock, because this - * one is released first */ - n2 = clone_kbnode(n); - insert_kbnode( dst, n2, PKT_SIGNATURE ); - n2->flag |= 1; - n->flag |= 1; - ++*n_sigs; - } - } - - return 0; -} - -/**************** - * append the subkey starting with NODE and all signatures to KEYBLOCK. - * Mark all new and copied packets by setting flag bit 0. - */ -static int -append_key( KBNODE keyblock, KBNODE node, int *n_sigs, - const char *fname, u32 *keyid ) -{ - KBNODE n; - - assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ); - - while( node ) { - /* we add a clone to the original keyblock, because this - * one is released first */ - n = clone_kbnode(node); - add_kbnode( keyblock, n ); - n->flag |= 1; - node->flag |= 1; - if( n->pkt->pkttype == PKT_SIGNATURE ) - ++*n_sigs; - - node = node->next; - if( node && node->pkt->pkttype != PKT_SIGNATURE ) - break; - } - - return 0; -} diff --git a/g10/kbnode.c b/g10/kbnode.c deleted file mode 100644 index 06d28f844..000000000 --- a/g10/kbnode.c +++ /dev/null @@ -1,399 +0,0 @@ -/* kbnode.c - keyblock node utility functions - * Copyright (C) 1998, 1999, 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 <assert.h> -#include "util.h" -#include "memory.h" -#include "packet.h" -#include "keydb.h" - -#define USE_UNUSED_NODES 1 - -static KBNODE unused_nodes; - -static KBNODE -alloc_node(void) -{ - KBNODE n; - - n = unused_nodes; - if( n ) - unused_nodes = n->next; - else - n = m_alloc( sizeof *n ); - n->next = NULL; - n->pkt = NULL; - n->flag = 0; - n->private_flag=0; - n->recno = 0; - return n; -} - -static void -free_node( KBNODE n ) -{ - if( n ) { - #if USE_UNUSED_NODES - n->next = unused_nodes; - unused_nodes = n; - #else - m_free( n ); - #endif - } -} - - - -KBNODE -new_kbnode( PACKET *pkt ) -{ - KBNODE n = alloc_node(); - n->pkt = pkt; - return n; -} - - -KBNODE -clone_kbnode( KBNODE node ) -{ - KBNODE n = alloc_node(); - - n->pkt = node->pkt; - n->private_flag = node->private_flag | 2; /* mark cloned */ - return n; -} - - -void -release_kbnode( KBNODE n ) -{ - KBNODE n2; - - while( n ) { - n2 = n->next; - if( !is_cloned_kbnode(n) ) { - free_packet( n->pkt ); - m_free( n->pkt ); - } - free_node( n ); - n = n2; - } -} - - -/**************** - * Delete NODE. - * Note: This only works with walk_kbnode!! - */ -void -delete_kbnode( KBNODE node ) -{ - node->private_flag |= 1; -} - - - -/**************** - * Append NODE to ROOT. ROOT must exist! - */ -void -add_kbnode( KBNODE root, KBNODE node ) -{ - KBNODE n1; - - for(n1=root; n1->next; n1 = n1->next) - ; - n1->next = node; -} - -/**************** - * Insert NODE into the list after root but before a packet which is not of - * type PKTTYPE - * (only if PKTTYPE != 0) - */ -void -insert_kbnode( KBNODE root, KBNODE node, int pkttype ) -{ - if( !pkttype ) { - node->next = root->next; - root->next = node; - } - else { - KBNODE n1; - - for(n1=root; n1->next; n1 = n1->next) - if( pkttype != n1->next->pkt->pkttype ) { - node->next = n1->next; - n1->next = node; - return; - } - /* no such packet, append */ - node->next = NULL; - n1->next = node; - } -} - - -/**************** - * Find the previous node (if PKTTYPE = 0) or the previous node - * with pkttype PKTTYPE in the list starting with ROOT of NODE. - */ -KBNODE -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; - } - return n1; -} - -/**************** - * Ditto, but find the next packet. The behaviour is trivial if - * PKTTYPE is 0 but if it is specified, the next node with a packet - * of this type is returned. The function has some knowledge about - * the valid ordering of packets: e.g. if the next signature packet - * is requested, the function will not return one if it encounters - * a user-id. - */ -KBNODE -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 - && ( node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_SECRET_KEY ) ) - return NULL; - else if( pkttype == PKT_SIGNATURE - && ( node->pkt->pkttype == PKT_USER_ID - || node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_SECRET_KEY ) ) - return NULL; - else if( node->pkt->pkttype == pkttype ) - return node; - } - return NULL; -} - - -KBNODE -find_kbnode( KBNODE node, int pkttype ) -{ - for( ; node; node = node->next ) { - if( node->pkt->pkttype == pkttype ) - return node; - } - return NULL; -} - - - -/**************** - * Walk through a list of kbnodes. This function returns - * the next kbnode for each call; before using the function the first - * time, the caller must set CONTEXT to NULL (This has simply the effect - * to start with ROOT). - */ -KBNODE -walk_kbnode( KBNODE root, KBNODE *context, int all ) -{ - KBNODE n; - - do { - if( !*context ) { - *context = root; - n = root; - } - else { - n = (*context)->next; - *context = n; - } - } while( !all && n && is_deleted_kbnode(n) ); - - return n; -} - -void -clear_kbnode_flags( KBNODE n ) -{ - for( ; n; n = n->next ) { - n->flag = 0; - } -} - - -/**************** - * Commit changes made to the kblist at ROOT. Note that ROOT my change, - * and it is therefore passed by reference. - * The function has the effect of removing all nodes marked as deleted. - * returns true if any node has been changed - */ -int -commit_kbnode( KBNODE *root ) -{ - KBNODE n, nl; - int changed = 0; - - for( n = *root, nl=NULL; n; n = nl->next ) { - if( is_deleted_kbnode(n) ) { - if( n == *root ) - *root = nl = n->next; - else - nl->next = n->next; - if( !is_cloned_kbnode(n) ) { - free_packet( n->pkt ); - m_free( n->pkt ); - } - free_node( n ); - changed = 1; - } - else - nl = n; - } - return changed; -} - -void -remove_kbnode( KBNODE *root, KBNODE node ) -{ - KBNODE n, nl; - - for( n = *root, nl=NULL; n; n = nl->next ) { - if( n == node ) { - if( n == *root ) - *root = nl = n->next; - else - nl->next = n->next; - if( !is_cloned_kbnode(n) ) { - free_packet( n->pkt ); - m_free( n->pkt ); - } - free_node( n ); - } - else - nl = n; - } -} - - -/**************** - * Move NODE behind right after WHERE or to the beginning if WHERE is NULL. - */ -void -move_kbnode( KBNODE *root, KBNODE node, KBNODE where ) -{ - KBNODE tmp, prev; - - if( !root || !*root || !node ) - return; /* sanity check */ - for( prev = *root; prev && prev->next != node; prev = prev->next ) - ; - if( !prev ) - return; /* node is not in the list */ - - if( !where ) { /* move node before root */ - if( node == *root ) /* move to itself */ - return; - prev->next = node->next; - node->next = *root; - *root = node; - return; - } - /* move it after where */ - if( node == where ) - return; - tmp = node->next; - node->next = where->next; - where->next = node; - prev->next = tmp; -} - - - - -void -dump_kbnode( KBNODE node ) -{ - for(; node; node = node->next ) { - const char *s; - switch( node->pkt->pkttype ) { - case 0: s="empty"; break; - case PKT_PUBLIC_KEY: s="public-key"; break; - case PKT_SECRET_KEY: s="secret-key"; break; - case PKT_SECRET_SUBKEY: s= "secret-subkey"; break; - case PKT_PUBKEY_ENC: s="public-enc"; break; - case PKT_SIGNATURE: s="signature"; break; - case PKT_ONEPASS_SIG: s="onepass-sig"; break; - case PKT_USER_ID: s="user-id"; break; - case PKT_PUBLIC_SUBKEY: s="public-subkey"; break; - case PKT_COMMENT: s="comment"; break; - case PKT_RING_TRUST: s="trust"; break; - 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, 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 ts=%lu\n", - node->pkt->pkt.signature->sig_class, - (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 ) { - 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/keydb.c b/g10/keydb.c deleted file mode 100644 index d8dd83fe6..000000000 --- a/g10/keydb.c +++ /dev/null @@ -1,686 +0,0 @@ -/* 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); - - 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 */ - mode_t oldmask; - 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; - - oldmask=umask(077); - iobuf = iobuf_create (filename); - umask(oldmask); - if (!iobuf) - { - log_error ( _("error creating keyring `%s': %s\n"), - filename, strerror(errno)); - rc = G10ERR_OPEN_FILE; - goto leave; - } - - 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 deleted file mode 100644 index ea9e48e6d..000000000 --- a/g10/keydb.h +++ /dev/null @@ -1,265 +0,0 @@ -/* keydb.h - Key database - * Copyright (C) 1998, 1999, 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 - */ - -#ifndef G10_KEYDB_H -#define G10_KEYDB_H - -#include "types.h" -#include "global.h" -#include "packet.h" -#include "cipher.h" - -/* 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) -#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18) -#define IS_KEY_REV(s) ((s)->sig_class == 0x20) -#define IS_UID_REV(s) ((s)->sig_class == 0x30) -#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28) - - -struct getkey_ctx_s; -typedef struct getkey_ctx_s *GETKEY_CTX; - -/**************** - * A Keyblock is all packets which form an entire certificate; - * i.e. the public key, certificate, trust packets, user ids, - * signatures, and subkey. - * - * This structure is also used to bind arbitrary packets together. - */ - -struct kbnode_struct { - KBNODE next; - PACKET *pkt; - int flag; - int private_flag; - ulong recno; /* used while updating the trustdb */ -}; - -#define is_deleted_kbnode(a) ((a)->private_flag & 1) -#define is_cloned_kbnode(a) ((a)->private_flag & 2) - - -enum resource_type { - rt_UNKNOWN = 0, - rt_RING = 1 -}; - - -/**************** - * A data structre to hold information about the external position - * of a keyblock. - */ -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; - int mark; -}; - -/* 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 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 ); -int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, - int unlock, unsigned use ); - -/*-- passphrase.h --*/ -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, - 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, 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( 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 ); -void get_pubkey_end( GETKEY_CTX ctx ); -int get_seckey( PKT_secret_key *sk, u32 *keyid ); -int get_primary_seckey( PKT_secret_key *sk, u32 *keyid ); -int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, - size_t fprint_len ); -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( 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 enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys ); -void merge_keys_and_selfsig( KBNODE keyblock ); -char*get_user_id_string( u32 *keyid ); -char*get_user_id_string_printable( u32 *keyid ); -char*get_long_user_id_string( u32 *keyid ); -char*get_user_id( u32 *keyid, size_t *rn ); -char*get_user_id_printable( u32 *keyid ); -KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx); - -/*-- keyid.c --*/ -int pubkey_letter( int algo ); -u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid ); -u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid ); -u32 keyid_from_sig( PKT_signature *sig, u32 *keyid ); -u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ); -unsigned nbits_from_pk( PKT_public_key *pk ); -unsigned nbits_from_sk( PKT_secret_key *sk ); -const char *datestr_from_pk( PKT_public_key *pk ); -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 ); - -/*-- kbnode.c --*/ -KBNODE new_kbnode( PACKET *pkt ); -KBNODE clone_kbnode( KBNODE node ); -void release_kbnode( KBNODE n ); -void delete_kbnode( KBNODE node ); -void add_kbnode( KBNODE root, KBNODE node ); -void insert_kbnode( KBNODE root, KBNODE node, int pkttype ); -void move_kbnode( KBNODE *root, KBNODE node, KBNODE where ); -void remove_kbnode( KBNODE *root, KBNODE node ); -KBNODE find_prev_kbnode( KBNODE root, KBNODE node, int pkttype ); -KBNODE find_next_kbnode( KBNODE node, int pkttype ); -KBNODE find_kbnode( KBNODE node, int pkttype ); -KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all ); -void clear_kbnode_flags( KBNODE n ); -int commit_kbnode( KBNODE *root ); -void dump_kbnode( KBNODE node ); - -#endif /*G10_KEYDB_H*/ diff --git a/g10/keyedit.c b/g10/keyedit.c deleted file mode 100644 index 71d2858b7..000000000 --- a/g10/keyedit.c +++ /dev/null @@ -1,3281 +0,0 @@ -/* keyedit.c - keyedit stuff - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <ctype.h> - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "photoid.h" -#include "util.h" -#include "main.h" -#include "trustdb.h" -#include "filter.h" -#include "ttyio.h" -#include "status.h" -#include "i18n.h" - -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 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, int sensitive ); -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) - -#define NODFLG_BADSIG (1<<0) /* bad signature */ -#define NODFLG_NOKEY (1<<1) /* no public key */ -#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,non_revocable; - struct revocation_reason_info *reason; -}; - -/**************** - * Print information about a signature, check it and return true - * if the signature is okay. NODE must be a signature packet. - */ -static int -print_and_check_one_sig( KBNODE keyblock, KBNODE node, - int *inv_sigs, int *no_key, int *oth_err, - int *is_selfsig, int print_without_key ) -{ - PKT_signature *sig = node->pkt->pkt.signature; - int rc, sigrc; - int is_rev = sig->sig_class == 0x30; - - /* TODO: Make sure a cached sig record here still has the pk that - issued it. See also keylist.c:list_keyblock_print */ - - switch( (rc = check_key_signature( keyblock, node, is_selfsig)) ) { - case 0: - node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR); - sigrc = '!'; - break; - case G10ERR_BAD_SIGN: - node->flag = NODFLG_BADSIG; - sigrc = '-'; - if( inv_sigs ) - ++*inv_sigs; - break; - case G10ERR_NO_PUBKEY: - case G10ERR_UNU_PUBKEY: - node->flag = NODFLG_NOKEY; - sigrc = '?'; - if( no_key ) - ++*no_key; - break; - default: - node->flag = NODFLG_SIGERR; - sigrc = '%'; - if( oth_err ) - ++*oth_err; - break; - } - if( sigrc != '?' || print_without_key ) { - 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] ", g10_errstr(rc) ); - else if( sigrc == '?' ) - ; - else if( *is_selfsig ) { - tty_printf( is_rev? _("[revocation]") - : _("[self-signature]") ); - } - else { - size_t n; - char *p = get_user_id( sig->keyid, &n ); - tty_print_utf8_string2( p, n, 40 ); - 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 == '!'); -} - - - -/**************** - * Check the keysigs and set the flags to indicate errors. - * Returns true if error found. - */ -static int -check_all_keysigs( KBNODE keyblock, int only_selected ) -{ - KBNODE kbctx; - KBNODE node; - int inv_sigs = 0; - int no_key = 0; - int oth_err = 0; - int has_selfsig = 0; - int mis_selfsig = 0; - int selected = !only_selected; - int anyuid = 0; - - for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - PKT_user_id *uid = node->pkt->pkt.user_id; - - if( only_selected ) - selected = (node->flag & NODFLG_SELUID); - if( selected ) { - tty_printf("uid "); - tty_print_utf8_string( uid->name, uid->len ); - tty_printf("\n"); - if( anyuid && !has_selfsig ) - mis_selfsig++; - has_selfsig = 0; - anyuid = 1; - } - } - else if( selected && node->pkt->pkttype == PKT_SIGNATURE - && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10 - || node->pkt->pkt.signature->sig_class == 0x30 ) ) { - int selfsig; - - if( print_and_check_one_sig( keyblock, node, &inv_sigs, - &no_key, &oth_err, &selfsig, 0 ) ) { - if( selfsig ) - has_selfsig = 1; - } - /* Hmmm: should we update the trustdb here? */ - } - } - if( !has_selfsig ) - mis_selfsig++; - if( inv_sigs == 1 ) - tty_printf(_("1 bad signature\n") ); - else if( inv_sigs ) - tty_printf(_("%d bad signatures\n"), inv_sigs ); - if( no_key == 1 ) - tty_printf(_("1 signature not checked due to a missing key\n") ); - else if( no_key ) - tty_printf(_("%d signatures not checked due to missing keys\n"), no_key ); - if( oth_err == 1 ) - tty_printf(_("1 signature not checked due to an error\n") ); - else if( oth_err ) - tty_printf(_("%d signatures not checked due to errors\n"), oth_err ); - if( mis_selfsig == 1 ) - tty_printf(_("1 user ID without valid self-signature detected\n")); - else if( mis_selfsig ) - tty_printf(_("%d user IDs without valid self-signatures detected\n"), - mis_selfsig); - - return inv_sigs || no_key || oth_err || mis_selfsig; -} - - - - -static int -sign_mk_attrib( PKT_signature *sig, void *opaque ) -{ - struct sign_attrib *attrib = opaque; - byte buf[8]; - - if( attrib->non_exportable ) { - 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 ); - - return 0; -} - - - -/**************** - * Loop over all locusr and and sign the uids after asking. - * If no user id is marked, all user ids will be signed; - * if some user_ids are marked those will be signed. - */ -static int -sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, - int local , int nonrevocable ) -{ - int rc = 0; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - PKT_secret_key *sk = NULL; - KBNODE node, uidnode; - PKT_public_key *primary_pk=NULL; - int select_all = !count_selected_uids(keyblock); - 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 signators */ - for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { - 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 - * changes to the secret key, we would save the unprotected - * version */ - if( sk ) - free_secret_key(sk); - sk = copy_secret_key( NULL, sk_rover->sk ); - keyid_from_sk( sk, sk_keyid ); - /* set mark A for all selected user ids */ - for( node=keyblock; node; node = node->next ) { - if( select_all || (node->flag & NODFLG_SELUID) ) - node->flag |= NODFLG_MARK_A; - else - node->flag &= ~NODFLG_MARK_A; - } - /* reset mark for uids which are already signed */ - uidnode = NULL; - for( node=keyblock; node; node = node->next ) { - 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. */ - 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); - } - } - } - /* check whether any uids are left for signing */ - if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) { - tty_printf(_("Nothing to sign with key %08lX\n"), - (ulong)sk_keyid[1] ); - continue; - } - /* Ask whether we really should sign these user id(s) */ - tty_printf("\n"); - show_key_with_all_names( keyblock, 1, 0, 1, 0, 0 ); - tty_printf("\n"); - - 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 ); - 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; - - 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; - for( node=keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) - primary_pk = node->pkt->pkt.public_key; - else if( node->pkt->pkttype == PKT_USER_ID - && (node->flag & NODFLG_MARK_A) ) { - PACKET *pkt; - PKT_signature *sig; - struct sign_attrib attrib; - - assert( primary_pk ); - memset( &attrib, 0, sizeof attrib ); - attrib.non_exportable = local; - attrib.non_revocable = nonrevocable; - node->flag &= ~NODFLG_MARK_A; - - /* 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"), g10_errstr(rc)); - goto leave; - } - - *ret_modified = 1; /* we changed the keyblock */ - update_trust = 1; - - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE ); - goto reloop; - } - } - - /* 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 ); - if( sk ) - free_secret_key(sk); - return rc; -} - - - -/**************** - * Change the passphrase of the primary and all secondary keys. - * We use only one passphrase for all keys. - */ -static int -change_passphrase( KBNODE keyblock ) -{ - int rc = 0; - int changed=0; - KBNODE node; - PKT_secret_key *sk; - char *passphrase = NULL; - int no_primary_secrets = 0; - - node = find_kbnode( keyblock, PKT_SECRET_KEY ); - if( !node ) { - log_error("Oops; secret key not found anymore!\n"); - goto leave; - } - sk = node->pkt->pkt.secret_key; - - switch( is_secret_key_protected( sk ) ) { - case -1: - rc = G10ERR_PUBKEY_ALGO; - break; - case 0: - tty_printf(_("This key is not protected.\n")); - break; - default: - if( sk->protect.s2k.mode == 1001 ) { - tty_printf(_("Secret parts of primary key are not available.\n")); - no_primary_secrets = 1; - } - else { - tty_printf(_("Key is protected.\n")); - rc = check_secret_key( sk, 0 ); - if( !rc ) - passphrase = get_last_passphrase(); - } - break; - } - - /* unprotect all subkeys (use the supplied passphrase or ask)*/ - for(node=keyblock; !rc && node; node = node->next ) { - if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *subsk = node->pkt->pkt.secret_key; - set_next_passphrase( passphrase ); - rc = check_secret_key( subsk, 0 ); - if( !rc && !passphrase ) - passphrase = get_last_passphrase(); - } - } - - if( rc ) - tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc)); - else { - DEK *dek = NULL; - STRING2KEY *s2k = m_alloc_secure( sizeof *s2k ); - const char *errtext = NULL; - - tty_printf(_("Enter the new passphrase for this secret key.\n\n") ); - - set_next_passphrase( NULL ); - 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, errtext); - if( !dek ) { - errtext = _("passphrase not correctly repeated; try again"); - tty_printf ("%s.\n", errtext); - } - else if( !dek->keylen ) { - rc = 0; - tty_printf(_( "You don't want a passphrase -" - " this is probably a *bad* idea!\n\n")); - if( cpr_get_answer_is_yes("change_passwd.empty.okay", - _("Do you really want to do this? "))) - changed++; - break; - } - else { /* okay */ - rc = 0; - if( !no_primary_secrets ) { - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); - } - for(node=keyblock; !rc && node; node = node->next ) { - if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *subsk = node->pkt->pkt.secret_key; - subsk->protect.algo = dek->algo; - subsk->protect.s2k = *s2k; - rc = protect_secret_key( subsk, dek ); - } - } - if( rc ) - log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); - else - changed++; - break; - } - } - m_free(s2k); - m_free(dek); - } - - leave: - m_free( passphrase ); - set_next_passphrase( NULL ); - return changed && !rc; -} - - -/**************** - * There are some keys out (due to a bug in gnupg), where the sequence - * of the packets is wrong. This function fixes that. - * Returns: true if the keyblock has been fixed. - * - * Note: This function does not work if there is more than one user ID. - */ -static int -fix_keyblock( KBNODE keyblock ) -{ - KBNODE node, last, subkey; - int fixed=0; - - /* locate key signatures of class 0x10..0x13 behind sub key packets */ - for( subkey=last=NULL, node = keyblock; node; - last=node, node = node->next ) { - switch( node->pkt->pkttype ) { - case PKT_PUBLIC_SUBKEY: - case PKT_SECRET_SUBKEY: - if( !subkey ) - subkey = last; /* actually it is the one before the subkey */ - break; - case PKT_SIGNATURE: - if( subkey ) { - PKT_signature *sig = node->pkt->pkt.signature; - if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) { - log_info(_( - "moving a key signature to the correct place\n")); - last->next = node->next; - node->next = subkey->next; - subkey->next = node; - node = last; - fixed=1; - } - } - break; - default: break; - } - } - - return fixed; -} - -/**************** - * Menu driven key editor. If sign_mode is true semi-automatical signing - * will be performed. commands are ignore in this case - * - * Note: to keep track of some selection we use node->mark MARKBIT_xxxx. - */ - -void -keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, - int sign_mode ) -{ - enum cmdids { cmdNONE = 0, - cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, - 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; - int not_with_sk; - int signmode; - const char *desc; - } cmds[] = { - { N_("quit") , cmdQUIT , 0,0,1, N_("quit this menu") }, - { N_("q") , cmdQUIT , 0,0,1, NULL }, - { N_("save") , cmdSAVE , 0,0,1, N_("save and quit") }, - { N_("help") , cmdHELP , 0,0,1, N_("show this help") }, - { "?" , cmdHELP , 0,0,1, NULL }, - { N_("fpr") , cmdFPR , 0,0,1, N_("show fingerprint") }, - { N_("list") , cmdLIST , 0,0,1, N_("list key and user IDs") }, - { N_("l") , cmdLIST , 0,0,1, NULL }, - { N_("uid") , cmdSELUID , 0,0,1, N_("select user ID N") }, - { N_("key") , cmdSELKEY , 0,0,0, N_("select secondary key N") }, - { N_("check") , cmdCHECK , 0,0,1, N_("list signatures") }, - { N_("c") , cmdCHECK , 0,0,1, NULL }, - { 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 (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; - KEYDB_HANDLE kdbhd = NULL; - KBNODE sec_keyblock = NULL; - KEYDB_HANDLE sec_kdbhd = NULL; - KBNODE cur_keyblock; - char *answer = NULL; - int redisplay = 1; - int modified = 0; - int sec_modified = 0; - int toggle; - int have_commands = !!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": - sign_mode == 2?"lsign": - sign_mode == 3?"nrsign":"nrlsign"); - have_commands = 1; - } - - /* get the public key */ - rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd); - if( rc ) - goto leave; - if( fix_keyblock( keyblock ) ) - modified++; - if( collapse_uids( &keyblock ) ) - modified++; - - 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, 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, 1, 0, 1, 0 ); - tty_printf("\n"); - redisplay = 0; - } - do { - m_free(answer); - if( have_commands ) { - if( commands ) { - answer = m_strdup( commands->d ); - commands = commands->next; - } - else if( opt.batch ) { - answer = m_strdup("quit"); - } - else - have_commands = 0; - } - if( !have_commands ) { - 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 */ - photo = 0; /* This too */ - if( !*answer ) - cmd = cmdLIST; - else if( *answer == CONTROL_D ) - cmd = cmdQUIT; - else if( isdigit( *answer ) ) { - cmd = cmdSELUID; - arg_number = atoi(answer); - } - else { - if( (p=strchr(answer,' ')) ) { - *p++ = 0; - trim_spaces(answer); - trim_spaces(p); - arg_number = atoi(p); - arg_string = p; - } - - for(i=0; cmds[i].name; i++ ) { - if( !ascii_strcasecmp( answer, cmds[i].name ) ) - break; - } - if( sign_mode && !cmds[i].signmode ) - cmd = cmdINVCMD; - else if( cmds[i].need_sk && !sec_keyblock ) { - tty_printf(_("Need the secret key to do this.\n")); - cmd = cmdNOP; - } - else if( cmds[i].not_with_sk && sec_keyblock && toggle ) { - tty_printf(_("Please use the command \"toggle\" first.\n")); - cmd = cmdNOP; - } - else - cmd = cmds[i].id; - } - switch( cmd ) { - case cmdHELP: - for(i=0; cmds[i].name; i++ ) { - if( sign_mode && !cmds[i].signmode ) - ; - else if( cmds[i].need_sk && !sec_keyblock ) - ; /* skip if we do not have the secret key */ - else if( cmds[i].desc ) - tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) ); - } - break; - - case cmdLIST: - redisplay = 1; - break; - - case cmdFPR: - show_key_and_fingerprint( keyblock ); - break; - - case cmdSELUID: - if( menu_select_uid( cur_keyblock, arg_number ) ) - redisplay = 1; - break; - - case cmdSELKEY: - if( menu_select_key( cur_keyblock, arg_number ) ) - redisplay = 1; - break; - - case cmdCHECK: - /* we can only do this with the public key becuase the - * check functions can't cope with secret keys and it - * is questionable whether this would make sense at all */ - check_all_keysigs( keyblock, count_selected_uids(keyblock) ); - break; - - 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? ")) ) { - tty_printf(_("Hint: Select the user IDs to sign\n")); - break; - } - } - if( !sign_uids( keyblock, locusr, &modified, - (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN), - (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN)) - && sign_mode ) - goto do_cmd_save; - break; - - case cmdDEBUG: - dump_kbnode( cur_keyblock ); - break; - - case cmdTOGGLE: - toggle = !toggle; - cur_keyblock = toggle? sec_keyblock : keyblock; - 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, photo ) ) { - redisplay = 1; - sec_modified = modified = 1; - merge_keys_and_selfsig( sec_keyblock ); - merge_keys_and_selfsig( keyblock ); - } - break; - - case cmdDELUID: { - int n1; - - if( !(n1=count_selected_uids(keyblock)) ) - tty_printf(_("You must select at least one user ID.\n")); - 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", - n1 > 1? _("Really remove all selected user IDs? ") - : _("Really remove this user ID? ") - ) ) { - menu_deluid( keyblock, sec_keyblock ); - redisplay = 1; - modified = 1; - if( sec_keyblock ) - sec_modified = 1; - } - } - break; - - case cmdDELSIG: { - int n1; - - if( !(n1=count_selected_uids(keyblock)) ) - tty_printf(_("You must select at least one user ID.\n")); - else if( menu_delsig( keyblock ) ) { - /* no redisplay here, because it may scroll away some - * status output of delsig */ - modified = 1; - } - } - break; - - case cmdADDKEY: - if( generate_subkeypair( keyblock, sec_keyblock ) ) { - redisplay = 1; - sec_modified = modified = 1; - merge_keys_and_selfsig( sec_keyblock ); - merge_keys_and_selfsig( keyblock ); - } - break; - - - case cmdDELKEY: { - int n1; - - if( !(n1=count_selected_keys( keyblock )) ) - tty_printf(_("You must select at least one key.\n")); - else if( sec_keyblock && !cpr_get_answer_is_yes( - "keyedit.remove.subkey.okay", - n1 > 1? - _("Do you really want to delete the selected keys? "): - _("Do you really want to delete this key? ") - )) - ; - else { - menu_delkey( keyblock, sec_keyblock ); - redisplay = 1; - modified = 1; - if( sec_keyblock ) - sec_modified = 1; - } - } - break; - - case cmdADDREVOKER: - { - int sensitive=0; - - if(arg_string && ascii_strcasecmp(arg_string,"sensitive")==0) - sensitive=1; - if( menu_addrevoker( keyblock, sec_keyblock, sensitive ) ) { - redisplay = 1; - sec_modified = modified = 1; - merge_keys_and_selfsig( sec_keyblock ); - merge_keys_and_selfsig( keyblock ); - } - } - break; - - case cmdREVKEY: { - int n1; - - if( !(n1=count_selected_keys( keyblock )) ) - tty_printf(_("You must select at least one key.\n")); - else if( sec_keyblock && !cpr_get_answer_is_yes( - "keyedit.revoke.subkey.okay", - n1 > 1? - _("Do you really want to revoke the selected keys? "): - _("Do you really want to revoke this key? ") - )) - ; - else { - if( menu_revkey( keyblock, sec_keyblock ) ) { - modified = 1; - /*sec_modified = 1;*/ - } - redisplay = 1; - } - } - break; - - case cmdEXPIRE: - if( menu_expire( keyblock, sec_keyblock ) ) { - merge_keys_and_selfsig( sec_keyblock ); - merge_keys_and_selfsig( keyblock ); - sec_modified = 1; - modified = 1; - redisplay = 1; - } - 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, 0, 1, 0 ); - tty_printf("\n"); - if( edit_ownertrust( find_kbnode( keyblock, - PKT_PUBLIC_KEY )->pkt->pkt.public_key, 1 ) ) { - redisplay = 1; - /* 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, 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: - break; - - case cmdREVSIG: - if( menu_revsig( keyblock ) ) { - redisplay = 1; - modified = 1; - } - break; - - case cmdENABLEKEY: - case cmdDISABLEKEY: - if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) { - redisplay = 1; - modified = 1; - } - break; - - case cmdSHOWPHOTO: - menu_showphoto(keyblock); - break; - - case cmdQUIT: - if( have_commands ) - goto leave; - if( !modified && !sec_modified ) - goto leave; - if( !cpr_get_answer_is_yes("keyedit.save.okay", - _("Save changes? ")) ) { - if( cpr_enabled() - || cpr_get_answer_is_yes("keyedit.cancel.okay", - _("Quit without saving? ")) ) - goto leave; - break; - } - /* fall thru */ - case cmdSAVE: - do_cmd_save: - if( modified || sec_modified ) { - if( modified ) { - rc = keydb_update_keyblock (kdbhd, keyblock); - if( rc ) { - log_error(_("update failed: %s\n"), g10_errstr(rc) ); - break; - } - } - if( sec_modified ) { - rc = keydb_update_keyblock (sec_kdbhd, sec_keyblock ); - if( rc ) { - log_error( _("update secret failed: %s\n"), - g10_errstr(rc) ); - break; - } - } - } - else - tty_printf(_("Key not changed so no update needed.\n")); - - if( update_trust ) - { - revalidation_mark (); - update_trust=0; - } - goto leave; - - case cmdINVCMD: - default: - tty_printf("\n"); - tty_printf(_("Invalid command (try \"help\")\n")); - break; - } - } /* end main loop */ - - leave: - release_kbnode( keyblock ); - release_kbnode( sec_keyblock ); - keydb_release (kdbhd); - m_free(answer); -} - - -/**************** - * show preferences of a public keyblock. - */ -static void -show_prefs (PKT_user_id *uid, int verbose) -{ - const prefitem_t fake={0,0}; - const prefitem_t *prefs; - int i; - - 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 { - 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"); - } -} - - -/* 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%s:\n", pk->revkey[i].class, - (pk->revkey[i].class&0x40)?"s":""); - } - } - } - } - - /* 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 = '?'; - - ++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'); - } - } -} - - -/**************** - * Display the key a the user ids, if only_marked is true, do only - * 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, 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 ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY - || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) { - PKT_public_key *pk = node->pkt->pkt.public_key; - int otrust=0, trust=0; - - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { - /* do it here, so that debug messages don't clutter the - * output */ - 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)? '*':' ', - nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), - (ulong)keyid_from_pk(pk,NULL), - datestr_from_pk(pk), - expirestr_from_pk(pk) ); - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { - tty_printf(_(" trust: %c/%c"), otrust, trust ); - if( node->pkt->pkttype == PKT_PUBLIC_KEY - && (get_ownertrust (pk)&TRUST_FLAG_DISABLED)) { - tty_printf("\n*** "); - tty_printf(_("This key has been disabled")); - } - - if( with_fpr ) { - tty_printf("\n"); - print_fingerprint ( pk, NULL, 2 ); - } - } - tty_printf("\n"); - } - else if( node->pkt->pkttype == PKT_SECRET_KEY - || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) { - PKT_secret_key *sk = node->pkt->pkt.secret_key; - tty_printf(_("%s%c %4u%c/%08lX created: %s expires: %s"), - node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb", - (node->flag & NODFLG_SELKEY)? '*':' ', - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid_from_sk(sk,NULL), - datestr_from_sk(sk), - expirestr_from_sk(sk) ); - tty_printf("\n"); - } - else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE - && node->pkt->pkt.signature->sig_class == 0x28 ) { - PKT_signature *sig = node->pkt->pkt.signature; - - rc = check_key_signature( keyblock, node, NULL ); - if( !rc ) - tty_printf( _("rev! subkey has been revoked: %s\n"), - datestr_from_sig( sig ) ); - else if( rc == G10ERR_BAD_SIGN ) - tty_printf( _("rev- faked revocation found\n") ); - else if( rc ) - tty_printf( _("rev? problem checking revocation: %s\n"), - g10_errstr(rc) ); - } - } - /* 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; - ++i; - if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){ - if( 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 ) - { - 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 user ID.\n")); - } - } - } - } - - if (do_warn) - tty_printf (_("Please note that the shown key validity " - "is not necessarily correct\n" - "unless you restart the program.\n")); - -} - - -/* Display basic key information. This fucntion is suitable to show - information on the key without any dependencies on the trustdb or - any other internal GnuPG stuff. KEYBLOCK may either be a public or - a secret key.*/ -void -show_basic_key_info ( KBNODE keyblock ) -{ - KBNODE node; - int i; - - /* The primary key */ - for (node = keyblock; node; node = node->next) - { - if (node->pkt->pkttype == PKT_PUBLIC_KEY) - { - PKT_public_key *pk = node->pkt->pkt.public_key; - - /* Note, we use the same format string as in other show - functions to make the translation job easier. */ - tty_printf (_("%s%c %4u%c/%08lX created: %s expires: %s"), - node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub", - ' ', - nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), - (ulong)keyid_from_pk(pk,NULL), - datestr_from_pk(pk), - expirestr_from_pk(pk) ); - tty_printf("\n"); - print_fingerprint ( pk, NULL, 3 ); - tty_printf("\n"); - } - else if (node->pkt->pkttype == PKT_SECRET_KEY) - { - PKT_secret_key *sk = node->pkt->pkt.secret_key; - tty_printf(_("%s%c %4u%c/%08lX created: %s expires: %s"), - node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb", - ' ', - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid_from_sk(sk,NULL), - datestr_from_sk(sk), - expirestr_from_sk(sk) ); - tty_printf("\n"); - print_fingerprint (NULL, sk, 3 ); - tty_printf("\n"); - } - } - - /* The user IDs. */ - for (i=0, node = keyblock; node; node = node->next) - { - if (node->pkt->pkttype == PKT_USER_ID) - { - PKT_user_id *uid = node->pkt->pkt.user_id; - ++i; - - tty_printf (" "); - 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"); - } - } -} - -static void -show_key_and_fingerprint( KBNODE keyblock ) -{ - KBNODE node; - PKT_public_key *pk = NULL; - - for( node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { - pk = node->pkt->pkt.public_key; - tty_printf("pub %4u%c/%08lX %s ", - nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), - (ulong)keyid_from_pk(pk,NULL), - datestr_from_pk(pk) ); - } - else if( node->pkt->pkttype == PKT_USER_ID ) { - PKT_user_id *uid = node->pkt->pkt.user_id; - tty_print_utf8_string( uid->name, uid->len ); - break; - } - } - tty_printf("\n"); - if( pk ) - print_fingerprint( pk, NULL, 2 ); -} - - - -/**************** - * 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, int photo) -{ - PKT_user_id *uid; - PKT_public_key *pk=NULL; - PKT_secret_key *sk=NULL; - PKT_signature *sig=NULL; - PACKET *pkt; - KBNODE node; - KBNODE pub_where=NULL, sec_where=NULL; - int rc; - - for( node = pub_keyblock; node; pub_where = node, node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) - pk = node->pkt->pkt.public_key; - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; - } - if( !node ) /* no subkey */ - pub_where = NULL; - for( node = sec_keyblock; node; sec_where = node, node = node->next ) { - if( node->pkt->pkttype == PKT_SECRET_KEY ) - sk = copy_secret_key( NULL, node->pkt->pkt.secret_key); - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) - break; - } - if( !node ) /* no subkey */ - sec_where = NULL; - 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. Also, PGP may not expect a photo on a v3 key. - 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; - } - } - - 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", g10_errstr(rc) ); - free_user_id(uid); - return 0; - } - - /* insert/append to secret keyblock */ - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_USER_ID; - 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 = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = copy_signature(NULL, sig); - if( sec_where ) - insert_kbnode( node, new_kbnode(pkt), 0 ); - else - add_kbnode( sec_keyblock, new_kbnode(pkt) ); - /* insert/append to public keyblock */ - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_USER_ID; - pkt->pkt.user_id = uid; - node = new_kbnode(pkt); - if( pub_where ) - insert_kbnode( pub_where, node, 0 ); - else - add_kbnode( pub_keyblock, node ); - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = copy_signature(NULL, sig); - if( pub_where ) - insert_kbnode( node, new_kbnode(pkt), 0 ); - else - add_kbnode( pub_keyblock, new_kbnode(pkt) ); - return 1; -} - - -/**************** - * Remove all selceted userids from the keyrings - */ -static void -menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock ) -{ - KBNODE node; - int selected=0; - - for( node = pub_keyblock; node; node = node->next ) { - 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; - int s_selected = 0; - PKT_user_id *uid = node->pkt->pkt.user_id; - for( snode = sec_keyblock; snode; snode = snode->next ) { - if( snode->pkt->pkttype == PKT_USER_ID ) { - PKT_user_id *suid = snode->pkt->pkt.user_id; - - s_selected = - (uid->len == suid->len - && !memcmp( uid->name, suid->name, uid->len)); - if( s_selected ) - delete_kbnode( snode ); - } - else if( s_selected - && snode->pkt->pkttype == PKT_SIGNATURE ) - delete_kbnode( snode ); - else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) - s_selected = 0; - } - } - } - } - else if( selected && node->pkt->pkttype == PKT_SIGNATURE ) - delete_kbnode( node ); - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - selected = 0; - } - commit_kbnode( &pub_keyblock ); - if( sec_keyblock ) - commit_kbnode( &sec_keyblock ); -} - - -static int -menu_delsig( KBNODE pub_keyblock ) -{ - KBNODE node; - PKT_user_id *uid = NULL; - int changed=0; - - for( node = pub_keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - uid = (node->flag & NODFLG_SELUID)? node->pkt->pkt.user_id : NULL; - } - else if( uid && node->pkt->pkttype == PKT_SIGNATURE ) { - int okay, valid, selfsig, inv_sig, no_key, other_err; - - tty_printf("uid "); - tty_print_utf8_string( uid->name, uid->len ); - tty_printf("\n"); - - okay = inv_sig = no_key = other_err = 0; - valid = print_and_check_one_sig( pub_keyblock, node, - &inv_sig, &no_key, &other_err, - &selfsig, 1 ); - - 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", - _("Delete this invalid signature? (y/N/q)")); - else if( no_key ) - okay = cpr_get_answer_yes_no_quit( - "keyedit.delsig.unknown", - _("Delete this unknown signature? (y/N/q)")); - - if( okay == -1 ) - break; - if( okay && selfsig && !cpr_get_answer_is_yes( - "keyedit.delsig.selfsig", - _("Really delete this self-signature? (y/N)") )) - okay = 0; - if( okay ) { - delete_kbnode( node ); - changed++; - } - - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - uid = NULL; - } - - if( changed ) { - commit_kbnode( &pub_keyblock ); - tty_printf( changed == 1? _("Deleted %d signature.\n") - : _("Deleted %d signatures.\n"), changed ); - } - else - tty_printf( _("Nothing deleted.\n") ); - - return changed; -} - - -/**************** - * Remove some of the secondary keys - */ -static void -menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) -{ - KBNODE node; - int selected=0; - - for( node = pub_keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - selected = node->flag & NODFLG_SELKEY; - if( selected ) { - delete_kbnode( node ); - if( sec_keyblock ) { - KBNODE snode; - int s_selected = 0; - u32 ki[2]; - - keyid_from_pk( node->pkt->pkt.public_key, ki ); - for( snode = sec_keyblock; snode; snode = snode->next ) { - if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) { - u32 ki2[2]; - - keyid_from_sk( snode->pkt->pkt.secret_key, ki2 ); - s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]); - if( s_selected ) - delete_kbnode( snode ); - } - else if( s_selected - && snode->pkt->pkttype == PKT_SIGNATURE ) - delete_kbnode( snode ); - else - s_selected = 0; - } - } - } - } - else if( selected && node->pkt->pkttype == PKT_SIGNATURE ) - delete_kbnode( node ); - else - selected = 0; - } - 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, int sensitive ) -{ - 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; - - if(pk->numrevkeys==0 && pk->version==3) - { - /* It is legal but bad for compatibility to add a revoker to a - v3 key as it means that PGP2 will not be able to use that key - anymore. Also, PGP may not expect a revoker on a v3 key. - Don't bother to ask this if the key already has a revoker - - any damage has already been done at that point. -dms */ - if(opt.expert) - { - tty_printf(_("WARNING: This is a PGP 2.x-style key. " - "Adding a designated revoker may cause\n" - " some versions of PGP to reject this key.\n")); - - if(!cpr_get_answer_is_yes("keyedit.v3_revoker.okay", - _("Are you sure you still want " - "to add it? (y/N) "))) - return 0; - } - else - { - tty_printf(_("You may not add a designated revoker to " - "a PGP 2.x-style key.\n")); - return 0; - } - } - - 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; - } - - revkey.class=0x80; - if(sensitive) - revkey.class|=0x40; - revkey.algid=revoker_pk->pubkey_algo; - - 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(pk,NULL); - - /* Does this revkey already exist? */ - if(!pk->revkey && pk->numrevkeys) - BUG(); - else - { - int i; - - for(i=0;i<pk->numrevkeys;i++) - { - if(memcmp(&pk->revkey[i],&revkey, - sizeof(struct revocation_key))==0) - { - char buf[50]; - - log_error(_("this key has already been designated " - "as a revoker\n")); - - sprintf(buf,"%08lX%08lX", - (ulong)pk->keyid[0],(ulong)pk->keyid[1]); - write_status_text(STATUS_ALREADY_SIGNED,buf); - - break; - } - } - - if(i<pk->numrevkeys) - 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; - - free_public_key(revoker_pk); - revoker_pk=NULL; - break; - } - - /* The 1F signature must be at least v4 to carry the revocation key - subpacket. */ - rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 4, 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 ) -{ - int n1, signumber, rc; - u32 expiredate; - int mainkey=0; - PKT_secret_key *sk; /* copy of the main sk */ - PKT_public_key *main_pk, *sub_pk; - PKT_user_id *uid; - KBNODE node; - u32 keyid[2]; - - if( count_selected_keys( sec_keyblock ) ) { - tty_printf(_("Please remove selections from the secret keys.\n")); - return 0; - } - - n1 = count_selected_keys( pub_keyblock ); - if( n1 > 1 ) { - tty_printf(_("Please select at most one secondary key.\n")); - return 0; - } - else if( n1 ) - tty_printf(_("Changing expiration time for a secondary key.\n")); - else { - tty_printf(_("Changing expiration time for the primary key.\n")); - mainkey=1; - } - - expiredate = ask_expiredate(); - 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 = sub_pk = NULL; - uid = NULL; - signumber = 0; - for( node=pub_keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { - main_pk = node->pkt->pkt.public_key; - keyid_from_pk( main_pk, keyid ); - main_pk->expiredate = expiredate; - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - && (node->flag & NODFLG_SELKEY ) ) { - sub_pk = node->pkt->pkt.public_key; - sub_pk->expiredate = expiredate; - } - 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 ) ) { - 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) - || (!mainkey && sig->sig_class == 0x18) ) ) { - /* this is a selfsignature which is to be replaced */ - PKT_signature *newsig; - PACKET *newpkt; - KBNODE sn; - int signumber2 = 0; - - signumber++; - - if( (mainkey && main_pk->version < 4) - || (!mainkey && sub_pk->version < 4 ) ) { - log_info(_( - "You can't change the expiration date of a v3 key\n")); - free_secret_key( sk ); - return 0; - } - - /* find the corresponding secret self-signature */ - for( sn=sec_keyblock; sn; sn = sn->next ) { - if( sn->pkt->pkttype == PKT_SIGNATURE ) { - PKT_signature *b = sn->pkt->pkt.signature; - if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1] - && sig->sig_class == b->sig_class - && ++signumber2 == signumber ) - break; - } - } - if( !sn ) - log_info(_("No corresponding signature in secret ring\n")); - - /* create new self signature */ - if( mainkey ) - rc = make_keysig_packet( &newsig, main_pk, uid, NULL, - 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, 0, 0, 0, - keygen_add_key_expire, sub_pk ); - if( rc ) { - log_error("make_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; - if( sn ) { - newpkt = m_alloc_clear( sizeof *newpkt ); - newpkt->pkttype = PKT_SIGNATURE; - newpkt->pkt.signature = copy_signature( NULL, newsig ); - free_packet( sn->pkt ); - m_free( sn->pkt ); - sn->pkt = newpkt; - } - sub_pk = NULL; - } - } - } - - 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. - * Returns: True if the selection changed; - */ -static int -menu_select_uid( KBNODE keyblock, int idx ) -{ - KBNODE node; - int i; - - /* first check that the index is valid */ - if( idx ) { - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - if( ++i == idx ) - break; - } - } - if( !node ) { - tty_printf(_("No user ID with index %d\n"), idx ); - return 0; - } - } - else { /* reset all */ - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) - node->flag &= ~NODFLG_SELUID; - } - return 1; - } - /* and toggle the new index */ - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) { - if( ++i == idx ) { - if( (node->flag & NODFLG_SELUID) ) - node->flag &= ~NODFLG_SELUID; - else - node->flag |= NODFLG_SELUID; - } - } - } - - return 1; -} - -/**************** - * Select secondary keys - * Returns: True if the selection changed; - */ -static int -menu_select_key( KBNODE keyblock, int idx ) -{ - KBNODE node; - int i; - - /* first check that the index is valid */ - if( idx ) { - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - if( ++i == idx ) - break; - } - } - if( !node ) { - tty_printf(_("No secondary key with index %d\n"), idx ); - return 0; - } - } - else { /* reset all */ - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) - node->flag &= ~NODFLG_SELKEY; - } - return 1; - } - /* and set the new index */ - for( i=0, node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - if( ++i == idx ) { - if( (node->flag & NODFLG_SELKEY) ) - node->flag &= ~NODFLG_SELKEY; - else - node->flag |= NODFLG_SELKEY; - } - } - } - - return 1; -} - - -static int -count_uids_with_flag( KBNODE keyblock, unsigned flag ) -{ - KBNODE node; - int i=0; - - for( node = keyblock; node; node = node->next ) - if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) ) - i++; - return i; -} - -static int -count_keys_with_flag( KBNODE keyblock, unsigned flag ) -{ - KBNODE node; - int i=0; - - for( node = keyblock; node; node = node->next ) - if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - && (node->flag & flag) ) - i++; - return i; -} - -static int -count_uids( KBNODE keyblock ) -{ - KBNODE node; - int i=0; - - for( node = keyblock; node; node = node->next ) - if( node->pkt->pkttype == PKT_USER_ID ) - i++; - return i; -} - - -/**************** - * Returns true if there is at least one selected user id - */ -static int -count_selected_uids( KBNODE keyblock ) -{ - return count_uids_with_flag( keyblock, NODFLG_SELUID); -} - -static int -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. - */ -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 ); - - if( !unode ) { - log_error("Oops: no user ID for signature\n"); - return; - } - - tty_printf(_("user ID: \"")); - tty_print_utf8_string( unode->pkt->pkt.user_id->name, - unode->pkt->pkt.user_id->len ); - - 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; - } -} - -/**************** - * Display all user ids of the current public key together with signatures - * done by one of our keys. Then walk over all this sigs and ask the user - * whether he wants to revoke this signature. - * Return: True when the keyblock has changed. - */ -static int -menu_revsig( KBNODE keyblock ) -{ - PKT_signature *sig; - PKT_public_key *primary_pk; - KBNODE node; - int changed = 0; - int rc, any, skip=1, all=!count_selected_uids(keyblock); - struct revocation_reason_info *reason = NULL; - - /* FIXME: detect duplicates here */ - tty_printf(_("You have signed these user IDs:\n")); - for( node = keyblock; node; node = node->next ) { - node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); - if( node->pkt->pkttype == PKT_USER_ID ) { - if( node->flag&NODFLG_SELUID || all ) { - PKT_user_id *uid = node->pkt->pkt.user_id; - /* Hmmm: Should we show only UIDs with a signature? */ - tty_printf(" "); - tty_print_utf8_string( uid->name, uid->len ); - tty_printf("\n"); - skip=0; - } - else - skip=1; - } - else if( !skip && node->pkt->pkttype == PKT_SIGNATURE - && ((sig = node->pkt->pkt.signature), - !seckey_available(sig->keyid) ) ) { - if( (sig->sig_class&~3) == 0x10 ) { - 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"), - (ulong)sig->keyid[1], datestr_from_sig(sig) ); - } - } - } - - /* ask */ - for( node = keyblock; node; node = node->next ) { - if( !(node->flag & NODFLG_SELSIG) ) - continue; - ask_revoke_sig( keyblock, node ); - } - - /* present selected */ - any = 0; - for( node = keyblock; node; node = node->next ) { - if( !(node->flag & NODFLG_MARK_A) ) - continue; - if( !any ) { - any = 1; - tty_printf(_("You are about to revoke these signatures:\n")); - } - if( node->pkt->pkttype == PKT_USER_ID ) { - PKT_user_id *uid = node->pkt->pkt.user_id; - tty_printf(" "); - tty_print_utf8_string( uid->name, uid->len ); - tty_printf("\n"); - } - else if( node->pkt->pkttype == PKT_SIGNATURE ) { - sig = node->pkt->pkt.signature; - 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) ")) ) - return 0; /* forget it */ - - reason = ask_revocation_reason( 0, 1, 0 ); - if( !reason ) { /* user decided to cancel */ - return 0; - } - - /* now we can sign the user ids */ - reloop: /* (must use this, because we are modifing the list) */ - primary_pk = keyblock->pkt->pkt.public_key; - for( node=keyblock; node; node = node->next ) { - KBNODE unode; - PACKET *pkt; - struct sign_attrib attrib; - PKT_secret_key *sk; - - if( !(node->flag & NODFLG_MARK_A) - || node->pkt->pkttype != PKT_SIGNATURE ) - continue; - unode = find_prev_kbnode( keyblock, node, PKT_USER_ID ); - assert( unode ); /* we already checked this */ - - memset( &attrib, 0, sizeof attrib ); - attrib.reason = reason; - attrib.non_exportable=!node->pkt->pkt.signature->flags.exportable; - - node->flag &= ~NODFLG_MARK_A; - sk = m_alloc_secure_clear( sizeof *sk ); - if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) { - log_info(_("no secret key\n")); - continue; - } - rc = make_keysig_packet( &sig, primary_pk, - unode->pkt->pkt.user_id, - NULL, - sk, - 0x30, 0, 0, 0, 0, - sign_mk_attrib, - &attrib ); - free_secret_key(sk); - if( rc ) { - log_error(_("signing failed: %s\n"), g10_errstr(rc)); - release_revocation_reason_info( reason ); - return changed; - } - changed = 1; /* we changed the keyblock */ - update_trust = 1; - /* Are we revoking our own uid? */ - if(primary_pk->keyid[0]==sig->keyid[0] && - primary_pk->keyid[1]==sig->keyid[1]) - unode->pkt->pkt.user_id->is_revoked=1; - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - insert_kbnode( unode, new_kbnode(pkt), 0 ); - goto reloop; - } - - release_revocation_reason_info( reason ); - return changed; -} - -/**************** - * Revoke some of the secondary keys. - * Hmmm: Should we add a revocation to the secret keyring too? - * Does its all make sense to duplicate most of the information? - */ -static int -menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) -{ - PKT_public_key *mainpk; - KBNODE node; - int changed = 0; - int rc; - struct revocation_reason_info *reason = NULL; - - reason = ask_revocation_reason( 1, 0, 0 ); - if( !reason ) { /* user decided to cancel */ - return 0; - } - - - reloop: /* (better this way because we are modifing the keyring) */ - mainpk = pub_keyblock->pkt->pkt.public_key; - for( node = pub_keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - && (node->flag & NODFLG_SELKEY) ) { - PACKET *pkt; - PKT_signature *sig; - PKT_secret_key *sk; - PKT_public_key *subpk = node->pkt->pkt.public_key; - struct sign_attrib attrib; - - memset( &attrib, 0, sizeof attrib ); - attrib.reason = reason; - - 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, 0, 0, 0, - sign_mk_attrib, &attrib ); - free_secret_key(sk); - if( rc ) { - log_error(_("signing failed: %s\n"), g10_errstr(rc)); - release_revocation_reason_info( reason ); - return changed; - } - changed = 1; /* we changed the keyblock */ - - pkt = m_alloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - insert_kbnode( node, new_kbnode(pkt), 0 ); - goto reloop; - } - } - commit_kbnode( &pub_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 */ - - release_revocation_reason_info( reason ); - return changed; -} - - -static int -enable_disable_key( KBNODE keyblock, int disable ) -{ - PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY ) - ->pkt->pkt.public_key; - unsigned int trust, newtrust; - - trust = newtrust = get_ownertrust (pk); - newtrust &= ~TRUST_FLAG_DISABLED; - if( disable ) - newtrust |= TRUST_FLAG_DISABLED; - if( trust == newtrust ) - return 0; /* already in that state */ - 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 deleted file mode 100644 index 7582805fa..000000000 --- a/g10/keygen.c +++ /dev/null @@ -1,2429 +0,0 @@ -/* keygen.c - generate a key pair - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <assert.h> -#include "util.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 */ - pSUBKEYEXPIRE, /* in n seconds */ - pPASSPHRASE, - pPASSPHRASE_DEK, - pPASSPHRASE_S2K -}; - -struct para_data_s { - struct para_data_s *next; - int lnr; - enum para_name key; - union { - DEK *dek; - STRING2KEY *s2k; - u32 expire; - unsigned int usage; - struct revocation_key revkey; - char value[1]; - } u; -}; - -struct output_control_s { - int lnr; - int dryrun; - int use_files; - struct { - char *fname; - char *newfname; - IOBUF stream; - armor_filter_context_t afx; - } pub; - struct { - char *fname; - char *newfname; - IOBUF stream; - armor_filter_context_t afx; - } sec; -}; - - -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 ); - - -static void -write_uid( KBNODE root, const char *s ) -{ - PACKET *pkt = m_alloc_clear(sizeof *pkt ); - size_t n = strlen(s); - - pkt->pkttype = PKT_USER_ID; - 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 -keygen_add_key_expire( PKT_signature *sig, void *opaque ) -{ - PKT_public_key *pk = opaque; - byte buf[8]; - u32 u; - - if( pk->expiredate ) { - u = pk->expiredate > pk->timestamp? pk->expiredate - pk->timestamp - : pk->timestamp; - buf[0] = (u >> 24) & 0xff; - buf[1] = (u >> 16) & 0xff; - buf[2] = (u >> 8) & 0xff; - buf[3] = u & 0xff; - build_sig_subpkt( sig, SIGSUBPKT_KEY_EXPIRE, buf, 4 ); - } - - 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 ); - 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 - * who are known to sign everything without any - * validation - so a signed key should be send - * to the holder who in turn can put it on a keyserver - */ - build_sig_subpkt( sig, SIGSUBPKT_KS_FLAGS, buf, 1 ); - - 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_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; - PKT_user_id *uid; - int rc=0; - KBNODE node; - PKT_public_key *pk; - - if( opt.verbose ) - log_info(_("writing self signature\n")); - - /* get the uid packet from the list */ - node = find_kbnode( root, PKT_USER_ID ); - if( !node ) - BUG(); /* no user id packet in tree */ - uid = node->pkt->pkt.user_id; - /* 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; - 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, 0, 0, 0, - keygen_add_std_prefs, pk ); - 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_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")); - - /* 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); - - /* find the last subkey */ - subpk = NULL; - for(node=pub_root; node; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - subpk = node->pkt->pkt.public_key; - } - if( !subpk ) - BUG(); - - /* and make the signature */ - 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", 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 -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; - MPI skey[4]; - MPI *factors; - - assert( is_ELGAMAL(algo) ); - - if( nbits < 512 ) { - nbits = 1024; - log_info(_("keysize invalid; using %u bits\n"), nbits ); - } - - if( (nbits % 32) ) { - nbits = ((nbits + 31) / 32) * 32; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - rc = pubkey_generate( algo, nbits, skey, &factors ); - if( rc ) { - log_error("pubkey_generate failed: %s\n", g10_errstr(rc) ); - return rc; - } - - 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; - 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] ); - if( ret_sk ) /* not a subkey: return an unprotected version of the sk */ - *ret_sk = copy_secret_key( NULL, sk ); - - if( dek ) { - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); - if( rc ) { - log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - } - - 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 = 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 )); - for(i=0; factors[i]; i++ ) - add_kbnode( sec_root, - make_mpi_comment_node("#:ELG_factor:", factors[i] )); - - return 0; -} - - -/**************** - * Generate a DSA key - */ -static int -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; - MPI skey[5]; - MPI *factors; - - if( nbits > 1024 || nbits < 512 ) { - nbits = 1024; - log_info(_("keysize invalid; using %u bits\n"), nbits ); - } - - if( (nbits % 64) ) { - nbits = ((nbits + 63) / 64) * 64; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors ); - if( rc ) { - log_error("pubkey_generate failed: %s\n", g10_errstr(rc) ); - return rc; - } - - 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 = 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] ); - if( ret_sk ) /* not a subkey: return an unprotected version of the sk */ - *ret_sk = copy_secret_key( NULL, sk ); - - if( dek ) { - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); - if( rc ) { - log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - } - - 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 = 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 )); - 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; -} - - -/* - * 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 ) -{ - int rc; - PACKET *pkt; - PKT_secret_key *sk; - PKT_public_key *pk; - MPI skey[6]; - MPI *factors; - - assert( is_RSA(algo) ); - - if( nbits < 1024 ) { - nbits = 1024; - log_info(_("keysize invalid; using %u bits\n"), nbits ); - } - - if( (nbits % 32) ) { - nbits = ((nbits + 31) / 32) * 32; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - rc = pubkey_generate( algo, nbits, skey, &factors ); - if( rc ) { - log_error("pubkey_generate failed: %s\n", g10_errstr(rc) ); - return rc; - } - - 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; - pk->pkey[0] = mpi_copy( skey[0] ); - pk->pkey[1] = mpi_copy( skey[1] ); - 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->skey[5] = skey[5]; - sk->is_protected = 0; - sk->protect.algo = 0; - - sk->csum = checksum_mpi (sk->skey[2] ); - sk->csum += checksum_mpi (sk->skey[3] ); - sk->csum += checksum_mpi (sk->skey[4] ); - sk->csum += checksum_mpi (sk->skey[5] ); - if( ret_sk ) /* not a subkey: return an unprotected version of the sk */ - *ret_sk = copy_secret_key( NULL, sk ); - - if( dek ) { - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); - if( rc ) { - log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - } - - 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 = 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; -} - - -/**************** - * check valid days: - * return 0 on error or the multiplier - */ -static int -check_valid_days( const char *s ) -{ - if( !isdigit(*s) ) - return 0; - for( s++; *s; s++) - if( !isdigit(*s) ) - break; - if( !*s ) - return 1; - if( s[1] ) - return 0; /* e.g. "2323wc" */ - if( *s == 'd' || *s == 'D' ) - return 1; - if( *s == 'w' || *s == 'W' ) - return 7; - if( *s == 'm' || *s == 'M' ) - return 30; - if( *s == 'y' || *s == 'Y' ) - return 365; - return 0; -} - - -/**************** - * 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, 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 ); - 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; - m_free(answer); - if( algo == 1 && !addmode ) { - algo = 0; /* create both keys */ - break; - } - 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 ) { - algo = PUBKEY_ALGO_RSA; - *r_usage = PUBKEY_USAGE_SIG; - break; - } - else if( algo == 4 && opt.expert) { - if( cpr_get_answer_is_yes("keygen.algo.elg_se",_( - "The use of this algorithm is deprecated - create anyway? "))){ - algo = PUBKEY_ALGO_ELGAMAL; - break; - } - } - else if( algo == 3 && addmode ) { - algo = PUBKEY_ALGO_ELGAMAL_E; - break; - } - else if( algo == 2 ) { - algo = PUBKEY_ALGO_DSA; - break; - } - else - tty_printf(_("Invalid selection.\n")); - } - return algo; -} - - -static unsigned -ask_keysize( int algo ) -{ - char *answer; - unsigned nbits; - - 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; - 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( 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 - * to create such a key (but less than the time the Sirius - * Computer Corporation needs to process one of the usual - * complaints) and {de,en}cryption although needs some time. - * So, before you complain about this limitation, I suggest that - * you start a discussion with Marvin about this theme and then - * do whatever you want. */ - tty_printf(_("keysize too large; %d is largest value allowed.\n"), - 4096); - } - else if( nbits > 2048 && !cpr_enabled() ) { - tty_printf( - _("Keysizes larger than 2048 are not suggested because\n" - "computations take REALLY long!\n")); - if( cpr_get_answer_is_yes("keygen.size.huge.okay",_( - "Are you sure that you want this keysize? ")) ) { - tty_printf(_("Okay, but keep in mind that your monitor " - "and keyboard radiation is also very vulnerable " - "to attacks!\n")); - break; - } - } - else - break; - } - tty_printf(_("Requested keysize is %u bits\n"), nbits ); - if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) { - nbits = ((nbits + 63) / 64) * 64; - tty_printf(_("rounded up to %u bits\n"), nbits ); - } - else if( (nbits % 32) ) { - nbits = ((nbits + 31) / 32) * 32; - tty_printf(_("rounded up to %u bits\n"), nbits ); - } - return nbits; -} - - -/**************** - * Parse an expire string and return it's value in days. - * Returns -1 on error. - */ -static int -parse_expire_string( const char *string ) -{ - int mult; - u32 abs_date=0; - u32 curtime = make_timestamp(); - int valid_days; - - if( !*string ) - valid_days = 0; - else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime ) { - /* This calculation is not perfectly okay because we - * are later going to simply multiply by 86400 and don't - * correct for leapseconds. A solution would be to change - * the whole implemenation to work with dates and not intervals - * which are required for v3 keys. - */ - valid_days = abs_date/86400-curtime/86400+1; - } - else if( (mult=check_valid_days(string)) ) { - valid_days = atoi(string) * mult; - if( valid_days < 0 || valid_days > 39447 ) - valid_days = 0; - } - else { - valid_days = -1; - } - return valid_days; -} - -/* 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; - - 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 */ - - answer = NULL; - for(;;) { - u32 curtime=make_timestamp(); - - 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 ); - if( valid_days < 0 ) { - tty_printf(_("invalid value\n")); - continue; - } - - if( !valid_days ) { - 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(_("%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")); - } - - if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay", - _("Is this correct (y/n)? ")) ) - break; - } - m_free(answer); - return interval; -} - -u32 -ask_expiredate() -{ - u32 x = ask_expire_interval(0); - return x? make_timestamp() + x : 0; -} - -static int -has_invalid_email_chars( const char *s ) -{ - int at_seen=0; - static char valid_chars[] = "01234567890_-." - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - for( ; *s; s++ ) { - if( *s & 0x80 ) - return 1; - if( *s == '@' ) - at_seen=1; - else if( !at_seen && !( !!strchr( valid_chars, *s ) || *s == '+' ) ) - return 1; - else if( at_seen && !strchr( valid_chars, *s ) ) - return 1; - } - return 0; -} - - -static char * -ask_user_id( int mode ) -{ - char *answer; - char *aname, *acomment, *amail, *uid; - - if( !mode ) - tty_printf( _("\n" -"You need a User-ID to identify your key; the software constructs the user id\n" -"from Real Name, Comment and Email Address in this form:\n" -" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") ); - uid = aname = acomment = amail = NULL; - for(;;) { - char *p; - int fail=0; - - if( !aname ) { - for(;;) { - m_free(aname); - aname = cpr_get("keygen.name",_("Real name: ")); - trim_spaces(aname); - cpr_kill_prompt(); - - if( opt.allow_freeform_uid ) - break; - - if( strpbrk( aname, "<>" ) ) - tty_printf(_("Invalid character in name\n")); - else if( isdigit(*aname) ) - tty_printf(_("Name may not start with a digit\n")); - else if( strlen(aname) < 5 ) - tty_printf(_("Name must be at least 5 characters long\n")); - else - break; - } - } - if( !amail ) { - for(;;) { - m_free(amail); - amail = cpr_get("keygen.email",_("Email address: ")); - trim_spaces(amail); - cpr_kill_prompt(); - if( !*amail ) - break; /* no email address is okay */ - else if( has_invalid_email_chars(amail) - || string_count_chr(amail,'@') != 1 - || *amail == '@' - || amail[strlen(amail)-1] == '@' - || amail[strlen(amail)-1] == '.' - || strstr(amail, "..") ) - tty_printf(_("Not a valid email address\n")); - else - break; - } - } - if( !acomment ) { - for(;;) { - m_free(acomment); - acomment = cpr_get("keygen.comment",_("Comment: ")); - trim_spaces(acomment); - cpr_kill_prompt(); - if( !*acomment ) - break; /* no comment is okay */ - else if( strpbrk( acomment, "()" ) ) - tty_printf(_("Invalid character in comment\n")); - else - break; - } - } - - - 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),")"); - if( *amail ) - p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); - - /* append a warning if we do not have dev/random - * or it is switched into quick testmode */ - if( quick_random_gen(-1) ) - strcpy(p, " (INSECURE!)" ); - - /* print a note in case that UTF8 mapping has to be done */ - for(p=uid; *p; p++ ) { - if( *p & 0x80 ) { - tty_printf(_("You are using the `%s' character set.\n"), - get_native_charset() ); - break; - } - } - - tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid); - /* fixme: add a warning if this user-id already exists */ - if( !*amail && (strchr( aname, '@' ) || strchr( acomment, '@'))) { - fail = 1; - tty_printf(_("Please don't put the email address " - "into the real name or the comment\n") ); - } - - for(;;) { - const char *ansstr = _("NnCcEeOoQq"); - - if( strlen(ansstr) != 10 ) - BUG(); - if( cpr_enabled() ) { - answer = m_strdup(ansstr+6); - answer[1] = 0; - } - else { - answer = cpr_get("keygen.userid.cmd", fail? - _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") : - _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); - cpr_kill_prompt(); - } - if( strlen(answer) > 1 ) - ; - else if( *answer == ansstr[0] || *answer == ansstr[1] ) { - m_free(aname); aname = NULL; - break; - } - else if( *answer == ansstr[2] || *answer == ansstr[3] ) { - m_free(acomment); acomment = NULL; - break; - } - else if( *answer == ansstr[4] || *answer == ansstr[5] ) { - m_free(amail); amail = NULL; - break; - } - else if( *answer == ansstr[6] || *answer == ansstr[7] ) { - if( fail ) { - tty_printf(_("Please correct the error first\n")); - } - else { - m_free(aname); aname = NULL; - m_free(acomment); acomment = NULL; - m_free(amail); amail = NULL; - break; - } - } - else if( *answer == ansstr[8] || *answer == ansstr[9] ) { - m_free(aname); aname = NULL; - m_free(acomment); acomment = NULL; - m_free(amail); amail = NULL; - m_free(uid); uid = NULL; - break; - } - m_free(answer); - } - m_free(answer); - if( !amail && !acomment && !amail ) - break; - m_free(uid); uid = NULL; - } - if( uid ) { - char *p = native_to_utf8( uid ); - m_free( uid ); - uid = p; - } - return uid; -} - - -static DEK * -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 = 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,errtext); - if( !dek ) { - errtext = _("passphrase not correctly repeated; try again"); - tty_printf(_("%s.\n"), errtext); - } - else if( !dek->keylen ) { - 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" - "using this program with the option \"--edit-key\".\n\n")); - break; - } - else - break; /* okay */ - } - *ret_s2k = s2k; - return dek; -} - - -static int -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; - - if( !opt.batch ) - tty_printf(_( -"We need to generate a lot of random bytes. It is a good idea to perform\n" -"some other action (type on the keyboard, move the mouse, utilize the\n" -"disks) during the prime generation; this gives the random number\n" -"generator a better chance to gain enough entropy.\n") ); - - 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 == PUBKEY_ALGO_DSA ) - rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate); - else if( algo == PUBKEY_ALGO_RSA ) - rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate); - else - BUG(); - - #ifdef ENABLE_COMMENT_PACKETS - if( !rc ) { - add_kbnode( pub_root, - make_comment_node("#created by GNUPG v" VERSION " (" - PRINTABLE_OS_NAME ")")); - add_kbnode( sec_root, - make_comment_node("#created by GNUPG v" VERSION " (" - PRINTABLE_OS_NAME ")")); - } - #endif - return rc; -} - - -/**************** - * Generate a new user id packet, or return NULL if canceled - */ -PKT_user_id * -generate_user_id() -{ - PKT_user_id *uid; - char *p; - size_t n; - - p = ask_user_id( 1 ); - if( !p ) - return NULL; - n = strlen(p); - uid = m_alloc_clear( sizeof *uid + n - 1 ); - uid->len = n; - strcpy(uid->name, p); - uid->ref = 1; - return uid; -} - - -static void -release_parameter_list( struct para_data_s *r ) -{ - struct para_data_s *r2; - - for( ; r ; r = r2 ) { - r2 = r->next; - if( r->key == pPASSPHRASE_DEK ) - m_free( r->u.dek ); - else if( r->key == pPASSPHRASE_S2K ) - m_free( r->u.s2k ); - - m_free(r); - } -} - -static struct para_data_s * -get_parameter( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r; - - for( r = para; r && r->key != key; r = r->next ) - ; - return r; -} - -static const char * -get_parameter_value( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - return (r && *r->u.value)? r->u.value : NULL; -} - -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 ) ) - 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 */ -} - - -static u32 -get_parameter_u32( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - - if( !r ) - 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 ); -} - -static unsigned int -get_parameter_uint( struct para_data_s *para, enum para_name key ) -{ - return get_parameter_u32( para, key ); -} - -static DEK * -get_parameter_dek( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - return r? r->u.dek : NULL; -} - -static STRING2KEY * -get_parameter_s2k( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, 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 para_data_s *r; - const char *s1, *s2, *s3; - size_t n; - char *p; - int i; - - /* check that we have all required parameters */ - assert( get_parameter( para, pKEYTYPE ) ); - i = get_parameter_algo( para, pKEYTYPE ); - 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 > 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 */ - s1 = get_parameter_value( para, pNAMEREAL ); - s2 = get_parameter_value( para, pNAMECOMMENT ); - s3 = get_parameter_value( para, pNAMEEMAIL ); - if( s1 || s2 || s3 ) { - n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0); - r = m_alloc_clear( sizeof *r + n + 20 ); - r->key = pUSERID; - p = r->u.value; - if( s1 ) - p = stpcpy(p, s1 ); - if( s2 ) - p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); - if( s3 ) - p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); - r->next = para; - para = r; - } - } - - /* 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 ) { - /* we have a plain text passphrase - create a DEK from it. - * It is a little bit ridiculous to keep it ih secure memory - * but becuase we do this alwasy, why not here */ - STRING2KEY *s2k; - DEK *dek; - - 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, NULL ); - set_next_passphrase( NULL ); - assert( dek ); - memset( r->u.value, 0, strlen(r->u.value) ); - - r = m_alloc_clear( sizeof *r ); - r->key = pPASSPHRASE_S2K; - r->u.s2k = s2k; - r->next = para; - para = r; - r = m_alloc_clear( sizeof *r ); - r->key = pPASSPHRASE_DEK; - r->u.dek = dek; - r->next = para; - para = r; - } - - /* make KEYEXPIRE from Expire-Date */ - r = get_parameter( para, pEXPIREDATE ); - if( r && *r->u.value ) { - i = parse_expire_string( r->u.value ); - if( i < 0 ) { - log_error("%s:%d: invalid expire date\n", fname, r->lnr ); - return -1; - } - r->u.expire = i * 86400L; - r->key = pKEYEXPIRE; /* change hat entry */ - /* also set it for the subkey */ - r = m_alloc_clear( sizeof *r + 20 ); - r->key = pSUBKEYEXPIRE; - r->u.expire = i * 86400L; - r->next = para; - para = r; - } - - if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) { - log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr ); - return -1; - } - - do_generate_keypair( para, outctrl ); - return 0; -} - - -/**************** - * Kludge to allow non interactive key generation controlled - * by a parameter file (which currently is only stdin) - * Note, that string parameters are expected to be in UTF-8 - */ -static void -read_parameter_file( const char *fname ) -{ - static struct { const char *name; - enum para_name key; - } 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; - char line[1024], *p; - int lnr; - const char *err = NULL; - struct para_data_s *para, *r; - int i; - struct output_control_s outctrl; - - memset( &outctrl, 0, sizeof( outctrl ) ); - - if( !fname || !*fname || !strcmp(fname,"-") ) { - fp = stdin; - fname = "-"; - } - else { - fp = fopen( fname, "r" ); - if( !fp ) { - log_error(_("can't open `%s': %s\n"), fname, strerror(errno) ); - return; - } - } - - lnr = 0; - err = NULL; - para = NULL; - while( fgets( line, DIM(line)-1, fp ) ) { - char *keyword, *value; - - lnr++; - if( *line && line[strlen(line)-1] != '\n' ) { - err = "line too long"; - break; - } - for( p = line; isspace(*(byte*)p); p++ ) - ; - if( !*p || *p == '#' ) - continue; - keyword = p; - if( *keyword == '%' ) { - for( ; !isspace(*(byte*)p); p++ ) - ; - if( *p ) - *p++ = 0; - for( ; isspace(*(byte*)p); p++ ) - ; - value = p; - trim_trailing_ws( value, strlen(value) ); - if( !ascii_strcasecmp( keyword, "%echo" ) ) - log_info("%s\n", value ); - else if( !ascii_strcasecmp( keyword, "%dry-run" ) ) - outctrl.dryrun = 1; - else if( !ascii_strcasecmp( keyword, "%commit" ) ) { - outctrl.lnr = lnr; - proc_parameter_file( para, fname, &outctrl ); - release_parameter_list( para ); - para = NULL; - } - else if( !ascii_strcasecmp( keyword, "%pubring" ) ) { - if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) - ; /* still the same file - ignore it */ - else { - m_free( outctrl.pub.newfname ); - outctrl.pub.newfname = m_strdup( value ); - outctrl.use_files = 1; - } - } - else if( !ascii_strcasecmp( keyword, "%secring" ) ) { - if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) ) - ; /* still the same file - ignore it */ - else { - m_free( outctrl.sec.newfname ); - outctrl.sec.newfname = m_strdup( value ); - outctrl.use_files = 1; - } - } - else - log_info("skipping control `%s' (%s)\n", keyword, value ); - - - continue; - } - - - if( !(p = strchr( p, ':' )) || p == keyword ) { - err = "missing colon"; - break; - } - if( *p ) - *p++ = 0; - for( ; isspace(*(byte*)p); p++ ) - ; - if( !*p ) { - err = "missing argument"; - break; - } - value = p; - trim_trailing_ws( value, strlen(value) ); - - for(i=0; keywords[i].name; i++ ) { - if( !ascii_strcasecmp( keywords[i].name, keyword ) ) - break; - } - if( !keywords[i].name ) { - err = "unknown keyword"; - break; - } - if( keywords[i].key != pKEYTYPE && !para ) { - err = "parameter block does not start with \"Key-Type\""; - break; - } - - if( keywords[i].key == pKEYTYPE && para ) { - outctrl.lnr = lnr; - proc_parameter_file( para, fname, &outctrl ); - release_parameter_list( para ); - para = NULL; - } - else { - for( r = para; r; r = r->next ) { - if( r->key == keywords[i].key ) - break; - } - if( r ) { - err = "duplicate keyword"; - break; - } - } - r = m_alloc_clear( sizeof *r + strlen( value ) ); - r->lnr = lnr; - r->key = keywords[i].key; - strcpy( r->u.value, value ); - r->next = para; - para = r; - } - if( err ) - log_error("%s:%d: %s\n", fname, lnr, err ); - else if( ferror(fp) ) { - log_error("%s:%d: read error: %s\n", fname, lnr, strerror(errno) ); - } - else if( para ) { - outctrl.lnr = lnr; - proc_parameter_file( para, fname, &outctrl ); - } - - if( outctrl.use_files ) { /* close open streams */ - iobuf_close( outctrl.pub.stream ); - iobuf_close( outctrl.sec.stream ); - m_free( outctrl.pub.fname ); - m_free( outctrl.pub.newfname ); - m_free( outctrl.sec.fname ); - m_free( outctrl.sec.newfname ); - } - - release_parameter_list( para ); - if( strcmp( fname, "-" ) ) - fclose(fp); -} - - -/**************** - * Generate a keypair - * (fname is only used in batch mode) - */ -void -generate_keypair( const char *fname ) -{ - unsigned int nbits; - char *uid = NULL; - DEK *dek; - STRING2KEY *s2k; - int algo; - unsigned int use; - int both = 0; - u32 expire; - struct para_data_s *para = NULL; - struct para_data_s *r; - struct output_control_s outctrl; - - memset( &outctrl, 0, sizeof( outctrl ) ); - - if( opt.batch ) { - read_parameter_file( fname ); - return; - } - - algo = ask_algo( 0, &use ); - if( !algo ) { /* default: DSA with ElG subkey of the specified size */ - both = 1; - r = m_alloc_clear( sizeof *r + 20 ); - r->key = pKEYTYPE; - sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA ); - r->next = para; - para = r; - tty_printf(_("DSA keypair will have 1024 bits.\n")); - r = m_alloc_clear( sizeof *r + 20 ); - r->key = pKEYLENGTH; - strcpy( r->u.value, "1024" ); - r->next = para; - para = r; - - 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 = 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 = 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(0); - r = m_alloc_clear( sizeof *r + 20 ); - r->key = pKEYEXPIRE; - r->u.expire = expire; - r->next = para; - para = r; - r = m_alloc_clear( sizeof *r + 20 ); - r->key = pSUBKEYEXPIRE; - r->u.expire = expire; - r->next = para; - para = r; - - uid = ask_user_id(0); - if( !uid ) { - log_error(_("Key generation canceled.\n")); - release_parameter_list( para ); - return; - } - r = m_alloc_clear( sizeof *r + strlen(uid) ); - r->key = pUSERID; - strcpy( r->u.value, uid ); - r->next = para; - para = r; - - dek = ask_passphrase( &s2k ); - if( dek ) { - r = m_alloc_clear( sizeof *r ); - r->key = pPASSPHRASE_DEK; - r->u.dek = dek; - r->next = para; - para = r; - r = m_alloc_clear( sizeof *r ); - r->key = pPASSPHRASE_S2K; - r->u.s2k = s2k; - r->next = para; - para = r; - } - - proc_parameter_file( para, "[internal]", &outctrl ); - release_parameter_list( para ); -} - - -static void -print_status_key_created (int letter, PKT_public_key *pk) -{ - byte array[MAX_FINGERPRINT_LEN], *s; - char buf[MAX_FINGERPRINT_LEN*2+30], *p; - size_t i, n; - - p = buf; - *p++ = letter; - *p++ = ' '; - fingerprint_from_pk (pk, array, &n); - s = array; - for (i=0; i < n ; i++, s++, p += 2) - sprintf (p, "%02X", *s); - *p = 0; - write_status_text (STATUS_KEY_CREATED, buf); -} - -static void -do_generate_keypair( struct para_data_s *para, - struct output_control_s *outctrl ) -{ - 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"); - return; - } - - - if( outctrl->use_files ) { - if( outctrl->pub.newfname ) { - iobuf_close(outctrl->pub.stream); - outctrl->pub.stream = NULL; - m_free( outctrl->pub.fname ); - outctrl->pub.fname = outctrl->pub.newfname; - outctrl->pub.newfname = NULL; - - outctrl->pub.stream = iobuf_create( outctrl->pub.fname ); - if( !outctrl->pub.stream ) { - log_error("can't create `%s': %s\n", outctrl->pub.newfname, - strerror(errno) ); - return; - } - if( opt.armor ) { - outctrl->pub.afx.what = 1; - iobuf_push_filter( outctrl->pub.stream, armor_filter, - &outctrl->pub.afx ); - } - } - if( outctrl->sec.newfname ) { - iobuf_close(outctrl->sec.stream); - outctrl->sec.stream = NULL; - m_free( outctrl->sec.fname ); - outctrl->sec.fname = outctrl->sec.newfname; - outctrl->sec.newfname = NULL; - - outctrl->sec.stream = iobuf_create( outctrl->sec.fname ); - if( !outctrl->sec.stream ) { - log_error("can't create `%s': %s\n", outctrl->sec.newfname, - strerror(errno) ); - return; - } - if( opt.armor ) { - outctrl->sec.afx.what = 5; - iobuf_push_filter( outctrl->sec.stream, armor_filter, - &outctrl->sec.afx ); - } - } - assert( outctrl->pub.stream ); - assert( outctrl->sec.stream ); - 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 ); - } - } - - - /* we create the packets as a tree of kbnodes. Because the structure - * we create is known in advance we simply generate a linked list - * The first packet is a dummy comment packet which we flag - * as deleted. The very first packet must always be a KEY packet. - */ - pub_root = make_comment_node("#"); delete_kbnode(pub_root); - sec_root = make_comment_node("#"); delete_kbnode(sec_root); - - rc = do_create( get_parameter_algo( para, pKEYTYPE ), - get_parameter_uint( para, pKEYLENGTH ), - pub_root, sec_root, - get_parameter_dek( para, pPASSPHRASE_DEK ), - 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, - get_parameter_uint (para, pKEYUSAGE)); - if( !rc ) - rc = write_selfsig(sec_root, pub_root, sk, - get_parameter_uint (para, pKEYUSAGE)); - } - - if( get_parameter( para, pSUBKEYTYPE ) ) { - rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ), - get_parameter_uint( para, pSUBKEYLENGTH ), - pub_root, sec_root, - get_parameter_dek( para, pPASSPHRASE_DEK ), - get_parameter_s2k( para, pPASSPHRASE_S2K ), - NULL, - get_parameter_u32( para, pSUBKEYEXPIRE ) ); - if( !rc ) - rc = write_keybinding(pub_root, pub_root, sk, - get_parameter_uint (para, pSUBKEYUSAGE)); - if( !rc ) - 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", g10_errstr(rc) ); - if( !rc ) { - rc = write_keyblock( outctrl->sec.stream, sec_root ); - if( rc ) - log_error("can't write secret key: %s\n", g10_errstr(rc) ); - } - - } - else if( !rc ) { /* write to the standard keyrings */ - 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( !opt.batch - && ( 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 " - "encryption. You may want to use\n" - "the command \"--edit-key\" to generate a " - "secondary key for this purpose.\n") ); - } - } - } - - if( rc ) { - if( opt.batch ) - log_error("key generation failed: %s\n", g10_errstr(rc) ); - else - tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) ); - } - else { - PKT_public_key *pk = find_kbnode (pub_root, - PKT_PUBLIC_KEY)->pkt->pkt.public_key; - print_status_key_created (did_sub? 'B':'P', pk); - } - release_kbnode( pub_root ); - release_kbnode( sec_root ); - if( sk ) /* the unprotected secret key */ - free_secret_key(sk); -} - - -/**************** - * add a new subkey to an existing key. - * Returns true if a new key has been generated and put into the keyblocks. - */ -int -generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) -{ - int okay=0, rc=0; - KBNODE node; - PKT_secret_key *sk = NULL; /* this is the primary sk */ - int algo; - unsigned int use; - u32 expire; - unsigned nbits; - char *passphrase = NULL; - DEK *dek = NULL; - STRING2KEY *s2k = NULL; - u32 cur_time; - - /* break out the primary secret key */ - node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); - if( !node ) { - log_error("Oops; secret key not found anymore!\n"); - goto leave; - } - - /* make a copy of the sk to keep the protected one in the keyblock */ - sk = copy_secret_key( NULL, node->pkt->pkt.secret_key ); - - cur_time = make_timestamp(); - if( sk->timestamp > cur_time ) { - ulong d = sk->timestamp - cur_time; - log_info( d==1 ? _("key has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key has been created %lu seconds " - "in future (time warp or clock problem)\n"), d ); - if( !opt.ignore_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 = G10ERR_PUBKEY_ALGO; - break; - case 0: - tty_printf("This key is not protected.\n"); - break; - default: - tty_printf("Key is protected.\n"); - rc = check_secret_key( sk, 0 ); - if( !rc ) - passphrase = get_last_passphrase(); - break; - } - if( rc ) - goto leave; - - - algo = ask_algo( 1, &use ); - assert(algo); - nbits = ask_keysize( algo ); - expire = ask_expire_interval(0); - if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", - _("Really create? ") ) ) - goto leave; - - if( passphrase ) { - 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, NULL ); - } - - rc = do_create( algo, nbits, pub_keyblock, sec_keyblock, - dek, s2k, NULL, expire ); - if( !rc ) - 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"), 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 ); - return okay; -} - -/**************** - * Write a keyblock to an output stream - */ -static int -write_keyblock( IOBUF out, KBNODE node ) -{ - for( ; node ; node = node->next ) { - int rc = build_packet( out, node->pkt ); - if( rc ) { - log_error("build_packet(%d) failed: %s\n", - node->pkt->pkttype, g10_errstr(rc) ); - return G10ERR_WRITE_FILE; - } - } - return 0; -} diff --git a/g10/keyid.c b/g10/keyid.c deleted file mode 100644 index 43e531e3e..000000000 --- a/g10/keyid.c +++ /dev/null @@ -1,502 +0,0 @@ -/* keyid.c - key ID and fingerprint handling - * Copyright (C) 1998, 1999, 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 <time.h> -#include <assert.h> -#include "util.h" -#include "main.h" -#include "packet.h" -#include "options.h" -#include "mpi.h" -#include "keydb.h" -#include "i18n.h" - - -int -pubkey_letter( int algo ) -{ - switch( algo ) { - 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 MD_HANDLE -do_fingerprint_md( PKT_public_key *pk ) -{ - 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 = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0); - n = pk->version < 4 ? 8 : 6; - for(i=0; i < npkey; i++ ) { - nb[i] = mpi_get_nbits(pk->pkey[i]); - pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL ); - n += 2 + nn[i]; - } - - md_putc( md, 0x99 ); /* ctb */ - md_putc( md, n >> 8 ); /* 2 byte length header */ - md_putc( md, n ); - if( pk->version < 4 ) - md_putc( md, 3 ); - else - md_putc( md, 4 ); - - { u32 a = pk->timestamp; - 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; - - if( pk->expiredate ) - a = (u16)((pk->expiredate - pk->timestamp) / 86400L); - else - a = 0; - md_putc( md, a >> 8 ); - md_putc( md, a ); - } - md_putc( md, pk->pubkey_algo ); - for(i=0; i < npkey; i++ ) { - md_putc( md, nb[i]>>8); - md_putc( md, nb[i] ); - md_write( md, pp[i], nn[i] ); - m_free(pp[i]); - } - md_final( md ); - - return md; -} - -static MD_HANDLE -do_fingerprint_md_sk( PKT_secret_key *sk ) -{ - PKT_public_key pk; - int npkey = pubkey_get_npkey( sk->pubkey_algo ); /* npkey is correct! */ - int i; - - pk.pubkey_algo = sk->pubkey_algo; - pk.version = sk->version; - pk.timestamp = sk->timestamp; - pk.expiredate = sk->expiredate; - pk.pubkey_algo = sk->pubkey_algo; - for( i=0; i < npkey; i++ ) - pk.pkey[i] = sk->skey[i]; - return do_fingerprint_md( &pk ); -} - - -/**************** - * 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. - */ -u32 -keyid_from_sk( PKT_secret_key *sk, u32 *keyid ) -{ - u32 lowbits; - u32 dummy_keyid[2]; - - if( !keyid ) - keyid = dummy_keyid; - - 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; - MD_HANDLE md; - md = do_fingerprint_md_sk(sk); - 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] ; - lowbits = keyid[1]; - md_close(md); - } - - return lowbits; -} - - -/**************** - * Get the keyid from the public key and put it into keyid - * if this is not NULL. Return the 32 low bits of the keyid. - */ -u32 -keyid_from_pk( PKT_public_key *pk, u32 *keyid ) -{ - u32 lowbits; - u32 dummy_keyid[2]; - - if( !keyid ) - keyid = dummy_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) ) { - 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; - MD_HANDLE md; - md = do_fingerprint_md(pk); - 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] ; - lowbits = keyid[1]; - md_close(md); - pk->keyid[0] = keyid[0]; - pk->keyid[1] = keyid[1]; - } - - return lowbits; -} - - -/**************** - * Get the keyid from the fingerprint. This function is simple for most - * keys, but has to do a keylookup for old stayle keys. - */ -u32 -keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ) -{ - u32 dummy_keyid[2]; - - if( !keyid ) - keyid = dummy_keyid; - - if( fprint_len != 20 ) { - /* This is special as we have to lookup the key first */ - PKT_public_key pk; - int rc; - - memset( &pk, 0, sizeof pk ); - rc = get_pubkey_byfprint( &pk, fprint, fprint_len ); - if( rc ) { - log_error("Oops: keyid_from_fingerprint: no pubkey\n"); - keyid[0] = 0; - keyid[1] = 0; - } - else - keyid_from_pk( &pk, keyid ); - } - else { - const byte *dp = fprint; - 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] ; - } - - return keyid[1]; -} - - -u32 -keyid_from_sig( PKT_signature *sig, u32 *keyid ) -{ - if( keyid ) { - keyid[0] = sig->keyid[0]; - keyid[1] = sig->keyid[1]; - } - return sig->keyid[1]; -} - -/**************** - * return the number of bits used in the pk - */ -unsigned -nbits_from_pk( PKT_public_key *pk ) -{ - return pubkey_nbits( pk->pubkey_algo, pk->pkey ); -} - -/**************** - * return the number of bits used in the sk - */ -unsigned -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. - * Format is: yyyy-mm-dd - */ -const char * -datestr_from_pk( PKT_public_key *pk ) -{ - static char buffer[11+5]; - time_t atime = pk->timestamp; - - return mk_datestr (buffer, atime); -} - -const char * -datestr_from_sk( PKT_secret_key *sk ) -{ - static char buffer[11+5]; - time_t atime = sk->timestamp; - - return mk_datestr (buffer, atime); -} - -const char * -datestr_from_sig( PKT_signature *sig ) -{ - static char buffer[11+5]; - time_t atime = sig->timestamp; - - return mk_datestr (buffer, atime); -} - -const char * -expirestr_from_pk( PKT_public_key *pk ) -{ - static char buffer[11+5]; - time_t atime; - - if( !pk->expiredate ) - return _("never "); - atime = pk->expiredate; - return mk_datestr (buffer, atime); -} - -const char * -expirestr_from_sk( PKT_secret_key *sk ) -{ - static char buffer[11+5]; - time_t atime; - - if( !sk->expiredate ) - return _("never "); - atime = sk->expiredate; - 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); -} - - -/**************** . - * Return a byte array with the fingerprint for the given PK/SK - * The length of the array is returned in ret_len. Caller must free - * the array or provide an array of length MAX_FINGERPRINT_LEN. - */ - -byte * -fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len ) -{ - 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 */ - MD_HANDLE md; - - md = md_open( DIGEST_ALGO_MD5, 0); - if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) { - 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); - } - md_final(md); - if( !array ) - array = m_alloc( 16 ); - len = 16; - memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 ); - md_close(md); - } - else { - MD_HANDLE md; - md = do_fingerprint_md(pk); - dp = md_read( md, 0 ); - len = md_digest_length( md_get_algo( md ) ); - assert( len <= MAX_FINGERPRINT_LEN ); - if( !array ) - array = m_alloc( len ); - memcpy(array, dp, len ); - 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; -} - -byte * -fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len ) -{ - 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 */ - MD_HANDLE md; - - md = md_open( DIGEST_ALGO_MD5, 0); - if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) { - 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); - } - md_final(md); - if( !array ) - array = m_alloc( 16 ); - len = 16; - memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 ); - md_close(md); - } - else { - MD_HANDLE md; - md = do_fingerprint_md_sk(sk); - dp = md_read( md, 0 ); - len = md_digest_length( md_get_algo( md ) ); - assert( len <= MAX_FINGERPRINT_LEN ); - if( !array ) - array = m_alloc( len ); - memcpy(array, dp, len ); - md_close(md); - } - - *ret_len = len; - return array; -} - - - diff --git a/g10/keylist.c b/g10/keylist.c deleted file mode 100644 index a1a0e4c13..000000000 --- a/g10/keylist.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* keylist.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "keydb.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); - -struct sig_stats -{ - int inv_sigs; - int no_key; - int oth_err; -}; - -static FILE *attrib_fp=NULL; - -/**************** - * List the keys - * If list is NULL, all available keys are listed - */ -void -public_key_list( STRLIST list ) -{ - if( !list ) - list_all(0); - else - list_one( list, 0 ); -} - -void -secret_key_list( STRLIST list ) -{ - if( !list ) - list_all(1); - else /* List by user id */ - 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 ) -{ - KEYDB_HANDLE hd; - KBNODE keyblock = NULL; - int rc=0; - const char *lastresname, *resname; - struct sig_stats stats; - - memset(&stats,0,sizeof(stats)); - - hd = keydb_new (secret); - if (!hd) - rc = G10ERR_GENERAL; - else - rc = keydb_search_first (hd); - if( rc ) { - if( rc != -1 ) - log_error("keydb_search_first failed: %s\n", g10_errstr(rc) ); - goto leave; - } - - 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; - - printf("%s\n", resname ); - for(i=strlen(resname); i; i-- ) - putchar('-'); - putchar('\n'); - lastresname = resname; - } - 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 ("keydb_search_next failed: %s\n", g10_errstr(rc)); - - if(opt.check_sigs && !opt.with_colons) - print_signature_stats(&stats); - - leave: - release_kbnode (keyblock); - keydb_release (hd); -} - - -static void -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", g10_errstr(rc) ); - get_seckey_end( ctx ); - return; - } - do { - 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, NULL ); - release_kbnode( keyblock ); - } while( !get_seckey_next( ctx, NULL, &keyblock ) ); - get_seckey_end( ctx ); - } - else { - rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock ); - if( rc ) { - log_error("error reading key: %s\n", g10_errstr(rc) ); - get_pubkey_end( ctx ); - return; - } - do { - 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 -print_key_data( PKT_public_key *pk, u32 *keyid ) -{ - int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0; - int i; - - for(i=0; i < n; 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) -{ - if(pk || (sk && sk->protect.s2k.mode!=1001)) - { - unsigned int use = pk? pk->pubkey_usage : sk->pubkey_usage; - - if ( use & PUBKEY_USAGE_ENC ) - putchar ('e'); - - if ( use & PUBKEY_USAGE_SIG ) - { - putchar ('s'); - if( pk? pk->is_primary : sk->is_primary ) - 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 = 1; - if(pk->is_primary) - 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 - && sk->protect.s2k.mode!=1001 ) { - if ( sk->pubkey_usage & PUBKEY_USAGE_ENC ) - enc = 1; - if ( sk->pubkey_usage & PUBKEY_USAGE_SIG ) - { - sign = 1; - if(sk->is_primary) - 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", - (ulong)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_print ( KBNODE keyblock, int secret, int fpr, void *opaque ) -{ - int rc = 0; - KBNODE kbctx; - KBNODE node; - PKT_public_key *pk; - PKT_secret_key *sk; - u32 keyid[2]; - int any=0; - struct sig_stats *stats=opaque; - - /* 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%c %4u%c/%08lX %s ", (sk->protect.s2k.mode==1001)?'#':' ', - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid[1], - datestr_from_sk( sk ) ); - } - else { - pk = node->pkt->pkt.public_key; - sk = NULL; - keyid_from_pk( pk, keyid ); - 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 or expired 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 || - node->pkt->pkt.user_id->is_expired )) - 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; - } - - /* TODO: Make sure a cached sig record here still has - the pk that issued it. See also - keyedit.c:print_and_check_one_sig */ - - } - else { - rc = 0; - sigrc = ' '; - } - - 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], - 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 (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 ) { - 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->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 ); - trustletter = get_validity_info( pk, namehash ); - } - else - trustletter = 'u'; - printf("%s:%c::::::::",str,trustletter); - } - } - 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; - } - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - u32 keyid2[2]; - PKT_public_key *pk2 = node->pkt->pkt.public_key; - - if( !any ) { - 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 ); - 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], - 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(':'); - 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 ); - } - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - u32 keyid2[2]; - PKT_secret_key *sk2 = node->pkt->pkt.secret_key; - - if( !any ) { - putchar(':'); - putchar(':'); - print_capabilities (pk, sk, keyblock); - putchar('\n'); - if( fpr ) - print_fingerprint( pk, sk, 0 ); /* of the main key */ - any = 1; - } - - keyid_from_sk( sk2, keyid2 ); - printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::", - nbits_from_sk( sk2 ), - sk2->pubkey_algo, - (ulong)keyid2[0],(ulong)keyid2[1], - 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; - - if( !any ) { /* no user id, (maybe a revocation follows)*/ - if( sig->sig_class == 0x20 ) - fputs("[revoked]:", stdout); - else if( sig->sig_class == 0x18 ) - fputs("[key binding]:", stdout); - else if( sig->sig_class == 0x28 ) - fputs("[subkey revoked]:", stdout); - else - putchar (':'); - putchar(':'); - print_capabilities (pk, sk, keyblock); - 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::::::::::%02x%c:\n", - sig->sig_class, sig->flags.exportable?'x':'l'); - continue; - } - if( opt.check_sigs ) { - fflush(stdout); - rc = check_key_signature( keyblock, node, NULL ); - switch( rc ) { - case 0: sigrc = '!'; break; - case G10ERR_BAD_SIGN: sigrc = '-'; break; - case G10ERR_NO_PUBKEY: - case G10ERR_UNU_PUBKEY: sigrc = '?'; break; - default: sigrc = '%'; break; - } - } - else { - rc = 0; - sigrc = ' '; - } - 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], colon_datestr_from_sig(sig), - colon_expirestr_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_string( stdout, p, n, ':' ); - m_free(p); - } - 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 */ - putchar(':'); - putchar(':'); - print_capabilities (pk, sk, keyblock); - putchar('\n'); - } -} - -/* - * 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 */ - - last->next = primary; - primary0->next = primary2->next; - primary2->next = node; -} - -void -list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque ) -{ - 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 - * 3: direct use of tty but only primary key. - * modes 1 and 2 will try and print both subkey and primary key fingerprints - */ -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; - int primary=0; - - if(sk) - { - if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1]) - primary=1; - } - else - { - if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1]) - primary=1; - } - - /* Just to be safe */ - if(mode&0x80 && !primary) - { - log_error("primary key is not really primary!\n"); - return; - } - - mode&=~0x80; - - if(!primary && (mode==1 || mode==2)) - { - if(sk) - { - PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk)); - get_seckey(primary_sk,sk->main_keyid); - print_fingerprint(NULL,primary_sk,mode|0x80); - free_secret_key(primary_sk); - } - else - { - PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk)); - get_pubkey(primary_pk,pk->main_keyid); - print_fingerprint(primary_pk,NULL,mode|0x80); - free_public_key(primary_pk); - } - } - - if (mode == 1) { - fp = log_stream (); - if(primary) - text = _("Primary key fingerprint:"); - else - text = _(" Subkey 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 */ - if(primary) - text = _(" Primary key fingerprint:"); - else - text = _(" Subkey fingerprint:"); - } - else if (mode == 3) { - fp = NULL; /* use tty */ - text = _(" Key fingerprint ="); - } - else { - 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 (fp) { - if (i && !(i%8) ) - putc (' ', fp); - fprintf (fp, " %02X", *p ); - } - else { - if (i && !(i%8) ) - tty_printf (" "); - tty_printf (" %02X", *p ); - } - } - } - } - 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 deleted file mode 100644 index 3160b1c37..000000000 --- a/g10/keyring.c +++ /dev/null @@ -1,1558 +0,0 @@ -/* 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; - mode_t oldmask; - - *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 */ - - /* Create the temp file with limited access */ - oldmask=umask(077); - *r_fp = iobuf_create (tmpfname); - umask(oldmask); - 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; - - /* 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; - } - - /* Now make sure the file has the same permissions as the original */ - -#ifndef HAVE_DOSISH_SYSTEM - { - struct stat statbuf; - - statbuf.st_mode=S_IRUSR | S_IWUSR; - - if(((secret && !opt.preserve_permissions) || - (stat(bakfname,&statbuf)==0)) && - (chmod(fname,statbuf.st_mode)==0)) - ; - else - log_error("WARNING: unable to restore permissions to `%s': %s", - fname,strerror(errno)); - } -#endif - - 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 checked so far (%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; - mode_t oldmask; - - oldmask=umask(077); - newfp = iobuf_create (fname); - umask(oldmask); - 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; - } - 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 deleted file mode 100644 index cb8e404a4..000000000 --- a/g10/keyring.h +++ /dev/null @@ -1,45 +0,0 @@ -/* 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.c b/g10/keyserver.c deleted file mode 100644 index 59d67e32d..000000000 --- a/g10/keyserver.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* 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 <assert.h> -#include "filter.h" -#include "keydb.h" -#include "status.h" -#include "exec.h" -#include "main.h" -#include "i18n.h" -#include "iobuf.h" -#include "memory.h" -#include "ttyio.h" -#include "options.h" -#include "packet.h" -#include "keyserver-internal.h" -#include "util.h" - -#define GET 0 -#define SEND 1 -#define SEARCH 2 - -struct keyrec -{ - KEYDB_SEARCH_DESC desc; - time_t createtime,expiretime; - int size,flags; - byte type; - IOBUF uidbuf; - int lines; -}; - -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} -}; - -static int keyserver_work(int action,STRLIST list, - KEYDB_SEARCH_DESC *desc,int count); - -void -parse_keyserver_options(char *options) -{ - char *tok; - - while((tok=strsep(&options," ,"))) - { - int i,hit=0; - - if(tok[0]=='\0') - continue; - - for(i=0;keyserver_opts[i].name;i++) - { - if(ascii_strcasecmp(tok,keyserver_opts[i].name)==0) - { - *(keyserver_opts[i].flag)=1; - hit=1; - break; - } - else if(ascii_strncasecmp("no-",tok,3)==0 && - ascii_strcasecmp(&tok[3],keyserver_opts[i].name)==0) - { - *(keyserver_opts[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(!parse_import_options(tok, - &opt.keyserver_options.import_options) && - !parse_export_options(tok, - &opt.keyserver_options.export_options)) - add_to_strlist(&opt.keyserver_options.other,tok); - } - } -} - -int -parse_keyserver_uri(char *uri,const char *configname,unsigned int configlineno) -{ - int assume_hkp=0; - - assert(uri!=NULL); - - opt.keyserver_host=NULL; - opt.keyserver_port=NULL; - opt.keyserver_opaque=NULL; - - /* Get the scheme */ - - opt.keyserver_scheme=strsep(&uri,":"); - if(uri==NULL) - { - /* Assume HKP if there is no scheme */ - assume_hkp=1; - uri=opt.keyserver_scheme; - opt.keyserver_scheme="hkp"; - } - else - { - /* Force to lowercase */ - char *i; - - for(i=opt.keyserver_scheme;*i!='\0';i++) - *i=ascii_tolower(*i); - } - - 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"; - } - - if(assume_hkp || (uri[0]=='/' && uri[1]=='/')) - { - /* Two slashes means network path. */ - - /* Skip over the "//", if any */ - if(!assume_hkp) - uri+=2; - - /* Get the host */ - opt.keyserver_host=strsep(&uri,":/"); - if(opt.keyserver_host[0]=='\0') - return G10ERR_BAD_URI; - - if(uri==NULL || uri[0]=='\0') - opt.keyserver_port=NULL; - 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++; - } - } - - /* (any path part of the URI is discarded for now as no keyserver - uses it yet) */ - } - else if(uri[0]!='/') - { - /* No slash means opaque. Just record the opaque blob and get - out. */ - opt.keyserver_opaque=uri; - return 0; - } - else - { - /* One slash means absolute path. We don't need to support that - yet. */ - return G10ERR_BAD_URI; - } - - if(opt.keyserver_scheme[0]=='\0') - return G10ERR_BAD_URI; - - return 0; -} - -static void -print_keyrec(int number,struct keyrec *keyrec) -{ - int i; - - iobuf_writebyte(keyrec->uidbuf,0); - iobuf_flush_temp(keyrec->uidbuf); - printf("(%d)\t%s ",number,iobuf_get_temp_buffer(keyrec->uidbuf)); - - if(keyrec->size>0) - printf("%d bit ",keyrec->size); - - if(keyrec->type) - { - const char *str=pubkey_algo_to_string(keyrec->type); - - if(str) - printf("%s ",str); - else - printf("unknown "); - } - - switch(keyrec->desc.mode) - { - case KEYDB_SEARCH_MODE_SHORT_KID: - printf("key %08lX",(ulong)keyrec->desc.u.kid[1]); - break; - - case KEYDB_SEARCH_MODE_LONG_KID: - printf("key %08lX%08lX",(ulong)keyrec->desc.u.kid[0], - (ulong)keyrec->desc.u.kid[1]); - break; - - case KEYDB_SEARCH_MODE_FPR16: - printf("key "); - for(i=0;i<16;i++) - printf("%02X",(unsigned char)keyrec->desc.u.fpr[i]); - break; - - case KEYDB_SEARCH_MODE_FPR20: - printf("key "); - for(i=0;i<20;i++) - printf("%02X",(unsigned char)keyrec->desc.u.fpr[i]); - break; - - default: - BUG(); - break; - } - - if(keyrec->createtime>0) - printf(", created %s",strtimestamp(keyrec->createtime)); - - if(keyrec->expiretime>0) - printf(", expires %s",strtimestamp(keyrec->expiretime)); - - if(keyrec->flags&1) - printf(" (%s)",("revoked")); - if(keyrec->flags&2) - printf(" (%s)",("disabled")); - if(keyrec->flags&4) - printf(" (%s)",("expired")); - - printf("\n"); -} - -/* Returns a keyrec (which must be freed) once a key is complete, and - NULL otherwise. Call with a NULL keystring once key parsing is - complete to return any unfinished keys. */ -static struct keyrec * -parse_keyrec(char *keystring) -{ - static struct keyrec *work=NULL; - struct keyrec *ret=NULL; - char *record,*tok; - int i; - - if(keystring==NULL) - { - if(work==NULL) - return NULL; - else if(work->desc.mode==KEYDB_SEARCH_MODE_NONE) - { - m_free(work); - return NULL; - } - else - { - ret=work; - work=NULL; - return ret; - } - } - - if(work==NULL) - { - work=m_alloc_clear(sizeof(struct keyrec)); - work->uidbuf=iobuf_temp(); - } - - /* Remove trailing whitespace */ - for(i=strlen(keystring);i>0;i--) - if(isspace(keystring[i-1])) - keystring[i-1]='\0'; - else - break; - - if((record=strsep(&keystring,":"))==NULL) - return ret; - - if(ascii_strcasecmp("pub",record)==0) - { - if(work->desc.mode) - { - ret=work; - work=m_alloc_clear(sizeof(struct keyrec)); - work->uidbuf=iobuf_temp(); - } - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - classify_user_id(tok,&work->desc); - if(work->desc.mode!=KEYDB_SEARCH_MODE_SHORT_KID - && work->desc.mode!=KEYDB_SEARCH_MODE_LONG_KID - && work->desc.mode!=KEYDB_SEARCH_MODE_FPR16 - && work->desc.mode!=KEYDB_SEARCH_MODE_FPR20) - { - work->desc.mode=KEYDB_SEARCH_MODE_NONE; - return ret; - } - - /* Note all items after this are optional. This allows us to - have a pub line as simple as pub:keyid and nothing else. */ - - work->lines++; - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - work->type=atoi(tok); - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - work->size=atoi(tok); - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - work->createtime=atoi(tok); - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - work->expiretime=atoi(tok); - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - while(*tok) - switch(*tok++) - { - case 'r': - case 'R': - work->flags|=1; - break; - - case 'd': - case 'D': - work->flags|=2; - break; - - case 'e': - case 'E': - work->flags|=4; - break; - } - - if(work->expiretime && work->expiretime<=make_timestamp()) - work->flags|=4; - } - else if(ascii_strcasecmp("uid",record)==0 && work->desc.mode) - { - char *userid,*tok,*decoded; - int i=0; - - if((tok=strsep(&keystring,":"))==NULL) - return ret; - - if(strlen(tok)==0) - return ret; - - userid=tok; - - /* By definition, de-%-encoding is always smaller than the - original string so we can decode in place. */ - - while(*tok) - if(tok[0]=='%' && tok[1] && tok[2]) - { - if((userid[i]=hextobyte(&tok[1]))==-1) - userid[i]='?'; - - i++; - tok+=3; - } - else - userid[i++]=*tok++; - - /* We don't care about the other info provided in the uid: line - since no keyserver supports marking userids with timestamps - or revoked/expired/disabled yet. */ - - /* No need to check for control characters, as utf8_to_native - does this for us. */ - - decoded=utf8_to_native(userid,i,0); - iobuf_writestr(work->uidbuf,decoded); - m_free(decoded); - iobuf_writestr(work->uidbuf,"\n\t"); - work->lines++; - } - - /* Ignore any records other than "pri" and "uid" for easy future - growth. */ - - return ret; -} - -/* TODO: do this as a list sent to keyserver_work rather than calling - it once for each key to get the correct counts after the import - (cosmetics, really) and to better take advantage of the keyservers - that can do multiple fetches in one go (LDAP). */ -static int -show_prompt(KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search) -{ - char *answer; - - if(count) - { - static int from=1; - tty_printf("Keys %d-%d of %d for \"%s\". ",from,numdesc,count,search); - from=numdesc+1; - } - - 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); - return 1; - } - else if(atoi(answer)>=1 && atoi(answer)<=numdesc) - { - char *split=answer,*num; - - while((num=strsep(&split," ,"))!=NULL) - if(atoi(num)>=1 && atoi(num)<=numdesc) - keyserver_work(GET,NULL,&desc[atoi(num)-1],1); - - m_free(answer); - return 1; - } - - 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. */ -static void -keyserver_search_prompt(IOBUF buffer,const char *searchstr) -{ - int i=0,validcount=0,started=0,count=1; - unsigned int maxlen,buflen; - KEYDB_SEARCH_DESC *desc; - byte *line=NULL; - /* TODO: Something other than 23? That's 24-1 (the prompt). */ - int maxlines=23,numlines=0; - - desc=m_alloc(count*sizeof(KEYDB_SEARCH_DESC)); - - for(;;) - { - struct keyrec *keyrec; - int rl; - - maxlen=1024; - rl=iobuf_read_line(buffer,&line,&buflen,&maxlen); - - /* Look for an info: line. The only current info: values - defined are the version and key count. */ - if(!started && rl>0 && ascii_strncasecmp("info:",line,5)==0) - { - char *tok,*str=&line[5]; - - if((tok=strsep(&str,":"))!=NULL) - { - int version; - - if(sscanf(tok,"%d",&version)!=1) - version=1; - - if(version!=1) - { - log_error(_("invalid keyserver protocol " - "(us %d!=handler %d)\n"),1,version); - break; - } - } - - if((tok=strsep(&str,":"))!=NULL && sscanf(tok,"%d",&count)==1) - { - if(count==0) - goto notfound; - else if(count<0) - count=10; - else - validcount=1; - - desc=m_realloc(desc,count*sizeof(KEYDB_SEARCH_DESC)); - } - - started=1; - continue; - } - - if(rl==0) - { - keyrec=parse_keyrec(NULL); - - if(keyrec==NULL) - { - if(i==0) - { - count=0; - break; - } - - if(i!=count) - validcount=0; - - for(;;) - { - if(show_prompt(desc,i,validcount?count:0,searchstr)) - break; - validcount=0; - } - - break; - } - } - else - keyrec=parse_keyrec(line); - - if(i==count) - { - /* keyserver helper sent more keys than they claimed in the - info: line. */ - count+=10; - desc=m_realloc(desc,count*sizeof(KEYDB_SEARCH_DESC)); - validcount=0; - } - - if(keyrec) - { - desc[i]=keyrec->desc; - - if(numlines+keyrec->lines>maxlines) - { - if(show_prompt(desc,i,validcount?count:0,searchstr)) - break; - else - numlines=0; - } - - print_keyrec(i+1,keyrec); - numlines+=keyrec->lines; - iobuf_close(keyrec->uidbuf); - m_free(keyrec); - - started=1; - i++; - } - } - - 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; - } -} - -#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,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 - - /* Push the libexecdir into path. If DISABLE_KEYSERVER_PATH is set, - use the 0 arg to replace the path. */ -#ifdef DISABLE_KEYSERVER_PATH - set_exec_path(GNUPG_LIBEXECDIR,0); -#else - set_exec_path(GNUPG_LIBEXECDIR,opt.exec_path_set); -#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); - - if(opt.keyserver_opaque) - fprintf(spawn->tochild,"OPAQUE %s\n",opt.keyserver_opaque); - else - { - if(opt.keyserver_host) - fprintf(spawn->tochild,"HOST %s\n",opt.keyserver_host); - - if(opt.keyserver_port) - 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, - opt.keyserver_options.export_options)==-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(;;) - { - int plen; - char *ptr; - - maxlen=1024; - if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0) - { - ret=G10ERR_READ_FILE; - goto fail; /* i.e. EOF */ - } - - ptr=line; - - /* remove trailing whitespace */ - plen=strlen(ptr); - while(plen>0 && isspace(ptr[plen-1])) - plen--; - plen[ptr]='\0'; - - if(*ptr=='\0') - break; - - if(ascii_strncasecmp(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_strncasecmp(ptr,"PROGRAM ",8)==0) - { - if(ascii_strncasecmp(&ptr[8],VERSION,strlen(VERSION))!=0) - log_info(_("WARNING: keyserver handler from a different " - "version of GnuPG (%s)\n"),&ptr[8]); - } - else if(ascii_strncasecmp(ptr,"OPTION OUTOFBAND",16)==0) - outofband=1; /* Currently the only OPTION */ - } - - 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,stats_handle, - opt.keyserver_options.import_options); - - import_print_stats(stats_handle); - import_release_stats_handle(stats_handle); - - break; - } - - /* Nothing to do here */ - case SEND: - break; - - case SEARCH: - { - keyserver_search_prompt(spawn->fromchild,searchstr); - - break; - } - - default: - log_fatal(_("no keyserver action!\n")); - break; - } - - fail: - m_free(line); - - *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) - { - log_error(_("no keyserver known (use option --keyserver)\n")); - return G10ERR_BAD_URI; - } - -#ifdef DISABLE_KEYSERVER_HELPERS - - log_error(_("external keyserver calls are not supported in this build\n")); - return G10ERR_KEYSERVER; - -#else - /* Spawn a handler */ - - 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); - break; - - case KEYSERVER_VERSION_ERROR: - log_error(_("gpgkeys_%s does not support handler version %d\n"), - opt.keyserver_scheme,KEYSERVER_PROTO_VERSION); - break; - - 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; -#endif /* ! DISABLE_KEYSERVER_HELPERS*/ -} - -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(_("refreshing 1 key from %s\n"),opt.keyserver_uri); - else - log_info(_("refreshing %d keys from %s\n"),count,opt.keyserver_uri); - - 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; -} diff --git a/g10/main.h b/g10/main.h deleted file mode 100644 index f16355bc8..000000000 --- a/g10/main.h +++ /dev/null @@ -1,224 +0,0 @@ -/* main.h - * 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 - */ -#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 CIPHER_ALGO_CAST5 -#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL -#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1 -#define DEFAULT_COMPRESS_ALGO 1 - -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; -}; - -/*-- g10.c --*/ -extern int g10_errors_seen; - -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) - void g10_exit(int rc) __attribute__ ((noreturn)); -#else - void g10_exit(int rc); -#endif -void print_pubkey_algo_note( int algo ); -void print_cipher_algo_note( int algo ); -void print_digest_algo_note( int algo ); - -/*-- armor.c --*/ -char *make_radix64_string( const byte *data, size_t len ); - -/*-- misc.c --*/ -void trap_unaligned(void); -int disable_core_dumps(void); -u16 checksum_u16( unsigned n ); -u16 checksum( byte *p, unsigned n ); -u16 checksum_mpi( MPI a ); -u32 buffer_to_u32( const byte *buffer ); -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 ); -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 ); - -/*-- encode.c --*/ -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, 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_revocation_keys (PKT_public_key *pk, PKT_signature *sig); -int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); -int check_key_signature2( KBNODE root, KBNODE node, - int *is_selfsig, u32 *r_expiredate, int *r_expired ); - -/*-- delkey.c --*/ -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 ); -void show_basic_key_info (KBNODE keyblock); - -/*-- 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 --*/ -int overwrite_filep( const char *fname ); -char *make_outfile_name( const char *iname ); -char *ask_outfile_name( const char *name, size_t namelen ); -int open_outfile( const char *iname, int mode, IOBUF *a ); -IOBUF open_sigfile( const char *iname ); -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, MD_HANDLE md, - int hash_algo, unsigned nbits, int v3compathack ); - -/*-- comment.c --*/ -KBNODE make_comment_node( const char *s ); -KBNODE make_mpi_comment_node( const char *s, MPI a ); - -/*-- import.c --*/ -#define IMPORT_ALLOW_LOCAL_SIGS 1 -#define IMPORT_REPAIR_HKP_SUBKEY_BUG 2 -#define IMPORT_FAST_IMPORT 4 - -int parse_import_options(char *str,unsigned int *options); -void import_keys( char **fnames, int nnames, - void *stats_hd, unsigned int options ); -int import_keys_stream( IOBUF inp, - void *stats_hd, unsigned int options ); -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 --*/ -#define EXPORT_INCLUDE_NON_RFC 1 -#define EXPORT_INCLUDE_LOCAL_SIGS 2 -#define EXPORT_INCLUDE_ATTRIBUTES 4 -#define EXPORT_INCLUDE_SENSITIVE_REVKEYS 8 - -int parse_export_options(char *str,unsigned int *options); -int export_pubkeys( STRLIST users, unsigned int options ); -int export_pubkeys_stream( IOBUF out, STRLIST users, unsigned int options ); -int export_seckeys( STRLIST users ); -int export_secsubkeys( STRLIST users ); - -/* dearmor.c --*/ -int dearmor_file( const char *fname ); -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 ); -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( 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 /*G10_MAIN_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c deleted file mode 100644 index f9be17600..000000000 --- a/g10/mainproc.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* mainproc.c - handle packets - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <time.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 "keyserver-internal.h" -#include "photoid.h" - - -struct kidlist_item { - struct kidlist_item *next; - u32 kid[2]; - int pubkey_algo; - int reason; -}; - - - -/**************** - * Structure to hold the context - */ -typedef struct mainproc_context *CTX; -struct mainproc_context { - struct mainproc_context *anchor; /* may be useful in the future */ - PKT_public_key *last_pubkey; - PKT_secret_key *last_seckey; - PKT_user_id *last_user_id; - md_filter_context_t mfx; - int sigs_only; /* process only signatures and reject all other stuff */ - int encrypt_only; /* process only encrytion messages */ - STRLIST signed_data; - const char *sigfilename; - DEK *dek; - int last_was_session_key; - KBNODE list; /* the current list of packets */ - int have_data; - IOBUF iobuf; /* used to get the filename etc. */ - int trustletter; /* temp usage in list_node */ - ulong local_id; /* ditto */ - struct kidlist_item *pkenc_list; /* list of encryption packets */ - struct { - int op; - int stop_now; - } pipemode; -}; - - -static int do_proc_packets( CTX c, IOBUF a ); - -static void list_node( CTX c, KBNODE node ); -static void proc_tree( CTX c, KBNODE node ); - - -static void -release_list( CTX c ) -{ - if( !c->list ) - return; - proc_tree(c, c->list ); - release_kbnode( c->list ); - while( c->pkenc_list ) { - struct kidlist_item *tmp = c->pkenc_list->next; - m_free( c->pkenc_list ); - c->pkenc_list = tmp; - } - 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; -} - - -static int -add_onepass_sig( CTX c, PACKET *pkt ) -{ - KBNODE node; - - if( c->list ) { /* add another packet */ - /* 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 ); - } - else - add_kbnode( c->list, new_kbnode( pkt )); - } - else /* insert the first one */ - c->list = node = new_kbnode( pkt ); - - return 1; -} - - -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 ) -{ - if( !c->list ) { - log_error("orphaned user ID\n" ); - return 0; - } - add_kbnode( c->list, new_kbnode( pkt ) ); - return 1; -} - -static int -add_subkey( CTX c, PACKET *pkt ) -{ - if( !c->list ) { - log_error("subkey w/o mainkey\n" ); - return 0; - } - add_kbnode( c->list, new_kbnode( pkt ) ); - return 1; -} - -static int -add_ring_trust( CTX c, PACKET *pkt ) -{ - if( !c->list ) { - log_error("ring trust w/o key\n" ); - return 0; - } - add_kbnode( c->list, new_kbnode( pkt ) ); - return 1; -} - - -static int -add_signature( CTX c, PACKET *pkt ) -{ - KBNODE node; - - if( pkt->pkttype == PKT_SIGNATURE && !c->list ) { - /* This is the first signature for the following datafile. - * GPG does not write such packets; instead it always uses - * onepass-sig packets. The drawback of PGP's method - * of prepending the signature to the data is - * that it is not possible to make a signature from data read - * from stdin. (GPG is able to read PGP stuff anyway.) */ - node = new_kbnode( pkt ); - c->list = node; - return 1; - } - else if( !c->list ) - return 0; /* oops (invalid packet sequence)*/ - else if( !c->list->pkt ) - BUG(); /* so nicht */ - - /* add a new signature node id at the end */ - node = new_kbnode( pkt ); - add_kbnode( c->list, node ); - return 1; -} - -static void -symkey_decrypt_sesskey( DEK *dek, byte *sesskey, size_t slen ) -{ - CIPHER_HANDLE hd; - int n; - - if ( slen < 17 || slen > 33 ) { - log_error ( _("weird size for an encrypted session key (%d)\n"), - (int)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; - } - n = cipher_get_keylen (sesskey[0]) / 8; - if (n > DIM(dek->key)) - BUG (); - /* 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 ) -{ - PKT_symkey_enc *enc; - - enc = pkt->pkt.symkey_enc; - 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; - 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); -} - -static void -proc_pubkey_enc( CTX c, PACKET *pkt ) -{ - PKT_pubkey_enc *enc; - int result = 0; - - /* check whether the secret key is available and store in this case */ - c->last_was_session_key = 1; - enc = pkt->pkt.pubkey_enc; - /*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/ - /* Hmmm: why do I have this algo check here - anyway there is - * function to check it. */ - if( opt.verbose ) - log_info(_("public key is %08lX\n"), (ulong)enc->keyid[1] ); - - if( is_status_enabled() ) { - char buf[50]; - sprintf(buf, "%08lX%08lX %d 0", - (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo ); - write_status_text( STATUS_ENC_TO, buf ); - } - - 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 = m_alloc_secure_clear( sizeof *c->dek ); - if( (result = get_session_key( enc, c->dek )) ) { - /* error: delete the DEK */ - m_free(c->dek); c->dek = NULL; - } - } - } - else - result = G10ERR_NO_SECKEY; - } - else - result = G10ERR_PUBKEY_ALGO; - - if( result == -1 ) - ; - 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); -} - - - -/**************** - * Print the list of public key encrypted packets which we could - * not decrypt. - */ -static void -print_pkenc_list( struct kidlist_item *list, int failed ) -{ - for( ; list; list = list->next ) { - 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 = "[?]"; - pk->pubkey_algo = list->pubkey_algo; - if( !get_pubkey( pk, list->kid ) ) { - size_t n; - char *p; - log_info( _("encrypted with %u-bit %s key, ID %08lX, created %s\n"), - nbits_from_pk( pk ), algstr, (ulong)list->kid[1], - strtimestamp(pk->timestamp) ); - fputs(" \"", log_stream() ); - p = get_user_id( list->kid, &n ); - print_utf8_string2 ( log_stream(), p, n, '"' ); - m_free(p); - fputs("\"\n", log_stream() ); - } - else { - log_info(_("encrypted with %s key, ID %08lX\n"), - algstr, (ulong) list->kid[1] ); - } - free_public_key( pk ); - - if( list->reason == G10ERR_NO_SECKEY ) { - if( is_status_enabled() ) { - char buf[20]; - sprintf(buf,"%08lX%08lX", (ulong)list->kid[0], - (ulong)list->kid[1] ); - write_status_text( STATUS_NO_SECKEY, buf ); - } - } - else if (list->reason) - log_info(_("public key decryption failed: %s\n"), - g10_errstr(list->reason)); - } -} - - -static void -proc_encrypted( CTX c, PACKET *pkt ) -{ - int result = 0; - - if (!opt.quiet) { - print_pkenc_list ( c->pkenc_list, 1 ); - print_pkenc_list ( c->pkenc_list, 0 ); - } - - write_status( STATUS_BEGIN_DECRYPTION ); - - /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ - if( opt.list_only ) - result = -1; - else if( !c->dek && !c->last_was_session_key ) { - 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 = G10ERR_NO_SECKEY; - if( !result ) - result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); - - m_free(c->dek); c->dek = NULL; - if( result == -1 ) - ; - else if( !result || (result==G10ERR_BAD_SIGN && opt.ignore_mdc_error)) { - write_status( STATUS_DECRYPTION_OKAY ); - if( opt.verbose > 1 ) - log_info(_("decryption okay\n")); - if( pkt->pkt.encrypted->mdc_method && !result ) - write_status( STATUS_GOODMDC ); - else if(!opt.no_mdc_warn) - log_info ("WARNING: message was not integrity protected\n"); - } - else if( result == G10ERR_BAD_SIGN ) { - log_error(_("WARNING: encrypted message has been manipulated!\n")); - write_status( STATUS_BADMDC ); - write_status( STATUS_DECRYPTION_FAILED ); - } - else { - write_status( STATUS_DECRYPTION_FAILED ); - 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)*/ - } - free_packet(pkt); - c->last_was_session_key = 0; - write_status( STATUS_END_DECRYPTION ); -} - - - -static void -proc_plaintext( CTX c, PACKET *pkt ) -{ - PKT_plaintext *pt = pkt->pkt.plaintext; - int any, clearsig, only_md5, rc; - KBNODE n; - - if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) - log_info(_("NOTE: sender requested \"for-your-eyes-only\"\n")); - else if( opt.verbose ) - log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name); - free_md_filter_context( &c->mfx ); - 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 - * Should we assume that plaintext in mode 't' has always sigclass 1?? - * See: Russ Allbery's mail 1999-02-09 - */ - any = clearsig = only_md5 = 0; - for(n=c->list; n; n = n->next ) { - if( n->pkt->pkttype == PKT_ONEPASS_SIG ) { - if( 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 - == DIGEST_ALGO_MD5 ) - only_md5 = 1; - else - only_md5 = 0; - any = 1; - } - if( n->pkt->pkt.onepass_sig->sig_class != 0x01 ) - only_md5 = 0; - } - 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 */ - 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 - * catch those mails which are armored. To catch the non-armored - * 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 = md_open( DIGEST_ALGO_MD5, 0); - } - if ( DBG_HASHING ) { - md_start_debug( c->mfx.md, "verify" ); - if ( c->mfx.md2 ) - md_start_debug( c->mfx.md2, "verify2" ); - } - 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", 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; -} - - -static int -proc_compressed_cb( IOBUF a, void *info ) -{ - return proc_signature_packets( info, a, ((CTX)info)->signed_data, - ((CTX)info)->sigfilename ); -} - -static int -proc_encrypt_cb( IOBUF a, void *info ) -{ - return proc_encryption_packets( info, a ); -} - -static void -proc_compressed( CTX c, PACKET *pkt ) -{ - PKT_compressed *zd = pkt->pkt.compressed; - int rc; - - /*printf("zip: compressed data packet\n");*/ - if( c->sigs_only ) - rc = handle_compressed( c, zd, proc_compressed_cb, c ); - else if( c->encrypt_only ) - rc = handle_compressed( c, zd, proc_encrypt_cb, c ); - else - rc = handle_compressed( c, zd, NULL, NULL ); - if( rc ) - log_error("uncompressing failed: %s\n", g10_errstr(rc)); - free_packet(pkt); - c->last_was_session_key = 0; -} - -/**************** - * check the signature - * Returns: 0 = valid signature or an error code - */ -static int -do_check_sig( CTX c, KBNODE node, int *is_selfsig, int *is_expkey ) -{ - PKT_signature *sig; - 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 ) - *is_selfsig = 0; - sig = node->pkt->pkt.signature; - - algo = sig->digest_algo; - if( (rc=check_digest_algo(algo)) ) - return rc; - - if( sig->sig_class == 0x00 ) { - if( c->mfx.md ) - md = md_copy( c->mfx.md ); - else /* detached signature */ - 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 = 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 = 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 == 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 ); - } - else if( sig->sig_class == 0x20 ) { - log_info(_("standalone revocation - " - "use \"gpg --import\" to apply\n")); - return G10ERR_NOT_PROCESSED; - } - else { - log_error("invalid root packet for sigclass %02x\n", - sig->sig_class); - return G10ERR_SIG_CLASS; - } - } - else - 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; -} - - -static void -print_userid( PACKET *pkt ) -{ - if( !pkt ) - BUG(); - if( pkt->pkttype != PKT_USER_ID ) { - printf("ERROR: unexpected packet type %d", pkt->pkttype ); - return; - } - if( opt.with_colons ) - { - 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 ); -} - - -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,SIGSUBPKT_NOTATION,&n,&seq,NULL))) { - if( n < 8 ) { - log_info(_("WARNING: invalid notation data found\n")); - return; - } - if( !(*p & 0x80) ) - return; /* not human readable */ - n1 = (p[4] << 8) | p[5]; - n2 = (p[6] << 8) | p[7]; - p += 8; - if( 8+n1+n2 != n ) { - log_info(_("WARNING: invalid notation data found\n")); - return; - } - log_info(_("Notation: ") ); - print_string( log_stream(), p, n1, 0 ); - 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 ); - } - - 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 whether the key of this signature has some - * notation data */ - - /* TODO */ -} - - -/**************** - * List the certificate in a user friendly way - */ - -static void -list_node( CTX c, KBNODE node ) -{ - int any=0; - int mainkey; - - if( !node ) - ; - else if( (mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY) ) - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - PKT_public_key *pk = node->pkt->pkt.public_key; - - if( opt.with_colons ) { - u32 keyid[2]; - keyid_from_pk( pk, keyid ); - if( mainkey ) { - c->local_id = pk->local_id; - c->trustletter = opt.fast_list_mode? - 0 : get_validity_info( pk, NULL ); - } - printf("%s:", mainkey? "pub":"sub" ); - if( c->trustletter ) - putchar( c->trustletter ); - printf(":%u:%d:%08lX%08lX:%s:%s:", - nbits_from_pk( pk ), - pk->pubkey_algo, - (ulong)keyid[0],(ulong)keyid[1], - colon_datestr_from_pk( pk ), - colon_strtime (pk->expiredate) ); - if( c->local_id ) - printf("%lu", c->local_id ); - putchar(':'); - 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, 0 ); - printf("rtv:1:%u:\n", - node->next->pkt->pkt.ring_trust->trustval ); - } - } - else - printf("%s %4u%c/%08lX %s ", - mainkey? "pub":"sub", - nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), - (ulong)keyid_from_pk( pk, NULL ), - datestr_from_pk( pk ) ); - - if( mainkey ) { - /* and now list all userids with their signatures */ - for( node = node->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_SIGNATURE ) { - if( !any ) { - if( node->pkt->pkt.signature->sig_class == 0x20 ) - puts("[revoked]"); - else - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - else if( node->pkt->pkttype == PKT_USER_ID ) { - if( any ) { - if( opt.with_colons ) - printf("%s:::::::::", - node->pkt->pkt.user_id->attrib_data?"uat":"uid"); - else - printf( "uid%*s", 28, "" ); - } - print_userid( node->pkt ); - if( opt.with_colons ) - putchar(':'); - putchar('\n'); - if( opt.fingerprint && !any ) - print_fingerprint( pk, NULL, 0 ); - if( node->next - && node->next->pkt->pkttype == PKT_RING_TRUST ) { - printf("rtv:2:%u:\n", - node->next->pkt->pkt.ring_trust->trustval ); - } - any=1; - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - if( !any ) { - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - } - } - else if( pk->expiredate ) { /* of subkey */ - printf(_(" [expires: %s]"), expirestr_from_pk( pk ) ); - } - - if( !any ) - putchar('\n'); - if( !mainkey && opt.fingerprint > 1 ) - print_fingerprint( pk, NULL, 0 ); - } - else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *sk = node->pkt->pkt.secret_key; - - if( opt.with_colons ) { - u32 keyid[2]; - keyid_from_sk( sk, keyid ); - printf("%s::%u:%d:%08lX%08lX:%s:%s:::", - mainkey? "sec":"ssb", - 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 */ ); - } - else - printf("%s %4u%c/%08lX %s ", - mainkey? "sec":"ssb", - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (ulong)keyid_from_sk( sk, NULL ), - datestr_from_sk( sk ) ); - if( mainkey ) { - /* and now list all userids with their signatures */ - for( node = node->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_SIGNATURE ) { - if( !any ) { - if( node->pkt->pkt.signature->sig_class == 0x20 ) - puts("[revoked]"); - else - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - else if( node->pkt->pkttype == PKT_USER_ID ) { - if( any ) { - if( opt.with_colons ) - printf("%s:::::::::", - node->pkt->pkt.user_id->attrib_data?"uat":"uid"); - else - printf( "uid%*s", 28, "" ); - } - print_userid( node->pkt ); - if( opt.with_colons ) - putchar(':'); - putchar('\n'); - if( opt.fingerprint && !any ) - print_fingerprint( NULL, sk, 0 ); - any=1; - } - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - if( !any ) { - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - } - } - if( !any ) - putchar('\n'); - if( !mainkey && opt.fingerprint > 1 ) - print_fingerprint( NULL, sk, 0 ); - } - else if( node->pkt->pkttype == PKT_SIGNATURE ) { - PKT_signature *sig = node->pkt->pkt.signature; - int is_selfsig = 0; - int rc2=0; - size_t n; - char *p; - int sigrc = ' '; - - if( !opt.list_sigs ) - return; - - if( sig->sig_class == 0x20 || sig->sig_class == 0x30 ) - fputs("rev", stdout); - else - fputs("sig", stdout); - if( opt.check_sigs ) { - fflush(stdout); - switch( (rc2=do_check_sig( c, node, &is_selfsig, NULL )) ) { - case 0: sigrc = '!'; break; - case G10ERR_BAD_SIGN: sigrc = '-'; break; - case G10ERR_NO_PUBKEY: - case G10ERR_UNU_PUBKEY: sigrc = '?'; break; - default: sigrc = '%'; break; - } - } - else { /* check whether this is a self signature */ - u32 keyid[2]; - - if( c->list->pkt->pkttype == PKT_PUBLIC_KEY - || c->list->pkt->pkttype == PKT_SECRET_KEY ) { - if( c->list->pkt->pkttype == PKT_PUBLIC_KEY ) - keyid_from_pk( c->list->pkt->pkt.public_key, keyid ); - else - keyid_from_sk( c->list->pkt->pkt.secret_key, keyid ); - - if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) - is_selfsig = 1; - } - } - if( opt.with_colons ) { - putchar(':'); - if( sigrc != ' ' ) - putchar(sigrc); - printf("::%d:%08lX%08lX:%s::::", sig->pubkey_algo, - (ulong)sig->keyid[0], - (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] ", g10_errstr(rc2) ); - else if( sigrc == '?' ) - ; - else if( is_selfsig ) { - if( opt.with_colons ) - putchar(':'); - fputs( sig->sig_class == 0x18? "[keybind]":"[selfsig]", stdout); - if( opt.with_colons ) - putchar(':'); - } - else if( !opt.fast_list_mode ) { - p = get_user_id( sig->keyid, &n ); - print_string( stdout, p, n, opt.with_colons ); - m_free(p); - } - if( opt.with_colons ) - printf(":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); - putchar('\n'); - } - else - log_error("invalid node with packet of type %d\n", node->pkt->pkttype); -} - - - -int -proc_packets( void *anchor, IOBUF a ) -{ - int rc; - CTX c = m_alloc_clear( sizeof *c ); - - c->anchor = anchor; - rc = do_proc_packets( c, a ); - m_free( c ); - return rc; -} - - - -int -proc_signature_packets( void *anchor, IOBUF a, - STRLIST signedfiles, const char *sigfilename ) -{ - CTX c = m_alloc_clear( sizeof *c ); - int rc; - - c->anchor = anchor; - c->sigs_only = 1; - c->signed_data = signedfiles; - c->sigfilename = sigfilename; - rc = do_proc_packets( c, a ); - m_free( c ); - return rc; -} - -int -proc_encryption_packets( void *anchor, IOBUF a ) -{ - CTX c = m_alloc_clear( sizeof *c ); - int rc; - - c->anchor = anchor; - c->encrypt_only = 1; - rc = do_proc_packets( c, a ); - m_free( c ); - return rc; -} - - -int -do_proc_packets( CTX c, IOBUF a ) -{ - 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)) != -1 ) { - any_data = 1; - if( rc ) { - free_packet(pkt); - /* 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; - } - newpkt = -1; - if( opt.list_packets ) { - switch( pkt->pkttype ) { - case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; - case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; - case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; - case PKT_COMPRESSED: proc_compressed( c, pkt ); break; - default: newpkt = 0; break; - } - } - else if( c->sigs_only ) { - switch( pkt->pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - case PKT_USER_ID: - case PKT_SYMKEY_ENC: - case PKT_PUBKEY_ENC: - case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: - 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; - } - } - else if( c->encrypt_only ) { - switch( pkt->pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - case PKT_USER_ID: - 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; - case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; - case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted( 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; - } - } - else { - switch( pkt->pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - release_list( c ); - c->list = new_kbnode( pkt ); - newpkt = 1; - break; - case PKT_PUBLIC_SUBKEY: - case PKT_SECRET_SUBKEY: - newpkt = add_subkey( c, pkt ); - break; - case PKT_USER_ID: newpkt = add_user_id( c, pkt ); break; - case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; - case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break; - case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; - case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted( 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; - case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break; - default: newpkt = 0; break; - } - } - /* 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 = 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 == G10ERR_INVALID_PACKET ) - write_status_text( STATUS_NODATA, "3" ); - if( any_data ) - rc = 0; - else if( rc == -1 ) - write_status_text( STATUS_NODATA, "2" ); - - - leave: - release_list( c ); - m_free(c->dek); - free_packet( pkt ); - m_free( pkt ); - free_md_filter_context( &c->mfx ); - return rc; -} - - -static int -check_sig_and_print( CTX c, KBNODE node ) -{ - PKT_signature *sig = node->pkt->pkt.signature; - const char *astr, *tstr; - 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 = 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, &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 == G10ERR_BAD_SIGN ) { - KBNODE un, keyblock; - 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 ); - - sprintf (keyid_str, "%08lX%08lX [uncertain] ", - (ulong)sig->keyid[0], (ulong)sig->keyid[1]); - - /* find and print the primary user ID */ - for( un=keyblock; un; un = un->next ) { - if( un->pkt->pkttype != PKT_USER_ID ) - continue; - if ( !un->pkt->pkt.user_id->created ) - continue; - if ( un->pkt->pkt.user_id->is_revoked ) - continue; - if ( un->pkt->pkt.user_id->is_expired ) - continue; - if ( !un->pkt->pkt.user_id->is_primary ) - continue; - /* We want the textual user ID here */ - if ( un->pkt->pkt.user_id->attrib_data ) - 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() ); - count++; - } - if( !count ) { /* just in case that we have no valid textual - userid */ - /* Try for an invalid textual userid */ - for( un=keyblock; un; un = un->next ) { - if( un->pkt->pkttype == PKT_USER_ID && - !un->pkt->pkt.user_id->attrib_data ) - break; - } - - /* Try for any userid at all */ - if(!un) { - 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 \"")); - 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 ) { - PKT_public_key *pk=NULL; - for( un=keyblock; un; un = un->next ) { - if(un->pkt->pkttype==PKT_PUBLIC_KEY) - pk=un->pkt->pkt.public_key; - if( un->pkt->pkttype != PKT_USER_ID ) - continue; - if ( un->pkt->pkt.user_id->is_revoked ) - continue; - if ( un->pkt->pkt.user_id->is_expired ) - continue; - /* Only skip textual primaries */ - if ( un->pkt->pkt.user_id->is_primary && - !un->pkt->pkt.user_id->attrib_data ) - continue; - - if(opt.show_photos && un->pkt->pkt.user_id->attrib_data) - show_photos(un->pkt->pkt.user_id->attribs, - un->pkt->pkt.user_id->numattribs,pk,NULL); - - 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 = m_alloc_clear( sizeof *pk ); - - if( !get_pubkey( pk, sig->keyid ) ) { - byte array[MAX_FINGERPRINT_LEN], *p; - 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 %lu", - strtimestamp( sig->timestamp ), - (ulong)sig->timestamp, - (ulong)sig->expiredate ); - write_status_text( STATUS_VALIDSIG, buf ); - } - free_public_key( pk ); - } - - 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 ) - g10_errors_seen = 1; - if( opt.batch && rc ) - g10_exit(1); - } - else { - char buf[50]; - sprintf(buf, "%08lX%08lX %d %d %02x %lu %d", - (ulong)sig->keyid[0], (ulong)sig->keyid[1], - sig->pubkey_algo, sig->digest_algo, - sig->sig_class, (ulong)sig->timestamp, rc ); - write_status_text( STATUS_ERRSIG, buf ); - if( rc == G10ERR_NO_PUBKEY ) { - buf[16] = 0; - write_status_text( STATUS_NO_PUBKEY, buf ); - } - if( rc != G10ERR_NOT_PROCESSED ) - log_error(_("Can't check signature: %s\n"), g10_errstr(rc) ); - } - return rc; -} - - -/**************** - * Process the tree which starts at node - */ -static void -proc_tree( CTX c, KBNODE node ) -{ - KBNODE n1; - int rc; - - 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 - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - merge_keys_and_selfsig( node ); - list_node( c, node ); - } - else if( node->pkt->pkttype == PKT_SECRET_KEY ) { - merge_keys_and_selfsig( node ); - list_node( c, node ); - } - else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { - /* check all signatures */ - if( !c->have_data ) { - free_md_filter_context( &c->mfx ); - /* prepare to create all requested message digests */ - 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 )); ) { - md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo); - } - /* ask for file and hash it */ - if( c->sigs_only ) { - rc = hash_datafiles( c->mfx.md, NULL, - c->signed_data, c->sigfilename, - n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); - } - else { - rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, - 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", 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; - - if( sig->sig_class != 0x00 && sig->sig_class != 0x01 ) - log_info(_("standalone signature of class 0x%02x\n"), - sig->sig_class); - else if( !c->have_data ) { - /* detached signature */ - free_md_filter_context( &c->mfx ); - c->mfx.md = md_open(sig->digest_algo, 0); - if( !opt.pgp2_workarounds ) - ; - else if( sig->digest_algo == DIGEST_ALGO_MD5 - && is_RSA( sig->pubkey_algo ) ) { - /* enable a workaround for a pgp2 bug */ - c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0 ); - } - 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 = md_open( sig->digest_algo, 0 ); - } - #if 0 /* workaround disabled */ - /* Here we have another hack to work around a pgp 2 bug - * It works by not using the textmode for detached signatures; - * this will let the first signature check (on md) fail - * but the second one (on md2) which adds an extra CR should - * then produce the "correct" hash. This is very, very ugly - * hack but it may help in some cases (and break others) - */ - /* 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, - (sig->sig_class == 0x01) ); - } - else { - rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, - iobuf_get_real_fname(c->iobuf), - (sig->sig_class == 0x01) ); - } - if( 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; - } - 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")); - - for( n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )) ) - check_sig_and_print( c, n1 ); - } - else { - dump_kbnode (c->list); - log_error(_("invalid root packet detected in proc_tree()\n")); - dump_kbnode (node); - } -} - - - - diff --git a/g10/misc.c b/g10/misc.c deleted file mode 100644 index ae553eb47..000000000 --- a/g10/misc.c +++ /dev/null @@ -1,548 +0,0 @@ -/* misc.c - miscellaneous functions - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#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 "util.h" -#include "main.h" -#include "photoid.h" -#include "options.h" -#include "i18n.h" - - -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 -static int -setsysinfo(unsigned long op, void *buffer, unsigned long size, - int *start, void *arg, unsigned long flag) -{ - return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag); -} - -void -trap_unaligned(void) -{ - unsigned int buf[2]; - - buf[0] = SSIN_UACPROC; - buf[1] = UAC_SIGBUS | UAC_NOPRINT; - setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0); -} -#else -void -trap_unaligned(void) -{ /* dummy */ -} -#endif - - -int -disable_core_dumps() -{ - #ifdef HAVE_DOSISH_SYSTEM - return 0; - #else - #ifdef HAVE_SETRLIMIT - struct rlimit limit; - - limit.rlim_cur = 0; - limit.rlim_max = 0; - if( !setrlimit( RLIMIT_CORE, &limit ) ) - return 0; - if( errno != EINVAL && errno != ENOSYS ) - log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) ); - #endif - return 1; - #endif -} - - - -u16 -checksum_u16( unsigned n ) -{ - u16 a; - - a = (n >> 8) & 0xff; - a += n & 0xff; - return a; -} - - -u16 -checksum( byte *p, unsigned n ) -{ - u16 a; - - for(a=0; n; n-- ) - a += *p++; - return a; -} - -u16 -checksum_mpi( MPI a ) -{ - u16 csum; - byte *buffer; - unsigned nbytes; - unsigned nbits; - - buffer = mpi_get_buffer( a, &nbytes, NULL ); - nbits = mpi_get_nbits(a); - csum = checksum_u16( nbits ); - csum += checksum( buffer, nbytes ); - m_free( buffer ); - return csum; -} - -u32 -buffer_to_u32( const byte *buffer ) -{ - unsigned long a; - a = *buffer << 24; - a |= buffer[1] << 16; - a |= buffer[2] << 8; - a |= buffer[3]; - return a; -} - - -static void -no_exp_algo(void) -{ - static int did_note = 0; - - if( !did_note ) { - did_note = 1; - log_info(_("Experimental algorithms should not be used!\n")); - } -} - -void -print_pubkey_algo_note( int algo ) -{ - if( algo >= 100 && algo <= 110 ) - no_exp_algo(); -} - -void -print_cipher_algo_note( int algo ) -{ - if( algo >= 100 && algo <= 110 ) - no_exp_algo(); - 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 { - static int did_note = 0; - - if( !did_note ) { - did_note = 1; - log_info(_("this cipher algorithm is deprecated; " - "please use a more standard one!\n")); - } - } -} - -void -print_digest_algo_note( int algo ) -{ - if( algo >= 100 && algo <= 110 ) - no_exp_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 - * openPGP contraints for the algo ID. - */ -int -openpgp_cipher_test_algo( int algo ) -{ - if( algo < 0 || algo > 110 ) - return G10ERR_CIPHER_ALGO; - return check_cipher_algo(algo); -} - -int -openpgp_pk_test_algo( int algo, unsigned int usage_flags ) -{ - if( algo < 0 || algo > 110 ) - return G10ERR_PUBKEY_ALGO; - return check_pubkey_algo2( algo, usage_flags ); -} - -int -openpgp_pk_algo_usage ( int algo ) -{ - int use = 0; - - /* they are hardwired in gpg 1.0 */ - switch ( algo ) { - case PUBKEY_ALGO_RSA: - use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; - break; - case PUBKEY_ALGO_RSA_E: - use = PUBKEY_USAGE_ENC; - break; - case PUBKEY_ALGO_RSA_S: - use = PUBKEY_USAGE_SIG; - break; - case PUBKEY_ALGO_ELGAMAL_E: - use = PUBKEY_USAGE_ENC; - break; - case PUBKEY_ALGO_DSA: - use = PUBKEY_USAGE_SIG; - break; - case PUBKEY_ALGO_ELGAMAL: - use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; - break; - default: - break; - } - return use; -} - -int -openpgp_md_test_algo( int algo ) -{ - if( algo < 0 || algo > 110 ) - return G10ERR_DIGEST_ALGO; - return check_digest_algo(algo); -} - -/* Special warning for the IDEA cipher */ -void -idea_cipher_warn(int show) -{ - 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; - } -} - -/* 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) -{ - 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, (len=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 -hextobyte( const char *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; -} - -void -deprecated_warning(const char *configname,unsigned int configlineno, - const char *option,const char *repl1,const char *repl2) -{ - if(configname) - { - if(strncmp("--",option,2)==0) - option+=2; - - if(strncmp("--",repl1,2)==0) - repl1+=2; - - log_info(_("%s:%d: deprecated option \"%s\"\n"), - configname,configlineno,option); - } - 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="?"; - - switch(algo) - { - case 0: - s="Uncompressed"; - break; - - 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/openfile.c b/g10/openfile.c deleted file mode 100644 index 83c734dfd..000000000 --- a/g10/openfile.c +++ /dev/null @@ -1,362 +0,0 @@ -/* openfile.c - * Copyright (C) 1998, 1999, 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 <assert.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include "util.h" -#include "memory.h" -#include "ttyio.h" -#include "options.h" -#include "main.h" -#include "status.h" -#include "i18n.h" - -#ifdef USE_ONLY_8DOT3 - #define SKELEXT ".skl" -#else - #define SKELEXT EXTSEP_S "skel" -#endif - -#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 - -#ifdef MKDIR_TAKES_ONE_ARG -# undef mkdir -# define mkdir(a,b) mkdir(a) -#endif - -/* FIXME: Implement opt.interactive. */ - -/**************** - * Check whether FNAME exists and ask if it's okay to overwrite an - * existing one. - * Returns: True: it's okay to overwrite or the file does not exist - * False: Do not overwrite - */ -int -overwrite_filep( const char *fname ) -{ - if( !fname || (*fname == '-' && !fname[1]) ) - return 1; /* writing to stdout is always okay */ - - if( access( fname, F_OK ) ) - return 1; /* does not exist */ - -#ifndef HAVE_DOSISH_SYSTEM - if ( !strcmp ( fname, "/dev/null" ) ) - return 1; /* does not do any harm */ -#endif - - /* fixme: add some backup stuff in case of overwrite */ - if( opt.answer_yes ) - return 1; - if( opt.answer_no || opt.batch ) - return 0; /* do not overwrite */ - - tty_printf(_("File `%s' exists. "), fname); - if( cpr_get_answer_is_yes("openfile.overwrite.okay", - _("Overwrite (y/N)? ")) ) - return 1; - return 0; -} - - -/**************** - * Strip know extensions from iname and return a newly allocated - * filename. Return NULL if we can't do that. - */ -char * -make_outfile_name( const char *iname ) -{ - size_t n; - - if( (!iname || (*iname=='-' && !iname[1]) )) - return m_strdup("-"); - - n = strlen(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, EXTSEP_S "sign") ) { - char *buf = m_strdup( iname ); - buf[n-5] = 0; - return buf; - } - - log_info(_("%s: unknown suffix\n"), iname ); - return NULL; -} - - -/**************** - * Ask for a outputfilename and use the given one as default. - * Return NULL if no file has been given or it is not possible to - * ask the user. - */ -char * -ask_outfile_name( const char *name, size_t namelen ) -{ - size_t n; - const char *s; - char *prompt; - char *fname; - char *defname; - - if( opt.batch ) - return NULL; - - s = _("Enter new filename"); - - n = strlen(s) + namelen + 10; - defname = name && namelen? make_printable_string( name, namelen, 0): NULL; - 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(); - m_free(prompt); - if( !*fname ) { - m_free( fname ); fname = NULL; - fname = defname; defname = NULL; - } - m_free(defname); - if (fname) - trim_spaces (fname); - return fname; -} - - - -/**************** - * Make an output filename for the inputfile INAME. - * Returns an IOBUF and an errorcode - * Mode 0 = use ".gpg" - * 1 = use ".asc" - * 2 = use ".sig" - */ -int -open_outfile( const char *iname, int mode, IOBUF *a ) -{ - int rc = 0; - - *a = NULL; - if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) { - if( !(*a = iobuf_create(NULL)) ) { - log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) ); - rc = G10ERR_CREATE_FILE; - } - else if( opt.verbose ) - log_info(_("writing to stdout\n")); - } - else { - char *buf=NULL; - const char *name; - - if( opt.dry_run ) - name = "/dev/null"; - else if( opt.outfile ) - name = opt.outfile; - else { - #ifdef USE_ONLY_8DOT3 - /* It is quite common DOS system to have only one dot in a - * a filename So if we have something like this, we simple - * replace the suffix execpt in cases where the suffix is - * larger than 3 characters and not the same as. - * We should really map the filenames to 8.3 but this tends to - * be more complicated and is probaly a duty of the filesystem - */ - char *dot; - const char *newsfx = mode==1 ? ".asc" : - mode==2 ? ".sig" : ".gpg"; - - buf = m_alloc(strlen(iname)+4+1); - strcpy(buf,iname); - dot = strchr(buf, '.' ); - if( dot && dot > buf && dot[1] && strlen(dot) <= 4 - && CMP_FILENAME(newsfx, dot) ) { - strcpy(dot, newsfx ); - } - else if( dot && !dot[1] ) /* don't duplicate a dot */ - strcpy( dot, newsfx+1 ); - else - strcat( buf, newsfx ); - #else - 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; - } - - 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 = G10ERR_CREATE_FILE; - } - else if( opt.verbose ) - log_info(_("writing to `%s'\n"), name ); - } - m_free(buf); - } - return rc; -} - - - -/**************** - * Try to open a file without the extension ".sig" or ".asc" - * Return NULL if such a file is not available. - */ -IOBUF -open_sigfile( const char *iname ) -{ - IOBUF a = NULL; - size_t len; - - if( iname && !(*iname == '-' && !iname[1]) ) { - len = strlen(iname); - 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 = m_strdup(iname); - buf[len-(buf[len-1]=='n'?5:4)] = 0 ; - a = iobuf_open( buf ); - if( a && opt.verbose ) - log_info(_("assuming signed data in `%s'\n"), buf ); - m_free(buf); - } - } - return a; -} - - -/**************** - * Copy the option file skeleton to the given directory. - */ -static void -copy_options_file( const char *destdir ) -{ - const char *datadir = GNUPG_DATADIR; - char *fname; - FILE *src, *dst; - int linefeeds=0; - int c; - mode_t oldmask; - - if( opt.dry_run ) - return; - - 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) ); - m_free(fname); - return; - } - strcpy(stpcpy(fname, destdir), DIRSEP_S "gpg" EXTSEP_S "conf" ); - oldmask=umask(077); - dst = fopen( fname, "w" ); - umask(oldmask); - if( !dst ) { - log_error(_("%s: can't create: %s\n"), fname, strerror(errno) ); - fclose( src ); - m_free(fname); - return; - } - - while( (c=getc(src)) != EOF ) { - if( linefeeds < 3 ) { - if( c == '\n' ) - linefeeds++; - } - else - putc( c, dst ); - } - fclose( dst ); - fclose( src ); - log_info(_("new configuration file `%s' created\n"), fname ); - m_free(fname); -} - - -void -try_make_homedir( const char *fname ) -{ - const char *defhome = GNUPG_HOMEDIR; - - /* Create the directory only if the supplied directory name - * is the same as the default one. This way we avoid to create - * arbitrary directories when a non-default homedirectory is used. - * 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 || opt.no_homedir_creation ) - return; - - if ( ( *defhome == '~' - && ( strlen(fname) >= strlen (defhome+1) - && !strcmp(fname+strlen(fname)-strlen(defhome+1), - defhome+1 ) )) - || ( *defhome != '~' - && !compare_filenames( fname, defhome ) ) - ) { - if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) ) - log_fatal( _("%s: can't create directory: %s\n"), - fname, strerror(errno) ); - else if( !opt.quiet ) - log_info( _("%s: directory created\n"), fname ); - copy_options_file( fname ); -/* log_info(_("you have to start GnuPG again, " */ -/* "so it can read the new configuration file\n") ); */ -/* g10_exit(1); */ - } -} diff --git a/g10/options.h b/g10/options.h deleted file mode 100644 index 6be587ab8..000000000 --- a/g10/options.h +++ /dev/null @@ -1,208 +0,0 @@ -/* options.h - * 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 - */ -#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 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: 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 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; - unsigned int emulate_bugs; /* bug emulation flags EMUBUG_xxxx */ - int shm_coprocess; - 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; - char *keyserver_uri; - char *keyserver_scheme; - char *keyserver_host; - char *keyserver_port; - char *keyserver_opaque; - 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; - unsigned int import_options; - unsigned int export_options; - STRLIST other; - } keyserver_options; - int exec_disable; - int exec_path_set; - unsigned int import_options; - unsigned int export_options; - char *def_preference_list; - prefitem_t *personal_cipher_prefs; - prefitem_t *personal_digest_prefs; - prefitem_t *personal_compress_prefs; - int no_perm_warn; - int no_mdc_warn; - char *temp_dir; - int no_encrypt_to; - int interactive; - 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 fast_list_mode; - int fixed_list_mode; - int ignore_time_conflict; - int ignore_valid_from; - int ignore_crc_error; - int ignore_mdc_error; - int command_fd; - 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; - int strict; -} opt; - - -#define EMUBUG_MDENCODE 4 - -#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */ -#define DBG_MPI_VALUE 2 /* debug mpi details */ -#define DBG_CIPHER_VALUE 4 /* debug cipher handling */ - /* (may reveal sensitive data) */ -#define DBG_FILTER_VALUE 8 /* debug internal filter handling */ -#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */ -#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */ -#define DBG_CACHE_VALUE 64 /* debug the cacheing */ -#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_CACHE (opt.debug & DBG_CACHE_VALUE) -#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE) -#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) -#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE) - - -#endif /*G10_OPTIONS_H*/ diff --git a/g10/options.skel b/g10/options.skel deleted file mode 100644 index cbb7cdf82..000000000 --- a/g10/options.skel +++ /dev/null @@ -1,203 +0,0 @@ -These first three lines are not copied to the gpg.conf file in -the users home directory. -$Id$ -# Options for GnuPG -# 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. -# -# Unless you specify which option file to use (with the command line -# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf -# by default. -# -# An options file can contain any long options which are available in -# GnuPG. If the first non white space character of a line is a '#', -# this line is ignored. Empty lines are also ignored. -# -# See the man page for a list of options. - -# Uncomment the following option to get rid of the copyright notice - -#no-greeting - -# If you have more than 1 secret key in your keyring, you may want to -# uncomment the following option and set your preferred keyid. - -#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. The second form uses the default key as -# default recipient. - -#default-recipient some-user-id -#default-recipient-self - -# By default GnuPG creates version 3 signatures for data files. This -# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP -# 7 require them. To disable this behavior, 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 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 recipient (-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. Note also that -# if there are spaces in the recipient name, this will appear as two -# recipients. In these cases it is better to use the key ID. - -#group mynames paige 0x12345678 joe patti - -# Lock the file only once for the lifetime of a process. If you do -# not define this, the lock will be obtained and released every time -# it is needed - normally this is not needed. - -#lock-once - -# 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://pgp.mit.edu -# -# Example email keyserver: -# mailto:pgp-public-keys@keys.nl.pgp.net -# -# Example LDAP keyservers: -# ldap://pgp.surfnet.nl:11370 -# ldap://keyserver.pgp.com -# -# 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. - -#keyserver x-hkp://pgp.mit.edu -#keyserver mailto:pgp-public-keys@keys.nl.pgp.net -#keyserver ldap://pgp.surfnet.nl:11370 -#keyserver ldap://keyserver.pgp.com - -# Common options for keyserver functions: -# -# include-disabled = when searching, include keys marked as "disabled" -# on the keyserver (not all keyservers support this). -# -# no-include-revoked = when searching, do not 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. -# -# no-include-attributes = do not include attribute IDs (aka "photo IDs") -# when sending keys to the keyserver. - -#keyserver-options auto-key-retrieve - -# Uncomment this line to display photo user IDs in key listings and -# when a signature from a key with a photo is verified. - -#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" -# On Mac OS X and Windows, the default is to use your regular image viewer. -# -# 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" - - -# 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 deleted file mode 100644 index fdca455a1..000000000 --- a/g10/packet.h +++ /dev/null @@ -1,494 +0,0 @@ -/* packet.h - packet definitions - * 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 - */ - -#ifndef G10_PACKET_H -#define G10_PACKET_H - -#include "types.h" -#include "iobuf.h" -#include "mpi.h" -#include "cipher.h" -#include "filter.h" -#include "global.h" - -#define DEBUG_PARSE_PACKET 1 - -typedef enum { - PKT_NONE =0, - PKT_PUBKEY_ENC =1, /* public key encrypted packet */ - PKT_SIGNATURE =2, /* secret key encrypted packet */ - PKT_SYMKEY_ENC =3, /* session key packet (OpenPGP)*/ - PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/ - PKT_SECRET_KEY =5, /* secret key */ - PKT_PUBLIC_KEY =6, /* public key */ - PKT_SECRET_SUBKEY =7, /* secret subkey (OpenPGP) */ - PKT_COMPRESSED =8, /* compressed data packet */ - PKT_ENCRYPTED =9, /* conventional encrypted data */ - PKT_MARKER =10, /* marker packet (OpenPGP) */ - PKT_PLAINTEXT =11, /* plaintext data with filename and mode */ - PKT_RING_TRUST =12, /* keyring trust packet */ - 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_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; - byte salt[8]; - u32 count; -} STRING2KEY; - -typedef struct { - byte version; - byte cipher_algo; /* cipher algorithm used */ - STRING2KEY s2k; - byte seskeylen; /* keylength in byte or 0 for no seskey */ - byte seskey[1]; -} PKT_symkey_enc; - -typedef struct { - u32 keyid[2]; /* 64 bit keyid */ - byte version; - byte pubkey_algo; /* algorithm used for public key scheme */ - byte throw_keyid; - MPI data[PUBKEY_MAX_NENC]; -} PKT_pubkey_enc; - - -typedef struct { - u32 keyid[2]; /* 64 bit keyid */ - byte sig_class; /* sig classification */ - byte digest_algo; /* algorithm used for digest */ - byte pubkey_algo; /* algorithm used for public key scheme */ - byte last; /* a stupid flag */ -} PKT_onepass_sig; - - -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 */ - /* (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[PUBKEY_MAX_NSIG]; -} PKT_signature; - -#define ATTRIB_IMAGE 1 - -/* This is the cooked form of attributes */ -struct user_attribute { - byte type; - const byte *data; - u32 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 - * has the same elemts as the public key at the begin of the array, so - * that npkey < nskey and it is possible to compare the secret and - * public keys by comparing the first npkey elements of pkey againts skey. - */ -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; /* 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() */ - byte is_primary; - prefitem_t *prefs; /* list of preferences (may be NULL) */ - int mdc_feature; /* mdc feature set */ - byte *namehash; /* if != NULL: found by this name */ - 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; - byte req_usage; - byte req_algo; - 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 */ - u32 main_keyid[2]; /* keyid of the primary key */ - u32 keyid[2]; - byte is_primary; - byte is_protected; /* The secret info is protected and must */ - /* be decrypted before use, the protected */ - /* MPIs are simply (void*) pointers to memory */ - /* 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[PUBKEY_MAX_NSKEY]; - u16 csum; /* checksum */ -} PKT_secret_key; - - -typedef struct { - int len; /* length of data */ - char data[1]; -} PKT_comment; - -typedef struct { - u32 len; /* reserved */ - byte new_ctb; - byte algorithm; - IOBUF buf; /* IOBUF reference */ -} PKT_compressed; - -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 */ -} PKT_encrypted; - -typedef struct { - byte hash[20]; -} PKT_mdc; - -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 { - pkttype_t pkttype; - union { - void *generic; - PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */ - PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ - PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */ - PKT_signature *signature; /* PKT_SIGNATURE */ - PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */ - PKT_secret_key *secret_key; /* PKT_SECRET_[SUB]KEY */ - PKT_comment *comment; /* PKT_COMMENT */ - PKT_user_id *user_id; /* PKT_USER_ID */ - PKT_compressed *compressed; /* PKT_COMPRESSED */ - PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */ - 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; -}; - -#define init_packet(a) do { (a)->pkttype = 0; \ - (a)->pkt.generic = NULL; \ - } while(0) - -typedef enum { - SIGSUBPKT_TEST_CRITICAL=-3, - SIGSUBPKT_LIST_UNHASHED=-2, - SIGSUBPKT_LIST_HASHED =-1, - SIGSUBPKT_NONE = 0, - SIGSUBPKT_SIG_CREATED = 2, /* signature creation time */ - SIGSUBPKT_SIG_EXPIRE = 3, /* signature expiration time */ - SIGSUBPKT_EXPORTABLE = 4, /* exportable */ - SIGSUBPKT_TRUST = 5, /* trust signature */ - SIGSUBPKT_REGEXP = 6, /* regular expression */ - SIGSUBPKT_REVOCABLE = 7, /* revocable */ - SIGSUBPKT_KEY_EXPIRE = 9, /* key expiration time */ - SIGSUBPKT_ARR =10, /* additional recipient request */ - SIGSUBPKT_PREF_SYM =11, /* preferred symmetric algorithms */ - SIGSUBPKT_REV_KEY =12, /* revocation key */ - SIGSUBPKT_ISSUER =16, /* issuer key ID */ - SIGSUBPKT_NOTATION =20, /* notation data */ - SIGSUBPKT_PREF_HASH =21, /* preferred hash algorithms */ - SIGSUBPKT_PREF_COMPR =22, /* preferred compression algorithms */ - SIGSUBPKT_KS_FLAGS =23, /* key server preferences */ - SIGSUBPKT_PREF_KS =24, /* preferred key server */ - SIGSUBPKT_PRIMARY_UID =25, /* primary user id */ - SIGSUBPKT_POLICY =26, /* policy URL */ - SIGSUBPKT_KEY_FLAGS =27, /* key flags */ - SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */ - SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */ - SIGSUBPKT_FEATURES =30, /* feature flags */ - SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result (obsolete)*/ - - SIGSUBPKT_FLAG_CRITICAL=128 -} sigsubpkttype_t; - - -/*-- mainproc.c --*/ -int proc_packets( void *ctx, IOBUF a ); -int proc_signature_packets( void *ctx, IOBUF a, - STRLIST signedfiles, const char *sigfile ); -int proc_encryption_packets( void *ctx, IOBUF a ); -int list_packets( IOBUF a ); - -/*-- parse-packet.c --*/ -int set_packet_list_mode( int mode ); - -#if DEBUG_PARSE_PACKET -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, 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, 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, off_t stopoff ); -int skip_some_packets( IOBUF inp, unsigned n ); -#endif - -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, size_t max_namelen); -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( 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,u32 buflen, - const void *header,u32 headerlen); - -/*-- free-packet.c --*/ -void free_symkey_enc( PKT_symkey_enc *enc ); -void free_pubkey_enc( PKT_pubkey_enc *enc ); -void free_seckey_enc( PKT_signature *enc ); -int digest_algo_from_sig( PKT_signature *sig ); -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 ); -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 *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 ); -int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk ); -int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); - - -/*-- sig-check.c --*/ -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 ); -int check_secret_key( PKT_secret_key *sk, int retries ); -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, - int (*callback)(IOBUF, void *), void *passthru ); - -/*-- encr-data.c --*/ -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( MD_HANDLE md, MD_HANDLE md2, - const char *inname, int textmode ); - -/*-- comment.c --*/ -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, - 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 /*G10_PACKET_H*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c deleted file mode 100644 index bce3ce308..000000000 --- a/g10/parse-packet.c +++ /dev/null @@ -1,2260 +0,0 @@ -/* parse-packet.c - read packets - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.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" - -static int mpi_print_mode = 0; -static int list_mode = 0; - -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 - ); -static int copy_packet( IOBUF inp, IOBUF out, int pkttype, - unsigned long pktlen ); -static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ); -static void skip_rest( IOBUF inp, unsigned long pktlen ); -static void *read_rest( IOBUF inp, size_t pktlen ); -static int parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); -static int parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); -static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, - PKT_signature *sig ); -static int parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, - PKT_onepass_sig *ops ); -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_attribute( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); -static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); -static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet ); -static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet, int new_ctb); -static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *packet, int new_ctb ); -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) -{ - unsigned short a; - a = iobuf_get_noeof(inp) << 8; - a |= iobuf_get_noeof(inp); - return a; -} - -static unsigned long -read_32(IOBUF inp) -{ - unsigned long a; - a = iobuf_get_noeof(inp) << 24; - a |= iobuf_get_noeof(inp) << 16; - a |= iobuf_get_noeof(inp) << 8; - a |= iobuf_get_noeof(inp); - return a; -} - - -int -set_packet_list_mode( int mode ) -{ - int old = list_mode; - list_mode = mode; - mpi_print_mode = DBG_MPI; - return old; -} - -static void -unknown_pubkey_warning( int algo ) -{ - static byte unknown_pubkey_algos[256]; - - algo &= 0xff; - if( !unknown_pubkey_algos[algo] ) { - if( opt.verbose ) - log_info(_("can't handle public key algorithm %d\n"), algo ); - unknown_pubkey_algos[algo] = 1; - } -} - -/**************** - * Parse a Packet and return it in packet - * Returns: 0 := valid packet in pkt - * -1 := no more packets - * >0 := error - * Note: The function may return an error and a partly valid packet; - * caller must free this packet. - */ -#ifdef DEBUG_PARSE_PACKET -int -dbg_parse_packet( IOBUF inp, PACKET *pkt, const char *dbg_f, int dbg_l ) -{ - int skip, rc; - - do { - 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 ) -{ - int skip, rc; - - do { - rc = parse( inp, pkt, 0, NULL, &skip, NULL, 0 ); - } while( skip ); - return rc; -} -#endif - -/**************** - * Like parse packet, but only return secret or public (sub)key packets. - */ -#ifdef DEBUG_PARSE_PACKET -int -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, 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, off_t *retpos, int with_uid ) -{ - int skip, rc; - - do { - rc = parse( inp, pkt, with_uid?2:1, retpos, &skip, NULL, 0 ); - } while( skip ); - return rc; -} -#endif - -/**************** - * Copy all packets from INP to OUT, thereby removing unused spaces. - */ -#ifdef DEBUG_PARSE_PACKET -int -dbg_copy_all_packets( IOBUF inp, IOBUF out, - const char *dbg_f, int dbg_l ) -{ - PACKET pkt; - int skip, rc=0; - do { - init_packet(&pkt); - } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0, "copy", dbg_f, dbg_l ))); - return rc; -} -#else -int -copy_all_packets( IOBUF inp, IOBUF out ) -{ - PACKET pkt; - int skip, rc=0; - do { - init_packet(&pkt); - } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 ))); - return rc; -} -#endif - -/**************** - * Copy some packets from INP to OUT, thereby removing unused spaces. - * Stop at offset STOPoff (i.e. don't copy packets at this or later offsets) - */ -#ifdef DEBUG_PARSE_PACKET -int -dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff, - const char *dbg_f, int dbg_l ) -{ - PACKET pkt; - int skip, rc=0; - do { - if( iobuf_tell(inp) >= stopoff ) - return 0; - init_packet(&pkt); - } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0, - "some", dbg_f, dbg_l )) ); - return rc; -} -#else -int -copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff ) -{ - PACKET pkt; - int skip, rc=0; - do { - if( iobuf_tell(inp) >= stopoff ) - return 0; - init_packet(&pkt); - } while( !(rc = parse( inp, &pkt, 0, NULL, &skip, out, 0 )) ); - return rc; -} -#endif - -/**************** - * Skip over N packets - */ -#ifdef DEBUG_PARSE_PACKET -int -dbg_skip_some_packets( IOBUF inp, unsigned n, - const char *dbg_f, int dbg_l ) -{ - int skip, rc=0; - PACKET pkt; - - for( ;n && !rc; n--) { - init_packet(&pkt); - rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1, "skip", dbg_f, dbg_l ); - } - return rc; -} -#else -int -skip_some_packets( IOBUF inp, unsigned n ) -{ - int skip, rc=0; - PACKET pkt; - - for( ;n && !rc; n--) { - init_packet(&pkt); - rc = parse( inp, &pkt, 0, NULL, &skip, NULL, 1 ); - } - return rc; -} -#endif - - -/**************** - * 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 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 - ) -{ - int rc=0, c, ctb, pkttype, lenbytes; - unsigned long pktlen; - byte hdr[8]; - int hdrlen; - int new_ctb = 0; - int with_uid = (onlykeypkts == 2); - - *skip = 0; - assert( !pkt->pkt.generic ); - if( retpos ) - *retpos = iobuf_tell(inp); - - if( (ctb = iobuf_get(inp)) == -1 ) { - rc = -1; - goto leave; - } - hdrlen=0; - hdr[hdrlen++] = ctb; - if( !(ctb & 0x80) ) { - log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb ); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - pktlen = 0; - new_ctb = !!(ctb & 0x40); - if( new_ctb ) { - pkttype = ctb & 0x3f; - if( (c = iobuf_get(inp)) == -1 ) { - log_error("%s: 1st length byte missing\n", iobuf_where(inp) ); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - if (pkttype == PKT_COMPRESSED) { - iobuf_set_partial_block_mode(inp, c & 0xff); - pktlen = 0;/* to indicate partial length */ - } - else { - hdr[hdrlen++] = c; - if( c < 192 ) - pktlen = c; - else if( c < 224 ) { - pktlen = (c - 192) * 256; - if( (c = iobuf_get(inp)) == -1 ) { - log_error("%s: 2nd length byte missing\n", - iobuf_where(inp) ); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - hdr[hdrlen++] = c; - pktlen += c + 192; - } - else if( c == 255 ) { - pktlen = (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 24; - pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 16; - 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 = G10ERR_INVALID_PACKET; - goto leave; - } - pktlen |= (hdr[hdrlen++] = c ); - } - else { /* partial body length */ - iobuf_set_partial_block_mode(inp, c & 0xff); - pktlen = 0;/* to indicate partial length */ - } - } - } - else { - pkttype = (ctb>>2)&0xf; - lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); - if( !lenbytes ) { - pktlen = 0; /* don't know the value */ - if( pkttype != PKT_COMPRESSED ) - iobuf_set_block_mode(inp, 1); - } - else { - for( ; lenbytes; lenbytes-- ) { - pktlen <<= 8; - pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp); - } - } - } - - 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 = G10ERR_WRITE_FILE; - else - rc = copy_packet(inp, out, pkttype, pktlen ); - goto leave; - } - - 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; - goto leave; - } - - if( DBG_PACKET ) { -#ifdef DEBUG_PARSE_PACKET - log_debug("parse_packet(iob=%d): type=%d length=%lu%s (%s.%s.%d)\n", - iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"", - dbg_w, dbg_f, dbg_l ); -#else - log_debug("parse_packet(iob=%d): type=%d length=%lu%s\n", - iobuf_id(inp), pkttype, pktlen, new_ctb?" (new_ctb)":"" ); -#endif - } - pkt->pkttype = pkttype; - rc = G10ERR_UNKNOWN_PACKET; /* default error */ - switch( pkttype ) { - case PKT_PUBLIC_KEY: - case PKT_PUBLIC_SUBKEY: - 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 = m_alloc_clear(sizeof *pkt->pkt.secret_key ); - rc = parse_key(inp, pkttype, pktlen, hdr, hdrlen, pkt ); - break; - case PKT_SYMKEY_ENC: - rc = parse_symkeyenc( inp, pkttype, pktlen, pkt ); - break; - case PKT_PUBKEY_ENC: - rc = parse_pubkeyenc(inp, pkttype, pktlen, pkt ); - break; - case 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 = 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_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: - rc = parse_comment(inp, pkttype, pktlen, pkt); - break; - case PKT_RING_TRUST: - parse_trust(inp, pkttype, pktlen, pkt); - rc = 0; - break; - case PKT_PLAINTEXT: - rc = parse_plaintext(inp, pkttype, pktlen, pkt, new_ctb ); - break; - case PKT_COMPRESSED: - rc = parse_compressed(inp, pkttype, pktlen, pkt, new_ctb ); - break; - case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: - rc = parse_encrypted(inp, pkttype, pktlen, pkt, new_ctb ); - break; - 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; - } - - leave: - if( !rc && iobuf_error(inp) ) - rc = G10ERR_INV_KEYRING; - return rc; -} - -static void -dump_hex_line( int c, int *i ) -{ - if( *i && !(*i%8) ) { - if( *i && !(*i%24) ) - printf("\n%4d:", *i ); - else - putchar(' '); - } - if( c == -1 ) - printf(" EOF" ); - else - printf(" %02x", c ); - ++*i; -} - - -static int -copy_packet( IOBUF inp, IOBUF out, int pkttype, unsigned long pktlen ) -{ - int n; - char buf[100]; - - if( iobuf_in_block_mode(inp) ) { - while( (n = iobuf_read( inp, buf, 100 )) != -1 ) - if( iobuf_write(out, buf, n ) ) - 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 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 G10ERR_READ_FILE; - if( iobuf_write(out, buf, n ) ) - return G10ERR_WRITE_FILE; /* write error */ - } - } - return 0; -} - - -static void -skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ) -{ - if( list_mode ) { - if( pkttype == PKT_MARKER ) - fputs(":marker packet:\n", stdout ); - else - printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen); - if( pkttype ) { - int c, i=0 ; - if( pkttype != PKT_MARKER ) - fputs("dump:", stdout ); - 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'); - return; - } - } - skip_rest(inp,pktlen); -} - -static void -skip_rest( IOBUF inp, unsigned long pktlen ) -{ - if( iobuf_in_block_mode(inp) ) { - while( iobuf_get(inp) != -1 ) - ; - } - else { - for( ; pktlen; pktlen-- ) - if( iobuf_get(inp) == -1 ) - break; - } -} - - -static void * -read_rest( IOBUF inp, size_t pktlen ) -{ - byte *p; - int i; - - if( iobuf_in_block_mode(inp) ) { - log_error("read_rest: can't store stream data\n"); - p = NULL; - } - else { - p = m_alloc( pktlen ); - for(i=0; pktlen; pktlen--, i++ ) - p[i] = iobuf_get(inp); - } - return p; -} - - - -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--; - s2kmode = iobuf_get_noeof(inp); pktlen--; - hash_algo = iobuf_get_noeof(inp); pktlen--; - switch( s2kmode ) { - case 0: /* simple s2k */ - minlen = 0; - break; - case 1: /* salted s2k */ - minlen = 8; - break; - case 3: /* iterated+salted s2k */ - minlen = 9; - break; - default: - log_error("unknown S2K %d\n", s2kmode ); - goto leave; - } - 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 = m_alloc_clear( sizeof *packet->pkt.symkey_enc - + seskeylen - 1 ); - k->version = version; - k->cipher_algo = cipher_algo; - k->s2k.mode = s2kmode; - k->s2k.hash_algo = hash_algo; - if( s2kmode == 1 || s2kmode == 3 ) { - for(i=0; i < 8 && pktlen; i++, pktlen-- ) - k->s2k.salt[i] = iobuf_get_noeof(inp); - } - if( s2kmode == 3 ) { - k->s2k.count = iobuf_get(inp); pktlen--; - } - k->seskeylen = seskeylen; - for(i=0; i < seskeylen && pktlen; i++, pktlen-- ) - k->seskey[i] = iobuf_get_noeof(inp); - assert( !pktlen ); - - if( list_mode ) { - printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n", - version, cipher_algo, s2kmode, hash_algo); - if( s2kmode == 1 || s2kmode == 3 ) { - printf("\tsalt "); - for(i=0; i < 8; i++ ) - printf("%02x", k->s2k.salt[i]); - if( s2kmode == 3 ) - printf(", count %lu\n", (ulong)k->s2k.count ); - printf("\n"); - } - } - - leave: - skip_rest(inp, pktlen); - return rc; -} - -static int -parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) -{ - unsigned int n; - int rc = 0; - int i, ndata; - PKT_pubkey_enc *k; - - 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; - k->keyid[1] = read_32(inp); pktlen -= 4; - k->pubkey_algo = iobuf_get_noeof(inp); pktlen--; - k->throw_keyid = 0; /* only used as flag for build_packet */ - if( list_mode ) - printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n", - k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]); - - ndata = pubkey_get_nenc(k->pubkey_algo); - if( !ndata ) { - if( list_mode ) - printf("\tunsupported algorithm %d\n", k->pubkey_algo ); - unknown_pubkey_warning( k->pubkey_algo ); - k->data[0] = NULL; /* no need to store the encrypted data */ - } - else { - for( i=0; i < ndata; i++ ) { - n = pktlen; - k->data[i] = mpi_read(inp, &n, 0); pktlen -=n; - if( list_mode ) { - printf("\tdata: "); - 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 rc; -} - - -static void -dump_sig_subpkt( int hashed, int type, int critical, - const byte *buffer, size_t buflen, size_t length ) -{ - const char *p=NULL; - int i; - - /* The CERT has warning out with explains how to use GNUPG to - * detect the ARRs - we print our old message here when it is a faked - * ARR and add an additional notice */ - if ( type == SIGSUBPKT_ARR && !hashed ) { - printf("\tsubpkt %d len %u (additional recipient request)\n" - "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically " - "encrypt to this key and thereby reveal the plaintext to " - "the owner of this ARR key. Detailed info follows:\n", - type, (unsigned)length ); - } - - - printf("\t%s%ssubpkt %d len %u (", /*)*/ - critical ? "critical ":"", - hashed ? "hashed ":"", type, (unsigned)length ); - buffer++; - length--; - if( length > buflen ) { - printf("too short: buffer is only %u)\n", (unsigned)buflen ); - return; - } - switch( type ) { - case SIGSUBPKT_SIG_CREATED: - if( length >= 4 ) - printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) ); - break; - case SIGSUBPKT_SIG_EXPIRE: - if( length >= 4 ) - printf("sig expires after %s", - strtimevalue( buffer_to_u32(buffer) ) ); - break; - case SIGSUBPKT_EXPORTABLE: - if( length ) - printf("%sexportable", *buffer? "":"not "); - break; - case SIGSUBPKT_TRUST: - if(length!=2) - p="[invalid trust signature]"; - else - printf("trust signature of level %d, amount %d",buffer[0],buffer[1]); - break; - case SIGSUBPKT_REGEXP: - if(!length) - p="[invalid regexp]"; - else - printf("regular expression: \"%s\"",buffer); - break; - case SIGSUBPKT_REVOCABLE: - if( length ) - printf("%srevocable", *buffer? "":"not "); - break; - case SIGSUBPKT_KEY_EXPIRE: - if( length >= 4 ) - printf("key expires after %s", - strtimevalue( buffer_to_u32(buffer) ) ); - break; - case SIGSUBPKT_PREF_SYM: - fputs("pref-sym-algos:", stdout ); - for( i=0; i < length; i++ ) - printf(" %d", buffer[i] ); - break; - case SIGSUBPKT_REV_KEY: - fputs("revocation key: ", stdout ); - if( length < 22 ) - p = "[too short]"; - else { - printf("c=%02x a=%d f=", buffer[0], buffer[1] ); - for( i=2; i < length; i++ ) - printf("%02X", buffer[i] ); - } - break; - case SIGSUBPKT_ISSUER: - if( length >= 8 ) - printf("issuer key ID %08lX%08lX", - (ulong)buffer_to_u32(buffer), - (ulong)buffer_to_u32(buffer+4) ); - break; - case SIGSUBPKT_NOTATION: - { - fputs("notation: ", stdout ); - if( length < 8 ) - p = "[too short]"; - else if( !(*buffer & 0x80) ) - p = "[not human readable]"; - else { - const byte *s = buffer; - size_t n1, n2; - - n1 = (s[4] << 8) | s[5]; - n2 = (s[6] << 8) | s[7]; - s += 8; - if( 8+n1+n2 != length ) - p = "[error]"; - else { - print_string( stdout, s, n1, ')' ); - putc( '=', stdout ); - print_string( stdout, s+n1, n2, ')' ); - } - } - } - break; - case SIGSUBPKT_PREF_HASH: - fputs("pref-hash-algos:", stdout ); - for( i=0; i < length; i++ ) - printf(" %d", buffer[i] ); - break; - case SIGSUBPKT_PREF_COMPR: - fputs("pref-zip-algos:", stdout ); - for( i=0; i < length; i++ ) - printf(" %d", buffer[i] ); - break; - case SIGSUBPKT_KS_FLAGS: - fputs("key server preferences:",stdout); - for(i=0;i<length;i++) - printf(" %02X", buffer[i]); - break; - case SIGSUBPKT_PREF_KS: - p = "preferred key server"; - break; - case SIGSUBPKT_PRIMARY_UID: - p = "primary user ID"; - break; - case SIGSUBPKT_POLICY: - fputs("policy: ", stdout ); - print_string( stdout, buffer, length, ')' ); - break; - case SIGSUBPKT_KEY_FLAGS: - fputs ( "key flags:", stdout ); - for( i=0; i < length; i++ ) - printf(" %02X", buffer[i] ); - break; - case SIGSUBPKT_SIGNERS_UID: - p = "signer's user ID"; - break; - case SIGSUBPKT_REVOC_REASON: - if( length ) { - printf("revocation reason 0x%02x (", *buffer ); - print_string( stdout, buffer+1, length-1, ')' ); - p = ")"; - } - break; - case SIGSUBPKT_ARR: - fputs("Big Brother's key (ignored): ", stdout ); - if( length < 22 ) - p = "[too short]"; - else { - printf("c=%02x a=%d f=", buffer[0], buffer[1] ); - for( i=2; i < length; i++ ) - printf("%02X", buffer[i] ); - } - break; - case SIGSUBPKT_FEATURES: - fputs ( "features:", stdout ); - for( i=0; i < length; i++ ) - printf(" %02x", buffer[i] ); - break; - case SIGSUBPKT_PRIV_VERIFY_CACHE: - p = "obsolete verification cache"; - break; - default: p = "?"; break; - } - - printf("%s)\n", p? p: ""); -} - -/**************** - * Returns: >= 0 offset into buffer - * -1 unknown type - * -2 unsupported type - * -3 subpacket too short - */ -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: - if( n < 4 ) - break; - return 0; - case SIGSUBPKT_KEY_FLAGS: - 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 */ - if( n < 8 ) - break; - return 0; - case SIGSUBPKT_NOTATION: - if( n < 8 ) /* minimum length needed */ - break; - return 0; - case SIGSUBPKT_REVOC_REASON: - if( !n ) - break; - return 0; - case SIGSUBPKT_PRIMARY_UID: - if ( n != 1 ) - break; - return 0; - 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' || buffer[3] ) - return -2; - return 4; - default: return -1; - } - return -3; -} - - -static int -can_handle_critical( const byte *buffer, size_t n, int type ) -{ - switch( type ) { - case SIGSUBPKT_NOTATION: - if( n >= 8 && (*buffer & 0x80) ) - return 1; /* human readable is handled */ - return 0; - - case SIGSUBPKT_SIG_CREATED: - 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_KEY_FLAGS: - case SIGSUBPKT_PRIMARY_UID: - case SIGSUBPKT_FEATURES: - case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */ - return 1; - - default: - return 0; - } -} - - -const byte * -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_dummy; - int offset; - size_t n; - int seq = 0; - int reqseq = start? *start: 0; - - if(!critical) - critical=&critical_dummy; - - if( !pktbuf || reqseq == -1 ) { - /* return some value different from NULL to indicate that - * 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*)&pktbuf : NULL; - } - buffer = pktbuf->data; - buflen = pktbuf->len; - 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; - type = *buffer; - if( type & 0x80 ) { - type &= 0x7f; - *critical = 1; - } - else - *critical = 0; - if( !(++seq > reqseq) ) - ; - else if( reqtype == SIGSUBPKT_TEST_CRITICAL ) { - if( *critical ) { - if( n-1 > buflen+1 ) - goto too_short; - if( !can_handle_critical(buffer+1, n-1, type ) ) { - log_info(_("subpacket of type %d has critical bit set\n"), - type); - if( start ) - *start = seq; - return NULL; /* this is an error */ - } - } - } - else if( reqtype < 0 ) /* list packets */ - dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED, - type, *critical, buffer, buflen, n ); - else if( type == reqtype ) { /* found */ - buffer++; - n--; - if( n > buflen ) - goto too_short; - if( ret_n ) - *ret_n = n; - offset = parse_one_sig_subpkt(buffer, n, type ); - switch( offset ) { - case -3: - log_error("subpacket of type %d too short\n", type); - return NULL; - case -2: - return NULL; - case -1: - BUG(); /* not yet needed */ - default: - break; - } - if( start ) - *start = seq; - return buffer+offset; - } - buffer += n; buflen -=n; - } - if( reqtype == SIGSUBPKT_TEST_CRITICAL ) - return buffer; /* as value true to indicate that there is no */ - /* critical bit we don't understand */ - if( start ) - *start = -1; - return NULL; /* end of packets; not found */ - - too_short: - log_error("buffer shorter than subpacket\n"); - if( start ) - *start = -1; - return NULL; -} - - -const byte * -parse_sig_subpkt (const subpktarea_t *buffer, sigsubpkttype_t reqtype, - size_t *ret_n) -{ - 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 ) -{ - const byte *p; - - p = parse_sig_subpkt (sig->hashed, reqtype, ret_n ); - if( !p ) - 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, - PKT_signature *sig ) -{ - int md5_len=0; - unsigned n; - int is_v4=0; - int rc=0; - int i, ndata; - - if( pktlen < 16 ) { - log_error("packet(%d) too short\n", pkttype); - goto leave; - } - sig->version = iobuf_get_noeof(inp); pktlen--; - if( sig->version == 4 ) - 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; - } - - if( !is_v4 ) { - md5_len = iobuf_get_noeof(inp); pktlen--; - } - sig->sig_class = iobuf_get_noeof(inp); pktlen--; - if( !is_v4 ) { - sig->timestamp = read_32(inp); pktlen -= 4; - sig->keyid[0] = read_32(inp); pktlen -= 4; - sig->keyid[1] = read_32(inp); pktlen -= 4; - } - 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 = G10ERR_INVALID_PACKET; - goto leave; - } - if( 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; - } - pktlen -= n; - } - n = read_16(inp); pktlen -= 2; /* length of unhashed data */ - if( n > 10000 ) { - log_error("signature packet: unhashed data too long\n"); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - if( n ) { - /* we add 8 extra bytes so that we have space for the signature - * status cache. Well we are wasting 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; - } - pktlen -= n; - } - } - - if( pktlen < 5 ) { /* sanity check */ - log_error("packet(%d) too short\n", pkttype); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - - sig->digest_start[0] = iobuf_get_noeof(inp); pktlen--; - sig->digest_start[1] = iobuf_get_noeof(inp); pktlen--; - - if( is_v4 && sig->pubkey_algo ) { /*extract required information */ - const byte *p; - - /* 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, SIGSUBPKT_TEST_CRITICAL, NULL) - || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, - NULL) ) - { - sig->flags.unknown_critical = 1; - } - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL ); - if( !p ) - log_error("signature packet without timestamp\n"); - else - sig->timestamp = buffer_to_u32(p); - p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL ); - if( !p ) - log_error("signature packet without keyid\n"); - else { - 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 ) { - printf(":signature packet: algo %d, keyid %08lX%08lX\n" - "\tversion %d, created %lu, md5len %d, sigclass %02x\n" - "\tdigest algo %d, begin of digest %02x %02x\n", - sig->pubkey_algo, - (ulong)sig->keyid[0], (ulong)sig->keyid[1], - sig->version, (ulong)sig->timestamp, md5_len, sig->sig_class, - sig->digest_algo, - sig->digest_start[0], sig->digest_start[1] ); - if( is_v4 ) { - parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL ); - parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL); - } - } - - ndata = pubkey_get_nsig(sig->pubkey_algo); - if( !ndata ) { - if( list_mode ) - printf("\tunknown algorithm %d\n", sig->pubkey_algo ); - unknown_pubkey_warning( sig->pubkey_algo ); - /* we store the plain material in data[0], so that we are able - * to write it back with build_packet() */ - sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen ); - pktlen = 0; - } - else { - for( i=0; i < ndata; i++ ) { - n = pktlen; - sig->data[i] = mpi_read(inp, &n, 0 ); - pktlen -=n; - if( list_mode ) { - printf("\tdata: "); - mpi_print(stdout, sig->data[i], mpi_print_mode ); - putchar('\n'); - } - if (!sig->data[i]) - rc = G10ERR_INVALID_PACKET; - } - } - - leave: - skip_rest(inp, pktlen); - return rc; -} - - -static int -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--; - ops->digest_algo = iobuf_get_noeof(inp); pktlen--; - ops->pubkey_algo = iobuf_get_noeof(inp); pktlen--; - ops->keyid[0] = read_32(inp); pktlen -= 4; - ops->keyid[1] = read_32(inp); pktlen -= 4; - ops->last = iobuf_get_noeof(inp); pktlen--; - if( list_mode ) - printf(":onepass_sig packet: keyid %08lX%08lX\n" - "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n", - (ulong)ops->keyid[0], (ulong)ops->keyid[1], - version, ops->sig_class, - ops->digest_algo, ops->pubkey_algo, ops->last ); - - - leave: - skip_rest(inp, pktlen); - return rc; -} - - -static MPI -read_protected_v3_mpi (IOBUF inp, unsigned long *length) -{ - int c; - unsigned int nbits, nbytes; - unsigned char *buf, *p; - MPI val; - - if (*length < 2) - { - log_error ("mpi too small\n"); - return NULL; - } - - if ((c=iobuf_get (inp)) == -1) - return NULL; - --*length; - nbits = c << 8; - if ((c=iobuf_get(inp)) == -1) - return NULL; - --*length; - nbits |= c; - - if (nbits > 16384) - { - log_error ("mpi too large (%u bits)\n", nbits); - return NULL; - } - nbytes = (nbits+7) / 8; - buf = p = m_alloc (2 + nbytes); - *p++ = nbits >> 8; - *p++ = nbits; - for (; nbytes && length; nbytes--, --*length) - *p++ = iobuf_get (inp); - if (nbytes) - { - log_error ("packet shorter tham mpi\n"); - m_free (buf); - return NULL; - } - - /* convert buffer into an opaque MPI */ - val = mpi_set_opaque (NULL, buf, p-buf); - return val; -} - - -static int -parse_key( IOBUF inp, int pkttype, unsigned long pktlen, - byte *hdr, int hdrlen, PACKET *pkt ) -{ - int i, version, algorithm; - unsigned n; - 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 G10 use old PGP comments packets; - * luckily all those comments are started by a hash */ - if( list_mode ) { - printf(":rfc1991 comment packet: \"" ); - for( ; pktlen; pktlen-- ) { - int c; - c = iobuf_get_noeof(inp); - if( c >= ' ' && c <= 'z' ) - putchar(c); - else - printf("\\x%02x", c ); - } - printf("\"\n"); - } - skip_rest(inp, pktlen); - return 0; - } - else if( version == 4 ) - 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 ) { - expiredate = 0; /* have to get it from the selfsignature */ - max_expiredate = 0; - } - else { - unsigned short ndays; - ndays = read_16(inp); pktlen -= 2; - if( ndays ) - expiredate = timestamp + ndays * 86400L; - else - expiredate = 0; - - max_expiredate=expiredate; - } - algorithm = iobuf_get_noeof(inp); pktlen--; - if( list_mode ) - printf(":%s key packet:\n" - "\tversion %d, algo %d, created %lu, expires %lu\n", - pkttype == PKT_PUBLIC_KEY? "public" : - pkttype == PKT_SECRET_KEY? "secret" : - pkttype == PKT_PUBLIC_SUBKEY? "public sub" : - pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??", - version, algorithm, timestamp, expiredate ); - - if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *sk = pkt->pkt.secret_key; - - 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; /* 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->is_primary = pkttype == PKT_PUBLIC_KEY; - pk->pubkey_algo = algorithm; - pk->req_usage = 0; - pk->pubkey_usage = 0; /* not yet used */ - pk->is_revoked = 0; - pk->keyid[0] = 0; - pk->keyid[1] = 0; - } - nskey = pubkey_get_nskey( algorithm ); - npkey = pubkey_get_npkey( algorithm ); - if( !npkey ) { - if( list_mode ) - printf("\tunknown algorithm %d\n", algorithm ); - unknown_pubkey_warning( algorithm ); - } - - - if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *sk = pkt->pkt.secret_key; - byte temp[16]; - - if( !npkey ) { - sk->skey[0] = mpi_set_opaque( NULL, - read_rest(inp, pktlen), pktlen ); - pktlen = 0; - goto leave; - } - - for(i=0; i < npkey; i++ ) { - n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n; - if( list_mode ) { - printf( "\tskey[%d]: ", i); - 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 == 254 || sk->protect.algo == 255 ) { - if( pktlen < 3 ) { - rc = G10ERR_INVALID_PACKET; - goto leave; - } - sk->protect.sha1chk = (sk->protect.algo == 254); - sk->protect.algo = iobuf_get_noeof(inp); pktlen--; - /* Note that a sk->protect.algo > 110 is illegal, but - I'm not erroring on it here as otherwise there - would be no way to delete such a key. */ - sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--; - sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--; - /* check for the special GNU extension */ - if( is_v4 && sk->protect.s2k.mode == 101 ) { - for(i=0; i < 4 && pktlen; i++, pktlen-- ) - temp[i] = iobuf_get_noeof(inp); - if( i < 4 || memcmp( temp, "GNU", 3 ) ) { - if( list_mode ) - printf( "\tunknown S2K %d\n", - sk->protect.s2k.mode ); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - /* here we know that it is a gnu extension - * What follows is the GNU protection mode: - * All values have special meanings - * and they are mapped in the mode with a base of 1000. - */ - sk->protect.s2k.mode = 1000 + temp[3]; - } - switch( sk->protect.s2k.mode ) { - case 1: - case 3: - for(i=0; i < 8 && pktlen; i++, pktlen-- ) - temp[i] = iobuf_get_noeof(inp); - memcpy(sk->protect.s2k.salt, temp, 8 ); - break; - } - switch( sk->protect.s2k.mode ) { - case 0: if( list_mode ) printf( "\tsimple S2K" ); - break; - case 1: if( list_mode ) printf( "\tsalted S2K" ); - break; - case 3: if( list_mode ) printf( "\titer+salt S2K" ); - break; - case 1001: if( list_mode ) printf( "\tgnu-dummy S2K" ); - break; - default: - if( list_mode ) - printf( "\tunknown %sS2K %d\n", - sk->protect.s2k.mode < 1000? "":"GNU ", - sk->protect.s2k.mode ); - rc = G10ERR_INVALID_PACKET; - goto leave; - } - - if( list_mode ) { - 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 ) { - printf(", salt: "); - for(i=0; i < 8; i++ ) - printf("%02x", sk->protect.s2k.salt[i]); - } - putchar('\n'); - } - - if( sk->protect.s2k.mode == 3 ) { - if( pktlen < 1 ) { - rc = G10ERR_INVALID_PACKET; - goto leave; - } - sk->protect.s2k.count = iobuf_get(inp); - pktlen--; - if( list_mode ) - printf("\tprotect count: %lu\n", - (ulong)sk->protect.s2k.count); - } - } - /* Note that a sk->protect.algo > 110 is illegal, but I'm - not erroring on it here as otherwise there would be no - way to delete such a key. */ - else { /* old version; no S2K, so we set mode to 0, hash MD5 */ - sk->protect.s2k.mode = 0; - 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 ); - } - /* It is really ugly that we don't know the size - * of the IV here in cases we are not aware of the algorithm. - * so a - * sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo); - * won't work. The only solution I see is to hardwire it here. - * NOTE: if you change the ivlen above 16, don't forget to - * enlarge temp. - */ - switch( sk->protect.algo ) { - case 7: case 8: case 9: /* reserved for AES */ - case 10: /* Twofish */ - sk->protect.ivlen = 16; - break; - default: - sk->protect.ivlen = 8; - } - if( sk->protect.s2k.mode == 1001 ) - sk->protect.ivlen = 0; - - if( pktlen < sk->protect.ivlen ) { - rc = G10ERR_INVALID_PACKET; - goto leave; - } - for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- ) - temp[i] = iobuf_get_noeof(inp); - if( list_mode ) { - printf( "\tprotect IV: "); - for(i=0; i < sk->protect.ivlen; i++ ) - printf(" %02x", temp[i] ); - putchar('\n'); - } - memcpy(sk->protect.iv, temp, sk->protect.ivlen ); - } - else - sk->is_protected = 0; - /* It does not make sense to read it into secure memory. - * If the user is so careless, not to protect his secret key, - * we can assume, that he operates an open system :=(. - * 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, 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] = mpi_set_opaque(NULL, - read_rest(inp, pktlen), pktlen ); - pktlen = 0; - if( list_mode ) { - printf("\tencrypted stuff follows\n"); - } - } - else { /* v3 method: the mpi length is not encrypted */ - for(i=npkey; i < nskey; i++ ) { - if ( sk->is_protected ) { - sk->skey[i] = read_protected_v3_mpi (inp, &pktlen); - if( list_mode ) - printf( "\tskey[%d]: [encrypted]\n", i); - } - else { - n = pktlen; - sk->skey[i] = mpi_read(inp, &n, 0 ); - pktlen -=n; - if( list_mode ) { - printf( "\tskey[%d]: ", i); - mpi_print(stdout, sk->skey[i], mpi_print_mode ); - putchar('\n'); - } - } - - if (!sk->skey[i]) - rc = G10ERR_INVALID_PACKET; - } - if (rc) - goto leave; - - sk->csum = read_16(inp); pktlen -= 2; - if( list_mode ) { - printf("\tchecksum: %04hx\n", sk->csum); - } - } - } - else { - PKT_public_key *pk = pkt->pkt.public_key; - - if( !npkey ) { - pk->pkey[0] = mpi_set_opaque( NULL, - read_rest(inp, pktlen), pktlen ); - pktlen = 0; - goto leave; - } - - for(i=0; i < npkey; i++ ) { - n = pktlen; pk->pkey[i] = mpi_read(inp, &n, 0 ); pktlen -=n; - if( list_mode ) { - printf( "\tpkey[%d]: ", i); - mpi_print(stdout, pk->pkey[i], mpi_print_mode ); - putchar('\n'); - } - if (!pk->pkey[i]) - rc = G10ERR_INVALID_PACKET; - } - if (rc) - goto leave; - } - - leave: - skip_rest(inp, 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 = m_alloc(sizeof *packet->pkt.user_id + pktlen); - packet->pkt.user_id->len = pktlen; - - setup_user_id(packet); - - p = packet->pkt.user_id->name; - for( ; pktlen; pktlen--, p++ ) - *p = iobuf_get_noeof(inp); - *p = 0; - - if( list_mode ) { - int n = packet->pkt.user_id->len; - printf(":user ID packet: \""); - /* 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); - else - printf("\\x%02x", *p ); - } - printf("\"\n"); - } - return 0; -} - - -void -make_attribute_uidname(PKT_user_id *uid, size_t max_namelen) -{ - assert ( max_namelen > 70 ); - 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,"[%.20s 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]", - (ulong)uid->attribs->len); - } - - uid->len = strlen(uid->name); -} - -static int -parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) -{ - byte *p; - -#define EXTRA_UID_NAME_SPACE 71 - packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id - + EXTRA_UID_NAME_SPACE); - - setup_user_id(packet); - - 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, EXTRA_UID_NAME_SPACE); - - if( list_mode ) { - printf(":attribute packet: %s\n", packet->pkt.user_id->name ); - } - return 0; -} - - -static int -parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) -{ - byte *p; - - 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++ ) - *p = iobuf_get_noeof(inp); - - if( list_mode ) { - int n = packet->pkt.comment->len; - printf(":%scomment packet: \"", pkttype == PKT_OLD_COMMENT? - "OpenPGP draft " : "" ); - for(p=packet->pkt.comment->data; n; p++, n-- ) { - if( *p >= ' ' && *p <= 'z' ) - putchar(*p); - else - printf("\\x%02x", *p ); - } - printf("\"\n"); - } - return 0; -} - - -static void -parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt ) -{ - 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); -} - - -static int -parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *pkt, int new_ctb ) -{ - 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 = 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); - } - else { - for( i=0; i < namelen; i++ ) - if( (c=iobuf_get(inp)) == -1 ) - break; - else - pt->name[i] = c; - } - pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4; - pt->len = pktlen; - pt->buf = inp; - pktlen = 0; - - if( list_mode ) { - printf(":literal data packet:\n" - "\tmode %c, created %lu, name=\"", - mode >= ' ' && mode <'z'? mode : '?', - (ulong)pt->timestamp ); - for(p=pt->name,i=0; i < namelen; p++, i++ ) { - if( *p >= ' ' && *p <= 'z' ) - putchar(*p); - else - printf("\\x%02x", *p ); - } - printf("\",\n\traw data: %lu bytes\n", (ulong)pt->len ); - } - - leave: - return rc; -} - - -static int -parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, - PACKET *pkt, int new_ctb ) -{ - PKT_compressed *zd; - - /* pktlen is here 0, but data follows - * (this should be the last object in a file or - * the compress algorithm should know the length) - */ - zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed ); - zd->algorithm = iobuf_get_noeof(inp); - zd->len = 0; /* not used */ - zd->new_ctb = new_ctb; - zd->buf = inp; - if( list_mode ) - printf(":compressed packet: algo=%d\n", zd->algorithm); - return 0; -} - - -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 = 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 some sanity - checks on the packet 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; - if( pkttype == PKT_ENCRYPTED_MDC ) { - /* fixme: add some pktlen sanity checks */ - int version; - - 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 = DIGEST_ALGO_SHA1; - } - 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( 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 ) - printf("\tmdc_method: %d\n", ed->mdc_method ); - } - - ed->buf = inp; - pktlen = 0; - - leave: - return rc; -} - - -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= 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; - for( ; pktlen; pktlen--, p++ ) - *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 deleted file mode 100644 index d84d6e88b..000000000 --- a/g10/passphrase.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* passphrase.c - Get a passphrase - * 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 <stddef.h> -#include <stdio.h> -#include <stdlib.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> -#endif -#if defined (__MINGW32__) || defined (__CYGWIN32__) -# include <windows.h> -#endif -#include <errno.h> -#ifdef HAVE_LOCALE_H -#include <locale.h> -#endif - -#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" - - -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))) -#define u32tobuf( p, a ) do { \ - ((byte*)p)[0] = (byte)((a) >> 24); \ - ((byte*)p)[1] = (byte)((a) >> 16); \ - ((byte*)p)[2] = (byte)((a) >> 8); \ - ((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 -have_static_passphrase() -{ - if ( opt.use_agent ) - return 0; - return !!fd_passwd; -} - -/**************** - * Set the passphrase to be used for the next query and only for the next - * one. - */ -void -set_next_passphrase( const char *s ) -{ - m_free(next_pw); - next_pw = NULL; - if( s ) { - next_pw = m_alloc_secure( strlen(s)+1 ); - strcpy(next_pw, s ); - } -} - -/**************** - * Get the last passphrase used in passphrase_to_dek. - * Note: This removes the passphrase from this modules and - * the caller must free the result. May return NULL: - */ -char * -get_last_passphrase() -{ - char *p = last_pw; - last_pw = NULL; - return p; -} - - -void -read_passphrase_from_fd( int fd ) -{ - int i, len; - char *pw; - - if ( opt.use_agent ) - return; /* not used here */ - - if( !opt.batch ) - tty_printf("Reading passphrase from file descriptor %d ...", fd ); - for( pw = NULL, i = len = 100; ; i++ ) { - if( i >= len-1 ) { - char *pw2 = pw; - len += 100; - pw = m_alloc_secure( len ); - if( pw2 ) - memcpy(pw, pw2, i ); - else - i=0; - } - if( read( fd, pw+i, 1) != 1 || pw[i] == '\n' ) - break; - } - pw[i] = 0; - if( !opt.batch ) - tty_printf("\b\b\b \n" ); - - 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; - int nwritten; - - while( nleft > 0 ) { - nwritten = write( fd, buf, nleft ); - if( nwritten < 0 ) { - if ( errno == EINTR ) - nwritten = 0; - else { - log_error ( "write() failed: %s\n", strerror (errno) ); - return -1; - } - } - nleft -= nwritten; - buf = (const char*)buf + nwritten; - } -#endif - - return 0; -} - - -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; - - p = buf; - while( nleft > 0 ) { - nread = read ( fd, buf, nleft ); - if( nread < 0 ) { - if (nread == EINTR) - nread = 0; - else { - log_error ( "read() error: %s\n", strerror (errno) ); - return -1; - } - } - else if( !nread ) - break; /* EOF */ - nleft -= nread; - buf = (char*)buf + 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__*/ - - -/* - * Open a connection to the agent and send the magic string - * Returns: -1 on error or an filedescriptor for urther processing - */ - -static int -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 ); - } - - if ( !(p = strchr ( infostr, ':')) || p == infostr - || (p-infostr)+1 >= sizeof client_addr.sun_path ) { - log_error( _("malformed GPG_AGENT_INFO environment variable\n")); - m_free (infostr ); - opt.use_agent = 0; - return -1; - } - *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) ); - 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 ); - len = offsetof (struct sockaddr_un, sun_path) - + strlen(client_addr.sun_path) + 1; - - if( connect( fd, (struct sockaddr*)&client_addr, len ) == -1 ) { - log_error ( _("can't connect to `%s': %s\n"), - infostr, strerror (errno) ); - m_free (infostr ); - close (fd ); - opt.use_agent = 0; - return -1; - } - m_free (infostr); - - 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); - 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__ */ - - - -/* - * Ask the GPG Agent for the passphrase. - * Mode 0: Allow cached passphrase - * 1: No cached passphrase FIXME: Not really implemented - * 2: Ditto, but change the text to "repeat entry" - */ -static char * -agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) -{ -#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 -#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 = 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 = 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; - 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; - } - 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; - } - pw[pwlen] = 0; /* make a C String */ - agent_close (fd); - free_public_key( pk ); - return pw; - } - else if ( reply == GPGA_PROT_CANCELED ) - log_info ( _("cancelled by user\n") ); - else - log_error ( _("problem with the agent: agent returns 0x%lx\n"), - (ulong)reply ); - } - else - { /* The new Assuan protocol */ - char *line, *p; - const unsigned char *s; - 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, s=tryagain_text; *s; s++) - { - if (*s < ' ' || *s == '+') - { - sprintf (p, "%%%02X", *s); - p += 3; - } - else if (*s == ' ') - *p++ = '+'; - else - *p++ = *s; - } - *p++ = ' '; - *p++ = 'X'; /* Use the standard prompt */ - *p++ = ' '; - /* copy description */ - for (i=0, s= atext; *s; s++) - { - if (*s < ' ' || *s == '+') - { - sprintf (p, "%%%02X", *s); - p += 3; - } - else if (*s == ' ') - *p++ = '+'; - else - *p++ = *s; - } - *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: - m_free (atext); - if ( fd != -1 ) - agent_close (fd); - m_free (pw ); - free_public_key( pk ); - - return NULL; -#endif /* Posix or W32 */ -} - -/* - * Clear the cached passphrase - */ -void -passphrase_clear_cache ( u32 *keyid, int algo ) -{ -#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 - - if (!opt.use_agent) - return; - - pk = m_alloc_clear ( sizeof *pk ); - 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 */ - } - - { - size_t dummy; - fingerprint_from_pk( pk, fpr, &dummy ); - } - - 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; - - /* get response */ - if ( readn ( fd, buf, 8, &nread ) ) - goto failure; - - 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 ); - } - } - 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 ); -#endif /* Posix or W32 */ -} - - - - -/**************** - * Get a passphrase for the secret key with KEYID, display TEXT - * if the user needs to enter the passphrase. - * mode 0 = standard, 2 = create new passphrase - * Returns: a DEK with a session key; caller must free - * or NULL if the passphrase was not correctly repeated. - * (only for mode 2) - * a dek->keylen of 0 means: no passphrase entered. - * (only for mode 2) - * pubkey_algo is only informational. - */ -DEK * -passphrase_to_dek( u32 *keyid, int pubkey_algo, - 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; - s2k->hash_algo = algo; - } - - if( !next_pw && is_status_enabled() ) { - char buf[50]; - - if( keyid ) { - 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 { - sprintf( buf, "%d %d %d", cipher_algo, s2k->mode, s2k->hash_algo ); - write_status_text( STATUS_NEED_PASSPHRASE_SYM, buf ); - } - } - - if( keyid && !opt.batch && !next_pw ) { - PKT_public_key *pk = m_alloc_clear( sizeof *pk ); - size_t n; - char *p; - - tty_printf(_("\nYou need a passphrase to unlock the secret key for\n" - "user: \"") ); - p = get_user_id( keyid, &n ); - tty_print_utf8_string( p, n ); - m_free(p); - tty_printf("\"\n"); - - if( !get_pubkey( pk, keyid ) ) { - 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) ); - if( keyid[2] && keyid[3] && keyid[0] != keyid[2] - && keyid[1] != keyid[3] ) - tty_printf( _(" (main key ID %08lX)"), (ulong)keyid[3] ); - tty_printf("\n"); - } - - tty_printf("\n"); - 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, 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, NULL ); - if (!pw2) - { - if (!opt.use_agent) - { - m_free (pw); - pw = NULL; - goto agent_died; - } - pw2 = m_strdup (""); - } - if( strcmp(pw, pw2) ) { - m_free(pw2); - m_free(pw); - return NULL; - } - m_free(pw2); - } - } - else if( fd_passwd ) { - 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 = m_strdup( "" ); /* return an empty passphrase */ - } - else { - pw = cpr_get_hidden("passphrase.enter", _("Enter passphrase: ") ); - tty_kill_prompt(); - if( mode == 2 && !cpr_enabled() ) { - char *pw2 = cpr_get_hidden("passphrase.repeat", - _("Repeat passphrase: ") ); - tty_kill_prompt(); - if( strcmp(pw, pw2) ) { - m_free(pw2); - m_free(pw); - return NULL; - } - m_free(pw2); - } - } - - if( !pw || !*pw ) - write_status( STATUS_MISSING_PASSPHRASE ); - - 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 ); - m_free(last_pw); - last_pw = pw; - return dek; -} - - -/**************** - * Hash a passphrase using the supplied s2k. If create is true, create - * a new salt or what else must be filled into the s2k for a new key. - * always needs: dek->algo, s2k->mode, s2k->hash_algo. - */ -static void -hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create ) -{ - MD_HANDLE md; - int pass, i; - int used = 0; - int pwlen = strlen(pw); - - assert( s2k->hash_algo ); - dek->keylen = cipher_get_keylen( dek->algo ) / 8; - if( !(dek->keylen > 0 && dek->keylen <= DIM(dek->key)) ) - BUG(); - - md = md_open( s2k->hash_algo, 1); - for(pass=0; used < dek->keylen ; pass++ ) { - if( pass ) { - md_reset(md); - for(i=0; i < pass; i++ ) /* preset the hash context */ - md_putc(md, 0 ); - } - - if( s2k->mode == 1 || s2k->mode == 3 ) { - int len2 = pwlen + 8; - ulong count = len2; - - if( create && !pass ) { - randomize_buffer(s2k->salt, 8, 1); - if( s2k->mode == 3 ) - s2k->count = 96; /* 65536 iterations */ - } - - if( s2k->mode == 3 ) { - count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6); - if( count < len2 ) - count = len2; - } - /* a little bit complicated because we need a ulong for count */ - while( count > len2 ) { /* maybe iterated+salted */ - md_write( md, s2k->salt, 8 ); - md_write( md, pw, pwlen ); - count -= len2; - } - if( count < 8 ) - md_write( md, s2k->salt, count ); - else { - md_write( md, s2k->salt, 8 ); - count -= 8; - md_write( md, pw, count ); - } - } - else - 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, md_read(md, s2k->hash_algo), i ); - used += i; - } - md_close(md); -} - diff --git a/g10/photoid.c b/g10/photoid.c deleted file mode 100644 index c20e20eca..000000000 --- a/g10/photoid.c +++ /dev/null @@ -1,332 +0,0 @@ -/* 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 __MINGW32__ -# include <windows.h> -# ifndef VER_PLATFORM_WIN32_WINDOWS -# define VER_PLATFORM_WIN32_WINDOWS 1 -# endif -#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; - -#define EXTRA_UID_NAME_SPACE 71 - uid=m_alloc_clear(sizeof(*uid)+71); - - 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, EXTRA_UID_NAME_SPACE); - - /* 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) -{ - u16 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; -} - -#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER) -static const char *get_default_photo_command(void) -{ -#if defined(__MINGW32__) - 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 -} -#endif - -void show_photos(const struct user_attribute *attrs, - int count,PKT_public_key *pk,PKT_secret_key *sk) -{ -#ifndef DISABLE_PHOTO_VIEWER - 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; - -#ifdef FIXED_PHOTO_VIEWER - opt.photo_viewer=FIXED_PHOTO_VIEWER; -#else - if(!opt.photo_viewer) - opt.photo_viewer=get_default_photo_command(); -#endif - - /* 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"); -#endif -} diff --git a/g10/photoid.h b/g10/photoid.h deleted file mode 100644 index 45d104f8c..000000000 --- a/g10/photoid.h +++ /dev/null @@ -1,14 +0,0 @@ -/* 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/pkclist.c b/g10/pkclist.c deleted file mode 100644 index cb1c506e3..000000000 --- a/g10/pkclist.c +++ /dev/null @@ -1,1303 +0,0 @@ -/* pkclist.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.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 "photoid.h" -#include "i18n.h" - - -#define CONTROL_D ('D' - 'A' + 1) - - -/**************** - * Show the revocation reason as it is stored with the given signature - */ -static void -do_show_revocation_reason( PKT_signature *sig ) -{ - size_t n, nn; - const byte *p, *pp; - int seq = 0; - const char *text; - - 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 superseded"); - else if( *p == 0x02 ) - text = _("Key has been compromised"); - else if( *p == 0x03 ) - text = _("Key is no longer used"); - else if( *p == 0x20 ) - text = _("User ID is no longer valid"); - else - text = NULL; - - log_info( _("reason for revocation: ") ); - if( text ) - fputs( text, log_stream() ); - else - fprintf( log_stream(), "code=%02x", *p ); - putc( '\n', log_stream() ); - n--; p++; - pp = NULL; - do { - /* We don't want any empty lines, so skip them */ - while( n && *p == '\n' ) { - p++; - n--; - } - if( n ) { - pp = memchr( p, '\n', n ); - nn = pp? pp - p : n; - log_info( _("revocation comment: ") ); - print_string( log_stream(), p, nn, 0 ); - putc( '\n', log_stream() ); - p += nn; n -= nn; - } - } while( pp ); - } -} - -/* 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 */ - -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 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; - 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( "failed to get the keyblock\n"); - return; - } - - for( node=keyblock; node; node = node->next ) { - 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 ) ) ) - break; - } - if( !node ) { - log_debug("Oops, PK not in keyblock\n"); - release_kbnode( keyblock ); - return; - } - /* now find the revocation certificate */ - for( node = node->next; node ; node = node->next ) { - if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - break; - if( node->pkt->pkttype == PKT_SIGNATURE - && (node->pkt->pkt.signature->sig_class == 0x20 - || 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 (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; - - last_level = 0; - while( (level=enum_cert_paths( &context, &lid, &otrust, &validity)) != -1){ - char *p; - int c, rc; - size_t n; - u32 keyid[2]; - PKT_public_key *pk ; - - if( level < last_level && only_first ) - break; - 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 = 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], g10_errstr(rc) ); - return; - } - - tty_printf("%*s%4u%c/%08lX.%lu %s \"", - level*2, "", - nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), - (ulong)keyid[1], lid, datestr_from_pk( pk ) ); - - c = trust_letter(otrust); - if( c ) - putchar( c ); - else - printf( "%02x", otrust ); - putchar('/'); - c = trust_letter(validity); - if( c ) - putchar( c ); - else - printf( "%02x", validity ); - putchar(' '); - - p = get_user_id( keyid, &n ); - tty_print_utf8_string( p, n ), - m_free(p); - tty_printf("\"\n"); - free_public_key( pk ); - } - enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */ -#endif - tty_printf("\n"); -} - - - - -/**************** - * 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 (PKT_public_key *pk, int mode, - unsigned *new_trust, int defer_help ) -{ - 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 ) - { - KBNODE keyblock, un; - - 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"); - - keyblock = get_pubkeyblock (keyid); - if (!keyblock) - BUG (); - 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_expired ) - continue; - /* Only skip textual primaries */ - if (un->pkt->pkt.user_id->is_primary && - !un->pkt->pkt.user_id->attrib_data ) - continue; - - if(opt.show_photos && un->pkt->pkt.user_id->attrib_data) - show_photos(un->pkt->pkt.user_id->attribs, - un->pkt->pkt.user_id->numattribs,pk,NULL); - - tty_printf (" %s", _(" aka \"")); - tty_print_utf8_string (un->pkt->pkt.user_id->name, - un->pkt->pkt.user_id->len ); - 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); -#if 0 - /* not yet implemented */ - tty_printf (_(" i = please show me more information\n") ); -#endif - 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; - } - } -#if 0 - /* not yet implemented */ - else if( *p == ans[0] || *p == ans[1] ) - { - tty_printf(_("Certificates leading to an ultimately trusted key:\n")); - show = 1; - break; - } -#endif - 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 (PKT_public_key *pk, int mode ) -{ - 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; - } - } -} - - -/**************** - * Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL - * Returns: true if we trust. - */ -static int -do_we_trust( PKT_public_key *pk, unsigned int *trustlevel ) -{ - 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, 0 ); - if( opt.batch ) - return 0; /* no */ - - if( !cpr_get_answer_is_yes("revoked_key.override", - _("Use this key anyway? ")) ) - return 0; /* no */ - trustmask |= TRUST_FLAG_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, 0 ); - if( opt.batch ) - return 0; - - if( !cpr_get_answer_is_yes("revoked_key.override", - _("Use this key anyway? ")) ) - return 0; - trustmask |= TRUST_FLAG_SUB_REVOKED; - } - *trustlevel &= ~trustmask; - - if( opt.always_trust) { - if( opt.verbose ) - log_info("No trust check due to --always-trust option\n"); - return 1; - } - - switch( (*trustlevel & TRUST_MASK) ) { - 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: - 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"), - (ulong)keyid_from_pk( pk, NULL) ); - return 0; /* no */ - - case TRUST_MARGINAL: - log_info( - _("%08lX: It is not sure that this key really belongs to the owner\n" - "but it is accepted anyway\n"), (ulong)keyid_from_pk( pk, NULL) ); - return 1; /* yes */ - - case TRUST_FULLY: - if( opt.verbose ) - log_info(_("This key probably belongs to the owner\n")); - return 1; /* yes */ - - case TRUST_ULTIMATE: - if( opt.verbose ) - log_info(_("This key belongs to us\n")); - return 1; /* yes */ - } - - return 1; /* yes */ -} - - - -/**************** - * wrapper around do_we_trust, so we can ask whether to use the - * key anyway. - */ -static int -do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel ) -{ - int rc; - - rc = do_we_trust( pk, &trustlevel ); - - if( (trustlevel & TRUST_FLAG_REVOKED) && !rc ) - return 0; - if( (trustlevel & TRUST_FLAG_SUB_REVOKED) && !rc ) - return 0; - - if( !opt.batch && !rc ) { - char *p; - u32 keyid[2]; - size_t n; - - keyid_from_pk( pk, keyid); - tty_printf( "%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(_( -"It is NOT certain that the key belongs to the person named\n" -"in the user ID. If you *really* know what you are doing,\n" -"you may answer the next question with yes\n\n")); - - if( cpr_get_answer_is_yes("untrusted_key.override", - _("Use this key anyway? ")) ) - rc = 1; - - /* Hmmm: Should we set a flag to tell the user about - * his decision the next time he encrypts for this recipient? - */ - } - else if( opt.always_trust && !rc ) { - if( !opt.quiet ) - log_info(_("WARNING: Using untrusted key!\n")); - rc = 1; - } - return rc; -} - - - -/**************** - * Check whether we can trust this signature. - * Returns: Error if we shall not trust this signatures. - */ -int -check_signatures_trust( PKT_signature *sig ) -{ - 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 = G10ERR_NO_PUBKEY; - goto leave; - } - - trustlevel = get_validity (pk, NULL); - - 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, 0 ); - } - - 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; -} - - -void -release_pk_list( PK_LIST pk_list ) -{ - PK_LIST pk_rover; - - for( ; pk_list; pk_list = pk_rover ) { - pk_rover = pk_list->next; - free_public_key( pk_list->pk ); - m_free( pk_list ); - } -} - - -static int -key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk) -{ - for( ; pk_list; pk_list = pk_list->next) - if (cmp_public_keys(pk_list->pk, pk) == 0) - return 0; - - return -1; -} - - -/**************** - * Return a malloced string with a default reciepient if there is any - */ -static char * -default_recipient(void) -{ - PKT_secret_key *sk; - byte fpr[MAX_FINGERPRINT_LEN+1]; - size_t n; - char *p; - int i; - - if( opt.def_recipient ) - return m_strdup( opt.def_recipient ); - if( !opt.def_recipient_self ) - return NULL; - sk = m_alloc_clear( sizeof *sk ); - i = get_seckey_byname( sk, NULL, 0 ); - if( i ) { - free_secret_key( sk ); - return NULL; - } - n = MAX_FINGERPRINT_LEN; - fingerprint_from_sk( sk, fpr, &n ); - free_secret_key( sk ); - p = m_alloc( 2*n+3 ); - *p++ = '0'; - *p++ = 'x'; - for(i=0; i < n; i++ ) - sprintf( p+2*i, "%02X", fpr[i] ); - p -= 2; - 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 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,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 & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) { - pk = m_alloc_clear( sizeof *pk ); - pk->req_usage = use; - if( (rc = get_pubkey_byname( pk, rov->d, NULL, NULL )) ) { - free_public_key( pk ); pk = NULL; - 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); - goto fail; - } - 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) { - free_public_key(pk); pk = NULL; - log_info(_("%s: skipped: public key already present\n"), - rov->d); - } - else { - PK_LIST r; - r = m_alloc( sizeof *r ); - r->pk = pk; pk = NULL; - r->next = pk_list; - r->mark = 0; - pk_list = r; - } - } - else { - free_public_key( pk ); pk = NULL; - 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); - goto fail; - } - } - } - - if( !any_recipients && !opt.batch ) { /* ask */ - 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")); - for(;;) { - rc = 0; - 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", - _("\nEnter the user ID. End with an empty line: ")); - trim_spaces(answer); - cpr_kill_prompt(); - } - if( !answer || !*answer ) { - m_free(answer); - break; - } - if(expand_id(answer,&backlog,0)) - continue; - if( pk ) - free_public_key( pk ); - pk = m_alloc_clear( sizeof *pk ); - pk->req_usage = use; - rc = get_pubkey_byname( pk, answer, NULL, NULL ); - if( rc ) - tty_printf(_("No such user ID.\n")); - 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; - 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; - continue; - } - else { - int trustlevel; - - 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 ) ) { - /* Skip the actual key if the key is already present - * 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\n") ); - } - else { - PK_LIST 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; - continue; - } - } - } - m_free(def_rec); def_rec = NULL; - have_def_rec = 0; - } - if( pk ) { - free_public_key( pk ); - pk = NULL; - } - } - else if( !any_recipients && (def_rec = default_recipient()) ) { - pk = m_alloc_clear( sizeof *pk ); - pk->req_usage = use; - rc = get_pubkey_byname( pk, def_rec, NULL, NULL ); - if( rc ) - log_error(_("unknown default recipient `%s'\n"), def_rec ); - 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; - } - } - if( pk ) { - free_public_key( pk ); - pk = NULL; - } - m_free(def_rec); def_rec = NULL; - } - else { - any_recipients = 0; - for(; remusr; remusr = remusr->next ) { - if( (remusr->flags & 1) ) - continue; /* encrypt-to keys are already handled */ - - pk = m_alloc_clear( sizeof *pk ); - pk->req_usage = use; - if( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL )) ) { - free_public_key( pk ); pk = NULL; - 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); - goto fail; - } - else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) { - int trustlevel; - - 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); - rc=G10ERR_UNU_PUBKEY; - goto fail; - } - else if( do_we_trust_pre( pk, trustlevel ) ) { - /* note: do_we_trust may have changed the trustlevel */ - - /* We have at least one valid recipient. It doesn't matters - * if this recipient is already present. */ - any_recipients = 1; - - /* Skip the actual key if the key is already present - * in the list */ - if (key_present_in_pk_list(pk_list, pk) == 0) { - free_public_key(pk); pk = NULL; - log_info(_("%s: skipped: public key already present\n"), - remusr->d); - } - else { - PK_LIST r; - r = m_alloc( sizeof *r ); - r->pk = pk; pk = NULL; - r->next = pk_list; - r->mark = 0; - pk_list = r; - } - } - else { /* we don't trust this pk */ - free_public_key( pk ); pk = NULL; - write_status_text_and_buffer (STATUS_INV_RECP, "10 ", - remusr->d, - strlen (remusr->d), - -1); - rc=G10ERR_UNU_PUBKEY; - goto fail; - } - } - else { - free_public_key( pk ); pk = NULL; - 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) ); - goto fail; - } - } - } - - if( !rc && !any_recipients ) { - log_error(_("no valid addressees\n")); - write_status_text (STATUS_NO_RECP, "0"); - rc = G10ERR_NO_USER_ID; - } - - fail: - - 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, void *hint ) -{ - if( preftype == PREFTYPE_SYM ) { - 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 ) { - 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_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, int request, void *hint) -{ - PK_LIST pkr; - u32 bits[8]; - const prefitem_t *prefs; - int i, j; - int compr_hack=0; - int any; - - if( !pk_list ) - return -1; - - memset( bits, ~0, 8 * sizeof *bits ); - for( pkr = pk_list; pkr; pkr = pkr->next ) { - u32 mask[8]; - - memset( mask, 0, 8 * sizeof *mask ); - 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 */ - } - 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( 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( (!prefs || !any) && preftype == PREFTYPE_ZIP ) { - mask[0] |= 3; /* asume no_compression and old pgp */ - compr_hack = 1; - } - - #if 0 - 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("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 - } - /* usable algorithms are now in bits - * We now use the last key from pk_list to select - * the algorithm we want to use. there are no - * preferences for the last key, we select the one - * corresponding to first set bit. - */ - i = -1; - any = 0; - - /* Can we use the requested algorithm? */ - if(request>-1 && (bits[request/32] & (1<<(request%32))) && - algo_available(preftype,request,hint)) - return request; - - /* 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 = prefs[j].value; - break; - } - } - } - } - } - if( !prefs || !any ) { - for(j=0; j < 256; j++ ) - if( (bits[j/32] & (1<<(j%32))) ) { - if( algo_available( preftype, j, hint ) ) { - i = j; - break; - } - } - } - - #if 0 - log_debug("prefs of type %d: selected %d\n", preftype, i ); - #endif - if( compr_hack && !i ) { - /* selected no compression, but we should check whether - * algorithm 1 is also available (the ordering is not relevant - * in this case). */ - if( bits[0] & (1<<1) ) - i = 1; /* yep; we can use compression algo 1 */ - } - - /* "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 deleted file mode 100644 index b12fb0f11..000000000 --- a/g10/plaintext.c +++ /dev/null @@ -1,418 +0,0 @@ -/* plaintext.c - process plaintext packets - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#ifdef HAVE_DOSISH_SYSTEM - #include <fcntl.h> /* for setmode() */ -#endif - -#include "util.h" -#include "memory.h" -#include "options.h" -#include "packet.h" -#include "ttyio.h" -#include "filter.h" -#include "main.h" -#include "status.h" -#include "i18n.h" - - - -/**************** - * Handle a plaintext packet. If MFX is not NULL, update the MDs - * Note: we should use the filter stuff here, but we have to add some - * easy mimic to set a read limit, so we calculate only the - * bytes from the plaintext. - */ -int -handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, - int nooutput, int clearsig ) -{ - char *fname = NULL; - FILE *fp = NULL; - int rc = 0; - int c; - int convert = pt->mode == 't'; - - /* create the filename as C string */ - if( nooutput ) - ; - else if( opt.outfile ) { - fname = m_alloc( strlen( opt.outfile ) + 1); - strcpy(fname, opt.outfile ); - } - else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) { - log_info(_("data not saved; use option \"--output\" to save it\n")); - nooutput = 1; - } - else if( !opt.use_embedded_filename ) { - fname = make_outfile_name( iobuf_get_real_fname(pt->buf) ); - if( !fname ) - fname = ask_outfile_name( pt->name, pt->namelen ); - if( !fname ) { - rc = G10ERR_CREATE_FILE; - goto leave; - } - } - else { - fname = make_printable_string( pt->name, pt->namelen, 0 ); - } - - if( nooutput ) - ; - else if( !*fname || (*fname=='-' && !fname[1])) { - /* no filename or "-" given; write to stdout */ - fp = stdout; - #ifdef HAVE_DOSISH_SYSTEM - setmode ( fileno(fp) , O_BINARY ); - #endif - } - 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 = 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->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 = G10ERR_READ_FILE; - goto leave; - } - if( mfx->md ) - 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 */ - #endif - if( fp ) { - if( putc( c, fp ) == EOF ) { - log_error("Error writing to `%s': %s\n", - fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; - goto leave; - } - } - } - } - else { /* binary mode */ - 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 = G10ERR_READ_FILE; - m_free( buffer ); - goto leave; - } - if( mfx->md ) - 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 = G10ERR_WRITE_FILE; - m_free( buffer ); - goto leave; - } - } - pt->len -= len; - } - m_free( buffer ); - } - } - else if( !clearsig ) { - if( convert ) { /* text mode */ - while( (c = iobuf_get(pt->buf)) != -1 ) { - if( mfx->md ) - md_putc(mfx->md, c ); - #ifndef HAVE_DOSISH_SYSTEM - if( convert && c == '\r' ) - continue; /* fixme: this hack might be too simple */ - #endif - if( fp ) { - if( putc( c, fp ) == EOF ) { - log_error("Error writing to `%s': %s\n", - fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; - goto leave; - } - } - } - } - else { /* binary mode */ - byte *buffer = m_alloc( 32768 ); - int eof; - for( eof=0; !eof; ) { - /* Why do we check for len < 32768: - * If we won't, we would practically read 2 EOFs but - * the first one has already popped the block_filter - * off and therefore we don't catch the boundary. - * So, always assume EOF if iobuf_read returns less bytes - * then requested */ - int len = iobuf_read( pt->buf, buffer, 32768 ); - if( len == -1 ) - break; - if( len < 32768 ) - eof = 1; - if( mfx->md ) - 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 = G10ERR_WRITE_FILE; - m_free( buffer ); - goto leave; - } - } - } - m_free( buffer ); - } - pt->buf = NULL; - } - else { /* clear text signature - don't hash the last cr,lf */ - int state = 0; - - while( (c = iobuf_get(pt->buf)) != -1 ) { - if( fp ) { - if( putc( c, fp ) == EOF ) { - log_error("Error writing to `%s': %s\n", - fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; - goto leave; - } - } - if( !mfx->md ) - continue; - if( state == 2 ) { - md_putc(mfx->md, '\r' ); - md_putc(mfx->md, '\n' ); - state = 0; - } - if( !state ) { - if( c == '\r' ) - state = 1; - else if( c == '\n' ) - state = 2; - else - md_putc(mfx->md, c ); - } - else if( state == 1 ) { - if( c == '\n' ) - state = 2; - else { - md_putc(mfx->md, '\r' ); - if( c == '\r' ) - state = 1; - else { - state = 0; - md_putc(mfx->md, c ); - } - } - } - } - pt->buf = NULL; - } - - if( fp && fp != stdout && fclose(fp) ) { - log_error("Error closing `%s': %s\n", fname, strerror(errno) ); - fp = NULL; - rc = G10ERR_WRITE_FILE; - goto leave; - } - fp = NULL; - - leave: - if( fp && fp != stdout ) - fclose(fp); - m_free(fname); - return rc; -} - -static void -do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode ) -{ - text_filter_context_t tfx; - int c; - - if( textmode ) { - memset( &tfx, 0, sizeof tfx); - iobuf_push_filter( fp, text_filter, &tfx ); - } - if( md2 ) { /* work around a strange behaviour in pgp2 */ - /* It seems that at least PGP5 converts a single CR to a CR,LF too */ - int lc = -1; - while( (c = iobuf_get(fp)) != -1 ) { - if( c == '\n' && lc == '\r' ) - md_putc(md2, c); - else if( c == '\n' ) { - md_putc(md2, '\r'); - md_putc(md2, c); - } - else if( c != '\n' && lc == '\r' ) { - md_putc(md2, '\n'); - md_putc(md2, c); - } - else - md_putc(md2, c); - - if( md ) - md_putc(md, c ); - lc = c; - } - } - else { - while( (c = iobuf_get(fp)) != -1 ) { - if( md ) - md_putc(md, c ); - } - } -} - - -/**************** - * Ask for the detached datafile and calculate the digest from it. - * INFILE is the name of the input file. - */ -int -ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2, - const char *inname, int textmode ) -{ - char *answer = NULL; - IOBUF fp; - int rc = 0; - - fp = open_sigfile( inname ); /* open default file */ - if( !fp && !opt.batch ) { - int any=0; - tty_printf(_("Detached signature.\n")); - do { - m_free(answer); - answer = cpr_get("detached_signature.filename", - _("Please enter name of data file: ")); - cpr_kill_prompt(); - if( any && !*answer ) { - rc = G10ERR_READ_FILE; - goto leave; - } - fp = iobuf_open(answer); - if( !fp && errno == ENOENT ) { - tty_printf("No such file, try again or hit enter to quit.\n"); - any++; - } - else if( !fp ) { - log_error("can't open `%s': %s\n", answer, strerror(errno) ); - rc = G10ERR_READ_FILE; - goto leave; - } - } while( !fp ); - } - - if( !fp ) { - if( opt.verbose ) - log_info(_("reading stdin ...\n")); - fp = iobuf_open( NULL ); - assert(fp); - } - do_hash( md, md2, fp, textmode ); - iobuf_close(fp); - - - leave: - m_free(answer); - return rc; -} - - - -/**************** - * Hash the given files and append the hash to hash context md. - * If FILES is NULL, hash stdin. - */ -int -hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files, - const char *sigfilename, int textmode ) -{ - IOBUF fp; - STRLIST sl; - - if( !files ) { - /* check whether we can open the signed material */ - fp = open_sigfile( sigfilename ); - if( fp ) { - do_hash( md, md2, fp, textmode ); - iobuf_close(fp); - return 0; - } - log_error (_("no signed data\n")); - return G10ERR_OPEN_FILE; - } - - - 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)); - return G10ERR_OPEN_FILE; - } - do_hash( md, md2, fp, textmode ); - iobuf_close(fp); - } - - return 0; -} - - - - - diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c deleted file mode 100644 index 2c8771c27..000000000 --- a/g10/pubkey-enc.c +++ /dev/null @@ -1,296 +0,0 @@ -/* pubkey-enc.c - public key encoded packet handling - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.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" -#include "i18n.h" - -static int get_it( PKT_pubkey_enc *k, - DEK *dek, PKT_secret_key *sk, u32 *keyid ); - - -/* check that the given algo is mentioned in one of the valid user IDs */ -static int -is_algo_in_prefs ( KBNODE keyblock, preftype_t type, int algo ) -{ - 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; - } - } - } - return 0; -} - - -/**************** - * Get the session key from a pubkey enc packet and return - * it in DEK, which should have been allocated in secure memory. - */ -int -get_session_key( PKT_pubkey_enc *k, DEK *dek ) -{ - PKT_secret_key *sk = NULL; - int rc; - - 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 = 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 ); - } - else { /* anonymous receiver: Try all available secret keys */ - void *enum_context = NULL; - u32 keyid[2]; - - for(;;) { - if( sk ) - free_secret_key( sk ); - sk = m_alloc_clear( sizeof *sk ); - rc=enum_secret_keys( &enum_context, sk, 1); - if( rc ) { - rc = G10ERR_NO_SECKEY; - break; - } - if( sk->pubkey_algo != k->pubkey_algo ) - continue; - keyid_from_sk( sk, keyid ); - 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 ); - if( !rc ) { - log_info(_("okay, we are the anonymous recipient.\n") ); - break; - } - } - enum_secret_keys( &enum_context, NULL, 0 ); /* free context */ - } - - leave: - if( sk ) - free_secret_key( sk ); - return rc; -} - - -static int -get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) -{ - int rc; - MPI plain_dek = NULL; - byte *frame = NULL; - unsigned n, nframe; - u16 csum, csum2; - - rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey ); - if( rc ) - goto leave; - 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 - * - * Old versions encode the DEK in in this format (msb is left): - * - * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 - * - * Later versions encode the DEK like this: - * - * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) - * - * (mpi_get_buffer already removed the leading zero). - * - * RND are non-zero randow bytes. - * A is the cipher algorithm - * DEK is the encryption key (session key) with length k - * CSUM - */ - if( DBG_CIPHER ) - log_hexdump("DEK frame:", frame, nframe ); - n=0; - if( n + 7 > nframe ) - { 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 = G10ERR_CIPHER_ALGO; - goto leave; - } - if( frame[n] != 2 ) /* somethink is wrong */ - { 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 = G10ERR_WRONG_SECKEY; goto leave; } - - dek->keylen = nframe - (n+1) - 2; - dek->algo = frame[n++]; - if( dek->algo == CIPHER_ALGO_IDEA ) - write_status(STATUS_RSA_OR_IDEA); - rc = check_cipher_algo( dek->algo ); - if( rc ) { - 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*8) != cipher_get_keylen( dek->algo ) ) { - rc = G10ERR_WRONG_SECKEY; - goto leave; - } - - /* copy the key to DEK and compare the checksum */ - csum = frame[nframe-2] << 8; - csum |= frame[nframe-1]; - memcpy( dek->key, frame+n, dek->keylen ); - for( csum2=0, n=0; n < dek->keylen; n++ ) - csum2 += dek->key[n]; - if( csum != csum2 ) { - 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 = 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 != 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) { - 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_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 deleted file mode 100644 index b6e9e6398..000000000 --- a/g10/revoke.c +++ /dev/null @@ -1,717 +0,0 @@ -/* revoke.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <ctype.h> - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "main.h" -#include "ttyio.h" -#include "status.h" -#include "i18n.h" - - -struct revocation_reason_info { - int code; - char *desc; -}; - - -int -revocation_reason_build_cb( PKT_signature *sig, void *opaque ) -{ - struct revocation_reason_info *reason = opaque; - char *ud = NULL; - byte *buffer; - size_t buflen = 1; - - if(!reason) - return 0; - - if( reason->desc ) { - ud = native_to_utf8( reason->desc ); - buflen += strlen(ud); - } - buffer = m_alloc( buflen ); - *buffer = reason->code; - if( ud ) { - memcpy(buffer+1, ud, strlen(ud) ); - m_free( ud ); - } - - build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen ); - m_free( buffer ); - return 0; -} - -/* Outputs a minimal pk (as defined by 2440) from a keyblock. A - minimal pk consists of the public key packet and a user ID. We try - and pick a user ID that has a uid signature, and include it if - possible. */ -static int -export_minimal_pk(IOBUF out,KBNODE keyblock, - PKT_signature *revsig,PKT_signature *revkey) -{ - KBNODE node; - PACKET pkt; - PKT_user_id *uid=NULL; - PKT_signature *selfsig=NULL; - u32 keyid[2]; - int rc; - - node=find_kbnode(keyblock,PKT_PUBLIC_KEY); - if(!node) - { - log_error(_("key incomplete\n")); - return G10ERR_GENERAL; - } - - keyid_from_pk(node->pkt->pkt.public_key,keyid); - - pkt=*node->pkt; - rc=build_packet(out,&pkt); - if(rc) - { - log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); - return rc; - } - - init_packet(&pkt); - pkt.pkttype=PKT_SIGNATURE; - - /* the revocation itself, if any. 2440 likes this to come first. */ - if(revsig) - { - pkt.pkt.signature=revsig; - rc=build_packet(out,&pkt); - if(rc) - { - log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); - return rc; - } - } - - /* If a revkey in a 1F sig is present, include it too */ - if(revkey) - { - pkt.pkt.signature=revkey; - rc=build_packet(out,&pkt); - if(rc) - { - log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); - return rc; - } - } - - 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 - { - log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]); - return G10ERR_GENERAL; - } - } - - 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) ); - return rc; - } - - 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) ); - return rc; - } - } - - 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; - 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_signature *revkey=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"); - if(pk->revkey[i].class&0x40) - tty_printf(_("(This is a sensitive revocation key)\n")); - tty_printf("\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. - Also include the direct key signature that contains - this revocation key. We're allowed to include - sensitive revocation keys along with a revocation, as - this may be the only time the recipient has seen it. - Note that this means that if we have multiple different - sensitive revocation keys in a given direct key - signature, we're going to include them all here. This - is annoying, but the good outweighs the bad, since - without including this a sensitive revoker can't really - do their job. People should not include multiple - sensitive revocation keys in one signature: 2440 says - "Note that it may be appropriate to isolate this - subpacket within a separate signature so that it is not - combined with other subpackets that need to be - exported." -dms */ - - while(!revkey) - { - KBNODE signode; - - signode=find_next_kbnode(node,PKT_SIGNATURE); - if(!signode) - break; - - node=signode; - - if(keyid[0]==signode->pkt->pkt.signature->keyid[0] && - keyid[1]==signode->pkt->pkt.signature->keyid[1] && - IS_KEY_SIG(signode->pkt->pkt.signature)) - { - int j; - - for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++) - { - if(pk->revkey[i].class== - signode->pkt->pkt.signature->revkey[j]->class && - pk->revkey[i].algid== - signode->pkt->pkt.signature->revkey[j]->algid && - memcmp(pk->revkey[i].fpr, - signode->pkt->pkt.signature->revkey[j]->fpr, - MAX_FINGERPRINT_LEN)==0) - { - revkey=signode->pkt->pkt.signature; - break; - } - } - } - } - - if(!revkey) - BUG(); - - rc=export_minimal_pk(out,keyblock,sig,revkey); - if(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 -gen_revoke( const char *uname ) -{ - int rc = 0; - armor_filter_context_t afx; - PACKET pkt; - PKT_secret_key *sk; /* used as pointer into a kbnode */ - PKT_public_key *pk = NULL; - PKT_signature *sig = NULL; - u32 sk_keyid[2]; - IOBUF out = NULL; - KBNODE keyblock = NULL, pub_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 G10ERR_GENERAL; - } - - memset( &afx, 0, sizeof afx); - 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; - } - - rc = keydb_get_keyblock (kdbhd, &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, PKT_SECRET_KEY ); - if( !node ) - BUG (); - - /* fixme: should make a function out of this stuff, - * it's used all over the source */ - sk = node->pkt->pkt.secret_key; - keyid_from_sk( sk, sk_keyid ); - tty_printf("\nsec %4u%c/%08lX %s ", - nbits_from_sk( sk ), - pubkey_letter( sk->pubkey_algo ), - (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 ); - m_free(p); - tty_printf("\n"); - } - pk = m_alloc_clear( sizeof *pk ); - - /* FIXME: We should get the public key direct from the secret one */ - - pub_keyblock=get_pubkeyblock(sk_keyid); - if(!pub_keyblock) - { - log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) ); - goto leave; - } - - node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY); - if(!node) - BUG(); - - pk=node->pkt->pkt.public_key; - - if( cmp_public_secret_key( pk, sk ) ) { - log_error(_("public key does not match secret key!\n") ); - rc = G10ERR_GENERAL; - goto leave; - } - - tty_printf("\n"); - if( !cpr_get_answer_is_yes("gen_revoke.okay", - _("Create a revocation certificate for this key? ")) ){ - rc = 0; - goto leave; - } - - 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 = G10ERR_PUBKEY_ALGO; - break; - case 0: - tty_printf(_("NOTE: This key is not protected!\n")); - break; - default: - rc = check_secret_key( sk, 0 ); - break; - } - if( rc ) - goto leave; - - - 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, - opt.force_v4_certs?4:0, 0, 0, - revocation_reason_build_cb, reason ); - if( rc ) { - log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc)); - goto leave; - } - - if(opt.pgp2 || opt.pgp6 || opt.pgp7) - { - /* Use a minimal pk for PGPx mode, since PGP can't import bare - revocation certificates. */ - rc=export_minimal_pk(out,pub_keyblock,sig,NULL); - if(rc) - goto leave; - } - else - { - 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; - } - } - - /* and issue a usage notice */ - tty_printf(_("Revocation certificate created.\n\n" -"Please move it to a medium which you can hide away; if Mallory gets\n" -"access to this certificate he can use it to make your key unusable.\n" -"It is smart to print this certificate and store it away, just in case\n" -"your media become unreadable. But have some caution: The print system of\n" -"your machine might store the data and make it available to others!\n")); - - leave: - if( sig ) - free_seckey_enc( sig ); - release_kbnode( keyblock ); - release_kbnode( pub_keyblock ); - keydb_release (kdbhd); - if( rc ) - iobuf_cancel(out); - else - iobuf_close(out); - release_revocation_reason_info( reason ); - return rc; -} - - - -struct revocation_reason_info * -ask_revocation_reason( int key_rev, int cert_rev, int hint ) -{ - 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 no longer valid"); - const char *code_text = NULL; - - do { - 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 ) - tty_printf(" 2 = %s\n", text_2 ); - if( key_rev ) - tty_printf(" 3 = %s\n", text_3 ); - if( cert_rev ) - tty_printf(" 4 = %s\n", text_4 ); - tty_printf( " Q = %s\n", _("Cancel") ); - if( hint ) - tty_printf(_("(Probably you want to select %d here)\n"), hint ); - - 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') - return NULL; /* cancel */ - if( hint && !*answer ) - n = hint; - else if(!isdigit( *answer ) ) - n = -1; - else - n = atoi(answer); - 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_text = text_1; - } - else if( key_rev && n == 2 ) { - code = 0x01; /* key is superseded */ - code_text = text_2; - } - else if( key_rev && n == 3 ) { - code = 0x03; /* key is no longer used */ - code_text = text_3; - } - else if( cert_rev && n == 4 ) { - code = 0x20; /* uid is no longer valid */ - code_text = text_4; - } - else - tty_printf(_("Invalid selection.\n")); - } - - tty_printf(_("Enter an optional description; " - "end it with an empty line:\n") ); - for(;;) { - char *answer = cpr_get("ask_revocation_reason.text", "> " ); - trim_trailing_ws( answer, strlen(answer) ); - cpr_kill_prompt(); - if( !*answer ) { - m_free(answer); - break; - } - - { - char *p = make_printable_string( answer, strlen(answer), 0 ); - m_free(answer); - answer = p; - } - - if( !description ) - description = m_strdup(answer); - else { - char *p = m_alloc( strlen(description) + strlen(answer) + 2 ); - strcpy(stpcpy(stpcpy( p, description),"\n"),answer); - m_free(description); - description = p; - } - m_free(answer); - } - - tty_printf(_("Reason for revocation: %s\n"), code_text ); - if( !description ) - tty_printf(_("(No description given)\n") ); - else - tty_printf("%s\n", description ); - - } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay", - _("Is this okay? ")) ); - - reason = m_alloc( sizeof *reason ); - reason->code = code; - reason->desc = description; - return reason; -} - -void -release_revocation_reason_info( struct revocation_reason_info *reason ) -{ - if( reason ) { - m_free( reason->desc ); - m_free( reason ); - } -} diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c deleted file mode 100644 index d19ac683a..000000000 --- a/g10/seckey-cert.c +++ /dev/null @@ -1,382 +0,0 @@ -/* seckey-cert.c - secret key certificate packet handling - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.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" - - -static int -do_check( PKT_secret_key *sk, const char *tryagain_text ) -{ - byte *buffer; - u16 csum=0; - int i, res; - unsigned nbytes; - - if( sk->is_protected ) { /* remove the protection */ - DEK *dek = NULL; - u32 keyid[4]; /* 4! because we need two of them */ - 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 G10ERR_GENERAL; - } - if( sk->protect.algo == CIPHER_ALGO_NONE ) - BUG(); - 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)":"" ); - if(sk->protect.algo==CIPHER_ALGO_IDEA) - idea_cipher_warn(0); - return G10ERR_CIPHER_ALGO; - } - keyid_from_sk( sk, keyid ); - keyid[2] = keyid[3] = 0; - if( !sk->is_primary ) { - keyid[2] = sk->main_keyid[0]; - keyid[3] = sk->main_keyid[1]; - } - dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo, - &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 ); - cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen ); - csum = 0; - if( sk->version >= 4 ) { - int ndata; - byte *p, *data; - u16 csumc = 0; - - i = pubkey_get_npkey(sk->pubkey_algo); - 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 = m_alloc_secure( ndata ); - cipher_decrypt( cipher_hd, data, p, ndata ); - mpi_free( sk->skey[i] ); sk->skey[i] = NULL ; - p = data; - 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); - } - } - 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++ ) { - byte *p; - int ndata; - unsigned int dummy; - - assert (mpi_is_opaque (sk->skey[i])); - p = mpi_get_opaque (sk->skey[i], &ndata); - assert (ndata >= 2); - assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2); - buffer = m_alloc_secure (ndata); - cipher_sync (cipher_hd); - buffer[0] = p[0]; - buffer[1] = p[1]; - cipher_decrypt (cipher_hd, buffer+2, p+2, ndata-2); - csum += checksum (buffer, ndata); - mpi_free (sk->skey[i]); - dummy = ndata; - sk->skey[i] = mpi_read_from_buffer (buffer, &dummy, 1); - assert (sk->skey[i]); - m_free (buffer); -/* csum += checksum_mpi (sk->skey[i]); */ - } - } - 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 G10ERR_BAD_PASS; - } - /* 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 G10ERR_BAD_PASS; - } - free_secret_key( save_sk ); - sk->is_protected = 0; - } - else { /* not protected, assume it is okay if the checksum is okay */ - 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( csum != sk->csum ) - return G10ERR_CHECKSUM; - } - - return 0; -} - - - -/**************** - * Check the secret key - * Ask up to 3 (or n) times for a correct passphrase - */ -int -check_secret_key( PKT_secret_key *sk, int n ) -{ - int rc = G10ERR_BAD_PASS; - int i; - - if( n < 1 ) - 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]; - - keyid_from_sk( sk, kid ); - sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]); - write_status_text( STATUS_BAD_PASSPHRASE, buf ); - } - if( have_static_passphrase() ) - break; - } - - if( !rc ) - write_status( STATUS_GOOD_PASSPHRASE ); - - return rc; -} - -/**************** - * check whether the secret key is protected. - * Returns: 0 not protected, -1 on error or the protection algorithm - */ -int -is_secret_key_protected( PKT_secret_key *sk ) -{ - return sk->is_protected? sk->protect.algo : 0; -} - - - -/**************** - * Protect the secret key with the passphrase from DEK - */ -int -protect_secret_key( PKT_secret_key *sk, DEK *dek ) -{ - int i,j, rc = 0; - byte *buffer; - unsigned nbytes; - u16 csum; - - if( !dek ) - return 0; - - if( !sk->is_protected ) { /* okay, apply the protection */ - CIPHER_HANDLE cipher_hd=NULL; - - if( check_cipher_algo( sk->protect.algo ) ) - rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ - else { - print_cipher_algo_note( sk->protect.algo ); - 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")); - 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[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( !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 < PUBKEY_MAX_NSKEY; j++ ) - bufarr[j] = NULL; - ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */ - - data = m_alloc_secure( ndata ); - p = data; - 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]; - m_free(bufarr[j]); - } - - 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_free( sk->skey[i] ); - sk->skey[i] = NULL; - } - i = pubkey_get_npkey(sk->pubkey_algo); - sk->skey[i] = mpi_set_opaque(NULL, data, ndata ); - } - else { - csum = 0; - for(i=pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { - byte *data; - unsigned int nbits; - - csum += checksum_mpi (sk->skey[i]); - buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL ); - cipher_sync (cipher_hd); - assert ( !mpi_is_opaque (sk->skey[i]) ); - data = m_alloc (nbytes+2); - nbits = mpi_get_nbits (sk->skey[i]); - assert (nbytes == (nbits + 7)/8); - data[0] = nbits >> 8; - data[1] = nbits; - cipher_encrypt (cipher_hd, data+2, buffer, nbytes); - m_free( buffer ); - - mpi_free (sk->skey[i]); - sk->skey[i] = mpi_set_opaque (NULL, data, nbytes+2); - } - sk->csum = csum; - } - sk->is_protected = 1; - cipher_close( cipher_hd ); - } - } - return rc; -} - diff --git a/g10/sig-check.c b/g10/sig-check.c deleted file mode 100644 index c068e4409..000000000 --- a/g10/sig-check.c +++ /dev/null @@ -1,619 +0,0 @@ -/* sig-check.c - Check a signature - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.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" -#include "options.h" - -struct cmp_help_context_s { - PKT_signature *sig; - MD_HANDLE md; -}; - -static int do_check( PKT_public_key *pk, PKT_signature *sig, - MD_HANDLE digest, int *r_expired ); - -/**************** - * Check the signature which is contained in SIG. - * 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, MD_HANDLE digest ) -{ - u32 dummy; - int dum2; - return signature_check2( sig, digest, &dummy, &dum2 ); -} - -int -signature_check2( PKT_signature *sig, MD_HANDLE digest, - u32 *r_expiredate, int *r_expired ) -{ - PKT_public_key *pk = m_alloc_clear( sizeof *pk ); - int rc=0; - - *r_expiredate = 0; - - /* Sanity check that the md has a context for the hash that the - sig is expecting. This can happen if a onepass sig header does - not match the actual sig, and also if the clearsign "Hash:" - header is missing or does not match the actual sig. */ - - if(!md_algo_present(digest,sig->digest_algo)) { - log_info(_("WARNING: signature digest conflict in message\n")); - rc=G10ERR_BAD_SIGN; - } - else if( get_pubkey( pk, sig->keyid ) ) - rc = G10ERR_NO_PUBKEY; - else if(!pk->is_valid && !pk->is_primary) - rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an - invalid subkey */ - else { - *r_expiredate = pk->expiredate; - rc = do_check( pk, sig, digest, r_expired ); - } - - free_public_key( pk ); - - if( !rc && sig->sig_class < 2 && is_status_enabled() ) { - /* This signature id works best with DLP algorithms because - * they use a random parameter for every signature. Instead of - * 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 batch processing applications might - * like this feature here */ - MD_HANDLE md; - u32 a = sig->timestamp; - int i, nsig = pubkey_get_nsig( sig->pubkey_algo ); - byte *p, *buffer; - - 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++ ) { - 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); - } - 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 ); - m_free(buffer); - m_free(p); - md_close(md); - } - - return rc; -} - - -/**************** - * This function gets called by pubkey_verify() if the algorithm needs it. - */ -static int -cmp_help( void *opaque, MPI result ) -{ - #if 0 /* we do not use this anymore */ - int rc=0, i, j, c, old_enc; - byte *dp; - const byte *asn; - size_t mdlen, asnlen; - struct cmp_help_context_s *ctx = opaque; - PKT_signature *sig = ctx->sig; - MD_HANDLE digest = ctx->md; - - old_enc = 0; - for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { - if( !j ) { - if( !i && c != 1 ) - break; - else if( i && c == 0xff ) - ; /* skip the padding */ - else if( i && !c ) - j++; - else - break; - } - else if( ++j == 18 && c != 1 ) - break; - else if( j == 19 && c == 0 ) { - old_enc++; - break; - } - } - if( old_enc ) { - log_error("old encoding scheme is not supported\n"); - return G10ERR_GENERAL; - } - - if( (rc=check_digest_algo(sig->digest_algo)) ) - return rc; /* unsupported algo */ - asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen ); - - for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0; - i++, j-- ) - if( asn[j] != c ) - break; - if( j != -1 || mpi_getbyte(result, i) ) - 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 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 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 G10ERR_BAD_SIGN; - } - return 0; - #else - return -1; - #endif -} - -static int -do_check_messages( PKT_public_key *pk, PKT_signature *sig, int *r_expired ) -{ - u32 cur_time; - - *r_expired = 0; - if( pk->version == 4 && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) { - log_info(_("key %08lX: this is a PGP generated " - "ElGamal key which is NOT secure for signatures!\n"), - (ulong)keyid_from_pk(pk,NULL)); - return G10ERR_PUBKEY_ALGO; - } - - if( pk->timestamp > sig->timestamp ) { - ulong d = pk->timestamp - sig->timestamp; - log_info( d==1 - ? _("public key %08lX is %lu second newer than the signature\n") - : _("public key %08lX is %lu seconds newer than the signature\n"), - (ulong)keyid_from_pk(pk,NULL),d ); - if( !opt.ignore_time_conflict ) - return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */ - } - - cur_time = make_timestamp(); - if( pk->timestamp > cur_time ) { - ulong d = pk->timestamp - cur_time; - log_info( d==1 ? _("key %08lX has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key %08lX has been created %lu seconds " - "in future (time warp or clock problem)\n"), - (ulong)keyid_from_pk(pk,NULL),d ); - if( !opt.ignore_time_conflict ) - return G10ERR_TIME_CONFLICT; - } - - if( pk->expiredate && pk->expiredate < cur_time ) { - 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; - } - - return 0; -} - - -static int -do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest, - int *r_expired ) -{ - MPI result = NULL; - int rc=0; - struct cmp_help_context_s ctx; - - if( (rc=do_check_messages(pk,sig,r_expired)) ) - return rc; - if( (rc=check_digest_algo(sig->digest_algo)) ) - return rc; - if( (rc=check_pubkey_algo(sig->pubkey_algo)) ) - return rc; - - /* make sure the digest algo is enabled (in case of a detached signature)*/ - md_enable( digest, sig->digest_algo ); - - /* complete the digest */ - if( sig->version >= 4 ) - md_putc( digest, sig->version ); - md_putc( digest, sig->sig_class ); - if( sig->version < 4 ) { - u32 a = sig->timestamp; - 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; - 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 { - /* Two octets for the (empty) length of the hashed - section. */ - md_putc (digest, 0); - md_putc (digest, 0); - n = 6; - } - /* add some magic */ - buf[0] = sig->version; - buf[1] = 0xff; - buf[2] = n >> 24; - buf[3] = n >> 16; - buf[4] = n >> 8; - buf[5] = n; - md_write( digest, buf, 6 ); - } - md_final( digest ); - - result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo, - mpi_get_nbits(pk->pkey[0]), 0 ); - if (!result) - return G10ERR_GENERAL; - ctx.sig = sig; - ctx.md = digest; - rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey, - cmp_help, &ctx ); - mpi_free( result ); - if( (opt.emulate_bugs & EMUBUG_MDENCODE) - && 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, - 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 from key %08lX due to an unknown critical bit\n"),(ulong)keyid_from_pk(pk,NULL)); - rc = G10ERR_BAD_SIGN; - } - - return rc; -} - - -static void -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->attrib_data ) { - if( sig->version >=4 ) { - byte 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 ); - } - md_write( md, uid->attrib_data, uid->attrib_len ); - } - else { - if( sig->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; - md_write( md, buf, 5 ); - } - 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; - } -} - - -/* 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 guarantees that a designated revocation sig will never be - considered valid unless it is actually valid, as well as being - issued by a revocation key in a valid direct signature. 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 */ - -/* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not - revoked */ -int -check_revocation_keys(PKT_public_key *pk,PKT_signature *sig) -{ - static int busy=0; - int i,rc=G10ERR_GENERAL; - - 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 rc; - } - - 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); - rc=signature_check(sig,md); - cache_sig_result(sig,rc); - break; - } - } - - busy=0; - - return rc; -} - -/**************** - * check the signature pointed to by NODE. This is a key signature. - * If the function detects a self-signature, it uses the PK from - * ROOT and does not read any public key. - */ -int -check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) -{ - u32 dummy; - int dum2; - return check_key_signature2(root, node, is_selfsig, &dummy, &dum2 ); -} - -int -check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, - u32 *r_expiredate, int *r_expired ) -{ - MD_HANDLE md; - PKT_public_key *pk; - PKT_signature *sig; - int algo; - int rc; - - if( is_selfsig ) - *is_selfsig = 0; - *r_expiredate = 0; - *r_expired = 0; - assert( node->pkt->pkttype == PKT_SIGNATURE ); - assert( root->pkt->pkttype == PKT_PUBLIC_KEY ); - - pk = root->pkt->pkt.public_key; - sig = node->pkt->pkt.signature; - algo = sig->digest_algo; - - /* 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; - } - if((rc=do_check_messages(pk,sig,r_expired))) - return rc; - return sig->flags.valid? 0 : G10ERR_BAD_SIGN; - } - } - - if( (rc=check_digest_algo(algo)) ) - return rc; - - if( sig->sig_class == 0x20 ) { /* key revocation */ - u32 keyid[2]; - keyid_from_pk( pk, keyid ); - - /* is it a designated revoker? */ - if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1]) - rc=check_revocation_keys(pk,sig); - else - { - 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 if( sig->sig_class == 0x28 ) { /* subkey revocation */ - KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY ); - - if( snode ) { - 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 ); - cache_sig_result ( sig, rc ); - md_close(md); - } - else { - if (!opt.quiet) - log_info (_("key %08lX: no subkey for subkey " - "revocation signature\n"), - (ulong)keyid_from_pk (pk, NULL)); - rc = G10ERR_SIG_CLASS; - } - } - else if( sig->sig_class == 0x18 ) { /* key binding */ - KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY ); - - if( snode ) { - if( is_selfsig ) { /* does this make sense????? */ - u32 keyid[2]; /* it should always be a selfsig */ - - keyid_from_pk( pk, keyid ); - if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) - *is_selfsig = 1; - } - 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 ); - cache_sig_result ( sig, rc ); - md_close(md); - } - else { - if (!opt.quiet) - log_info ("key %08lX: no subkey for subkey " - "binding signature\n",(ulong)keyid_from_pk(pk,NULL)); - rc = G10ERR_SIG_CLASS; - } - } - 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 ); - 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] ) { - if( is_selfsig ) - *is_selfsig = 1; - rc = do_check( pk, sig, md, r_expired ); - } - else { - rc = signature_check2( sig, md, r_expiredate, r_expired ); - } - cache_sig_result ( sig, rc ); - md_close(md); - } - else { - 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; - } - } - - return rc; -} diff --git a/g10/sign.c b/g10/sign.c deleted file mode 100644 index fe242b8da..000000000 --- a/g10/sign.c +++ /dev/null @@ -1,1300 +0,0 @@ -/* sign.c - sign data - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <unistd.h> /* need sleep() */ - -#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" -#include "ttyio.h" -#include "trustdb.h" -#include "status.h" -#include "i18n.h" - - -#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; - -/**************** - * 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 void -mk_notation_and_policy( PKT_signature *sig, - PKT_public_key *pk, PKT_secret_key *sk ) -{ - const char *string; - char *s=NULL; - byte *buf; - unsigned n1, n2; - STRLIST nd=NULL,pu=NULL; - struct expando_args args; - - memset(&args,0,sizeof(args)); - args.pk=pk; - args.sk=sk; - - /* 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); - } - - if(opt.show_notation) - show_notation(sig,0); - - /* 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); -} - - -/* - * 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 ); - } - - if(uid->attrib_data) - md_write (md, uid->attrib_data, uid->attrib_len ); - else - md_write (md, uid->name, uid->len ); -} - - -/* - * Helper to hash some parts from the signature - */ -static void -hash_sigversion_to_magic (MD_HANDLE md, const PKT_signature *sig) -{ - 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 ); - } - 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, - MD_HANDLE md, int digest_algo ) -{ - MPI frame; - byte *dp; - int rc; - - if( sk->timestamp > sig->timestamp ) { - ulong d = sk->timestamp - sig->timestamp; - log_info( d==1 ? _("key has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key has been created %lu seconds " - "in future (time warp or clock problem)\n"), d ); - if( !opt.ignore_time_conflict ) - return G10ERR_TIME_CONFLICT; - } - - - print_pubkey_algo_note(sk->pubkey_algo); - - if( !digest_algo ) - digest_algo = md_get_algo(md); - - print_digest_algo_note( 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, 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"), g10_errstr(rc) ); - else { - if( opt.verbose ) { - char *ustr = get_user_id_string_printable (sig->keyid); - log_info(_("%s signature from: \"%s\"\n"), - pubkey_algo_to_string(sk->pubkey_algo), ustr ); - m_free(ustr); - } - } - return rc; -} - - - -int -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 ); - return rc; -} - -static int -hash_for(int pubkey_algo, int packet_version ) -{ - if( opt.def_digest_algo ) - return opt.def_digest_algo; - 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; -} - -static int -only_old_style( SK_LIST sk_list ) -{ - SK_LIST sk_rover = NULL; - int old_style = 0; - - /* 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 == PUBKEY_ALGO_RSA && sk->version < 4 ) - old_style = 1; - else - return 0; - } - return old_style; -} - - -static void -print_status_sig_created ( PKT_secret_key *sk, PKT_signature *sig, int what ) -{ - byte array[MAX_FINGERPRINT_LEN], *p; - char buf[100+MAX_FINGERPRINT_LEN*2]; - size_t i, n; - - sprintf(buf, "%c %d %d %02x %lu ", - what, sig->pubkey_algo, sig->digest_algo, sig->sig_class, - (ulong)sig->timestamp ); - - fingerprint_from_sk( sk, array, &n ); - p = buf + strlen(buf); - for(i=0; i < n ; i++ ) - sprintf(p+2*i, "%02X", array[i] ); - - 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_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass ) -{ - int skcount; - SK_LIST sk_rover; - - for (skcount=0, sk_rover=sk_list; sk_rover; sk_rover = sk_rover->next) - skcount++; - - for (; skcount; skcount--) { - PKT_secret_key *sk; - PKT_onepass_sig *ops; - PACKET pkt; - int i, rc; - - for (i=0, sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { - if (++i == skcount) - break; - } - - 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; - } - } - - return 0; -} - -/* - * 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; - } - } - - /* 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. - * If DETACHED has the value true, - * 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 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 - * uncompressed, non-armored and in binary mode. - */ -int -sign_file( STRLIST filenames, int detached, STRLIST locusr, - int encryptflag, STRLIST remusr, const char *outfile ) -{ - const char *fname; - armor_filter_context_t afx; - compress_filter_context_t zfx; - md_filter_context_t mfx; - text_filter_context_t tfx; - encrypt_filter_context_t efx; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - int rc = 0; - PK_LIST pk_list = NULL; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - int multifile = 0; - 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( &efx, 0, sizeof efx); - init_packet( &pkt ); - - if( filenames ) { - fname = filenames->d; - multifile = !!filenames->next; - } - else - fname = NULL; - - if( fname && filenames->next && (!detached || encryptflag) ) - log_bug("multiple files can only be detached signed"); - - 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(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 %s\n"),"PGP 2.x"); - 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 */ - inp = NULL; /* we do it later */ - else if( !(inp = iobuf_open(fname)) ) { - log_error("can't open %s: %s\n", fname? fname: "[stdin]", - strerror(errno) ); - 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 = G10ERR_CREATE_FILE; - goto leave; - } - else if( opt.verbose ) - log_info(_("writing to `%s'\n"), outfile ); - } - else if( (rc = open_outfile( fname, opt.armor? 1: detached? 2:0, &out ))) - goto leave; - - /* prepare to calculate the MD over the input */ - if( opt.textmode && !outfile ) - iobuf_push_filter( inp, text_filter, &tfx ); - 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; - md_enable(mfx.md, hash_for(sk->pubkey_algo, sk->version )); - } - - if( !multifile ) - iobuf_push_filter( inp, md_filter, &mfx ); - - if( detached && !encryptflag && !opt.rfc1991 ) - afx.what = 2; - - if( opt.armor && !outfile ) - iobuf_push_filter( out, armor_filter, &afx ); - - if( encryptflag ) { - efx.pk_list = pk_list; - /* fixme: set efx.cfx.datalen if known */ - iobuf_push_filter( out, encrypt_filter, &efx ); - } - - 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 ); - } - } - - /* 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 ) { - if( multifile ) { - STRLIST sl; - - if( opt.verbose ) - log_info(_("signing:") ); - /* must walk reverse trough this list */ - for( sl = strlist_last(filenames); sl; - sl = strlist_prev( filenames, sl ) ) { - if( !(inp = iobuf_open(sl->d)) ) { - log_error(_("can't open %s: %s\n"), - sl->d, strerror(errno) ); - rc = G10ERR_OPEN_FILE; - goto leave; - } - if( opt.verbose ) - fprintf(stderr, " `%s'", sl->d ); - iobuf_push_filter( inp, md_filter, &mfx ); - while( iobuf_get(inp) != -1 ) - ; - iobuf_close(inp); inp = NULL; - } - if( opt.verbose ) - putc( '\n', stderr ); - } - else { - /* read, so that the filter can calculate the digest */ - while( iobuf_get(inp) != -1 ) - ; - } - } - else { - rc = write_plaintext_packet (out, inp, fname, - opt.textmode && !outfile ? 't':'b'); - } - - /* catch errors from above */ - if (rc) - goto leave; - - /* write the signatures */ - rc = write_signature_packets (sk_list, out, mfx.md, - opt.textmode && !outfile? 0x01 : 0x00, - timestamp, duration, detached ? 'D':'S'); - if( rc ) - goto leave; - - - leave: - if( rc ) - iobuf_cancel(out); - else { - iobuf_close(out); - if (encryptflag) - write_status( STATUS_END_ENCRYPTION ); - } - iobuf_close(inp); - md_close( mfx.md ); - release_sk_list( sk_list ); - release_pk_list( pk_list ); - recipient_digest_algo=0; - return rc; -} - - - -/**************** - * make a clear signature. note that opt.armor is not needed - */ -int -clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) -{ - armor_filter_context_t afx; - MD_HANDLE textmd = NULL; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - int rc = 0; - SK_LIST sk_list = NULL; - 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(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 && !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 %s\n"),"PGP 2.x"); - opt.pgp2=0; - } - - /* prepare iobufs */ - if( !(inp = iobuf_open(fname)) ) { - log_error("can't open %s: %s\n", fname? fname: "[stdin]", - strerror(errno) ); - 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 = G10ERR_CREATE_FILE; - goto leave; - } - else if( opt.verbose ) - log_info(_("writing to `%s'\n"), outfile ); - } - else if( (rc = open_outfile( fname, 1, &out )) ) - goto leave; - - iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF ); - - 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) == DIGEST_ALGO_MD5 ) - only_md5 = 1; - else { - only_md5 = 0; - break; - } - } - - if( !(old_style && only_md5) ) { - const char *s; - int any = 0; - byte hashs_seen[256]; - - memset( hashs_seen, 0, sizeof hashs_seen ); - iobuf_writestr(out, "Hash: " ); - for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { - PKT_secret_key *sk = sk_rover->sk; - int i = hash_for(sk->pubkey_algo, sk->version); - - if( !hashs_seen[ i & 0xff ] ) { - s = digest_algo_to_string( i ); - if( s ) { - hashs_seen[ i & 0xff ] = 1; - if( any ) - iobuf_put(out, ',' ); - iobuf_writestr(out, s ); - any = 1; - } - } - } - assert(any); - 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 = 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(textmd, hash_for(sk->pubkey_algo, sk->version)); - } - if ( DBG_HASHING ) - 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 */ - - /* now write the armor */ - afx.what = 2; - iobuf_push_filter( out, armor_filter, &afx ); - - /* write the signatures */ - rc = write_signature_packets (sk_list, out, textmd, 0x01, - timestamp, duration, 'C'); - if( rc ) - goto leave; - - leave: - if( rc ) - iobuf_cancel(out); - else - iobuf_close(out); - iobuf_close(inp); - 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. - * 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; - MD_HANDLE md; - - assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F - || sigclass == 0x20 || sigclass == 0x18 - || sigclass == 0x30 || sigclass == 0x28 ); - - 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. Note that this implies that a signature on an attribute - uid is usually going to be v4 as well, since they are not - generally found on v3 keys. */ - 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 != 0x1F && sigclass != 0x20 ) { - hash_uid (md, sigversion, uid); - } - /* and make the signature packet */ - 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; - 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 ); - - if( sig->version >= 4 && mksubpkt ) - rc = (*mksubpkt)( sig, opaque ); - - if( !rc ) { - mk_notation_and_policy( sig, pk, sk ); - 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; -} - - - -/**************** - * 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 deleted file mode 100644 index 0517ba648..000000000 --- a/g10/signal.c +++ /dev/null @@ -1,217 +0,0 @@ -/* signal.c - signal handling - * Copyright (C) 1998, 1999, 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 <signal.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "options.h" -#include "errors.h" -#include "memory.h" -#include "util.h" -#include "main.h" -#include "ttyio.h" - - -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 ) -{ - #if defined(SYS_SIGLIST_DECLARED) && defined(NSIG) - return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?"; - #else - return "some signal"; - #endif -} - - -static RETSIGTYPE -got_fatal_signal( int sig ) -{ - const char *s; - - if( caught_fatal_sig ) - raise( sig ); - caught_fatal_sig = 1; - - 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", 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 ); -} - - -static RETSIGTYPE -got_usr_signal( int sig ) -{ - caught_sigusr1 = 1; -} - - -void -init_signals() -{ - #ifndef HAVE_DOSISH_SYSTEM - 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 -} - - -void -pause_on_sigusr( int which ) -{ - #ifndef HAVE_DOSISH_SYSTEM - #ifdef HAVE_SIGPROCMASK - sigset_t mask, oldmask; - - assert( which == 1 ); - sigemptyset( &mask ); - sigaddset( &mask, SIGUSR1 ); - - sigprocmask( SIG_BLOCK, &mask, &oldmask ); - while( !caught_sigusr1 ) - 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 -} - - -static void -do_block( int block ) -{ - #ifndef HAVE_DOSISH_SYSTEM - static int is_blocked; - #ifdef HAVE_SIGPROCMASK - static sigset_t oldmask; - - if( block ) { - sigset_t newmask; - - if( is_blocked ) - log_bug("signals are already blocked\n"); - sigfillset( &newmask ); - sigprocmask( SIG_BLOCK, &newmask, &oldmask ); - is_blocked = 1; - } - else { - if( !is_blocked ) - log_bug("signals are not blocked\n"); - sigprocmask( SIG_SETMASK, &oldmask, NULL ); - is_blocked = 0; - } - #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*/ -} - - -void -block_all_signals() -{ - do_block(1); -} - -void -unblock_all_signals() -{ - do_block(0); -} diff --git a/g10/status.c b/g10/status.c deleted file mode 100644 index 799b42edc..000000000 --- a/g10/status.c +++ /dev/null @@ -1,693 +0,0 @@ -/* status.c - * 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 <stdio.h> -#include <stdlib.h> -#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 - #include <sys/shm.h> - #endif - #if defined(HAVE_MLOCK) - #include <sys/mman.h> - #endif -#endif -#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; - -#ifdef USE_SHM_COPROCESSING - static int shm_id = -1; - static volatile char *shm_area; - static size_t shm_size; - static int shm_is_locked; -#endif /*USE_SHM_COPROCESSING*/ - - -static void -progress_cb ( void *ctx, int c ) -{ - char buf[50]; - - if ( c == '\n' ) - sprintf ( buf, "%.20s X 100 100", (char*)ctx ); - else - sprintf ( buf, "%.20s %c 0 0", (char*)ctx, 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_OK : s = "IMPORT_OK"; 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 fd ) -{ - 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 !!statusfp; -} - -void -write_status ( int no ) -{ - write_status_text( no, NULL ); -} - -void -write_status_text ( int no, const char *text) -{ - if( !statusfp ) - return; /* not enabled */ - - 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 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; - } - - 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 - -#ifndef IPC_RMID_DEFERRED_RELEASE -static void -remove_shmid( void ) -{ - if( shm_id != -1 ) { - shmctl ( shm_id, IPC_RMID, 0); - shm_id = -1; - } -} -#endif - -void -init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) -{ - char buf[100]; - struct shmid_ds shmds; - - #ifndef IPC_RMID_DEFERRED_RELEASE - atexit( remove_shmid ); - #endif - requested_shm_size = (requested_shm_size + 4095) & ~4095; - if ( requested_shm_size > 2 * 4096 ) - log_fatal("too much shared memory requested; only 8k are allowed\n"); - shm_size = 4096 /* one page for us */ + requested_shm_size; - - shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 ); - if ( shm_id == -1 ) - log_fatal("can't get %uk of shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - - #if !defined(IPC_HAVE_SHM_LOCK) \ - && defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - /* part of the old code which uses mlock */ - shm_area = shmat( shm_id, 0, 0 ); - if ( shm_area == (char*)-1 ) - log_fatal("can't attach %uk shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - log_debug("mapped %uk shared memory at %p, id=%d\n", - (unsigned)shm_size/1024, shm_area, shm_id ); - if( lock_mem ) { - #ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); - #endif - /* (need the cast for Solaris with Sun's workshop compilers) */ - if ( mlock ( (char*)shm_area, shm_size) ) - log_info("locking shared memory %d failed: %s\n", - shm_id, strerror(errno)); - else - shm_is_locked = 1; - #ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); - #endif - } - - #ifdef IPC_RMID_DEFERRED_RELEASE - if( shmctl( shm_id, IPC_RMID, 0) ) - log_fatal("shmctl IPC_RMDID of %d failed: %s\n", - shm_id, strerror(errno)); - #endif - - if( shmctl( shm_id, IPC_STAT, &shmds ) ) - log_fatal("shmctl IPC_STAT of %d failed: %s\n", - shm_id, strerror(errno)); - if( shmds.shm_perm.uid != getuid() ) { - shmds.shm_perm.uid = getuid(); - if( shmctl( shm_id, IPC_SET, &shmds ) ) - log_fatal("shmctl IPC_SET of %d failed: %s\n", - shm_id, strerror(errno)); - } - - #else /* this is the new code which handles the changes in the SHM semantics - * introduced with Linux 2.4. The changes is that we now change the - * permissions and then attach to the memory. - */ - - if( lock_mem ) { - #ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); - #endif - #ifdef IPC_HAVE_SHM_LOCK - if ( shmctl (shm_id, SHM_LOCK, 0) ) - log_info("locking shared memory %d failed: %s\n", - shm_id, strerror(errno)); - else - shm_is_locked = 1; - #else - log_info("Locking shared memory %d failed: No way to do it\n", shm_id ); - #endif - #ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); - #endif - } - - if( shmctl( shm_id, IPC_STAT, &shmds ) ) - log_fatal("shmctl IPC_STAT of %d failed: %s\n", - shm_id, strerror(errno)); - if( shmds.shm_perm.uid != getuid() ) { - shmds.shm_perm.uid = getuid(); - if( shmctl( shm_id, IPC_SET, &shmds ) ) - log_fatal("shmctl IPC_SET of %d failed: %s\n", - shm_id, strerror(errno)); - } - - shm_area = shmat( shm_id, 0, 0 ); - if ( shm_area == (char*)-1 ) - log_fatal("can't attach %uk shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - log_debug("mapped %uk shared memory at %p, id=%d\n", - (unsigned)shm_size/1024, shm_area, shm_id ); - - #ifdef IPC_RMID_DEFERRED_RELEASE - if( shmctl( shm_id, IPC_RMID, 0) ) - log_fatal("shmctl IPC_RMDID of %d failed: %s\n", - shm_id, strerror(errno)); - #endif - - #endif - /* write info; Protocol version, id, size, locked size */ - sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(), - shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 ); - write_status_text( STATUS_SHM_INFO, buf ); -} - -/**************** - * Request a string from client - * If bool, returns static string on true (do not free) or NULL for false - */ -static char * -do_shm_get( const char *keyword, int hidden, int bool ) -{ - size_t n; - byte *p; - char *string; - - if( !shm_area ) - BUG(); - - shm_area[0] = 0; /* msb of length of control block */ - shm_area[1] = 32; /* and lsb */ - shm_area[2] = 1; /* indicate that we are waiting on a reply */ - shm_area[3] = 0; /* clear data available flag */ - - write_status_text( bool? STATUS_SHM_GET_BOOL : - hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword ); - - do { - pause_on_sigusr(1); - if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 ) - log_fatal("client modified shm control block - abort\n"); - } while( !shm_area[3] ); - shm_area[2] = 0; /* reset request flag */ - p = (byte*)shm_area+32; - n = p[0] << 8 | p[1]; - p += 2; - if( n+32+2+1 > 4095 ) - log_fatal("client returns too large data (%u bytes)\n", (unsigned)n ); - - if( bool ) - return p[0]? "" : NULL; - - 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 */ - memset( p, 0, n ); - - return string; -} - -#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 - * If bool, returns static string on true (do not free) or NULL for false - */ -static char * -do_get_from_fd( const char *keyword, int hidden, int bool ) -{ - int i, len; - char *string; - - write_status_text( bool? STATUS_GET_BOOL : - hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword ); - - for( string = NULL, i = len = 200; ; i++ ) { - if( i >= len-1 ) { - char *save = string; - len += 100; - 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( 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; - - write_status( STATUS_GOT_IT ); - - if( bool ) /* Fixme: is this correct??? */ - return string[0] == 'Y' ? "" : NULL; - - return string; -} - - - -int -cpr_enabled() -{ - if( opt.command_fd != -1 ) - return 1; - #ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return 1; - #endif - return 0; -} - -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; - - 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 ); - if( *p=='?' && !p[1] && !(keyword && !*keyword)) { - m_free(p); - display_online_help( keyword ); - } - else - return p; - } -} - - -char * -cpr_get_utf8( const char *keyword, const char *prompt ) -{ - char *p; - p = cpr_get( keyword, prompt ); - if( p ) { - char *utf8 = native_to_utf8( p ); - m_free( p ); - p = utf8; - } - return p; -} - -char * -cpr_get_hidden( const char *keyword, const char *prompt ) -{ - char *p; - - if( opt.command_fd != -1 ) - return do_get_from_fd ( keyword, 1, 0 ); - #ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return do_shm_get( keyword, 1, 0 ); - #endif - for(;;) { - p = tty_get_hidden( prompt ); - if( *p == '?' && !p[1] ) { - m_free(p); - display_online_help( keyword ); - } - else - return p; - } -} - -void -cpr_kill_prompt(void) -{ - if( opt.command_fd != -1 ) - return; - #ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return; - #endif - tty_kill_prompt(); - return; -} - -int -cpr_get_answer_is_yes( const char *keyword, const char *prompt ) -{ - int yes; - char *p; - - if( opt.command_fd != -1 ) - return !!do_get_from_fd ( keyword, 0, 1 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return !!do_shm_get( keyword, 0, 1 ); -#endif - for(;;) { - p = tty_get( prompt ); - trim_spaces(p); /* it is okay to do this here */ - if( *p == '?' && !p[1] ) { - m_free(p); - display_online_help( keyword ); - } - else { - tty_kill_prompt(); - yes = answer_is_yes(p); - m_free(p); - return yes; - } - } -} - -int -cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ) -{ - int yes; - char *p; - - if( opt.command_fd != -1 ) - return !!do_get_from_fd ( keyword, 0, 1 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return !!do_shm_get( keyword, 0, 1 ); -#endif - for(;;) { - p = tty_get( prompt ); - trim_spaces(p); /* it is okay to do this here */ - if( *p == '?' && !p[1] ) { - m_free(p); - display_online_help( keyword ); - } - else { - tty_kill_prompt(); - yes = answer_is_yes_no_quit(p); - m_free(p); - return yes; - } - } -} - diff --git a/g10/status.h b/g10/status.h deleted file mode 100644 index dd913b4bd..000000000 --- a/g10/status.h +++ /dev/null @@ -1,126 +0,0 @@ -/* status.h - * Copyright (C) 1998, 1999, 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 - */ -#ifndef G10_STATUS_H -#define G10_STATUS_H - - -#define STATUS_ENTER 1 -#define STATUS_LEAVE 2 -#define STATUS_ABORT 3 - -#define STATUS_GOODSIG 4 -#define STATUS_BADSIG 5 -#define STATUS_ERRSIG 6 - - -#define STATUS_BADARMOR 7 - -#define STATUS_RSA_OR_IDEA 8 -#define STATUS_KEYEXPIRED 9 -#define STATUS_KEYREVOKED 10 - -#define STATUS_TRUST_UNDEFINED 11 -#define STATUS_TRUST_NEVER 12 -#define STATUS_TRUST_MARGINAL 13 -#define STATUS_TRUST_FULLY 14 -#define STATUS_TRUST_ULTIMATE 15 - -#define STATUS_SHM_INFO 16 -#define STATUS_SHM_GET 17 -#define STATUS_SHM_GET_BOOL 18 -#define STATUS_SHM_GET_HIDDEN 19 - -#define STATUS_NEED_PASSPHRASE 20 -#define STATUS_VALIDSIG 21 -#define STATUS_SIG_ID 22 -#define STATUS_ENC_TO 23 -#define STATUS_NODATA 24 -#define STATUS_BAD_PASSPHRASE 25 -#define STATUS_NO_PUBKEY 26 -#define STATUS_NO_SECKEY 27 -#define STATUS_NEED_PASSPHRASE_SYM 28 -#define STATUS_DECRYPTION_FAILED 29 -#define STATUS_DECRYPTION_OKAY 30 -#define STATUS_MISSING_PASSPHRASE 31 -#define STATUS_GOOD_PASSPHRASE 32 -#define STATUS_GOODMDC 33 -#define STATUS_BADMDC 34 -#define STATUS_ERRMDC 35 -#define STATUS_IMPORTED 36 -#define STATUS_IMPORT_RES 37 -#define STATUS_FILE_START 38 -#define STATUS_FILE_DONE 39 -#define STATUS_FILE_ERROR 40 - -#define STATUS_BEGIN_DECRYPTION 41 -#define STATUS_END_DECRYPTION 42 -#define STATUS_BEGIN_ENCRYPTION 43 -#define STATUS_END_ENCRYPTION 44 - -#define STATUS_DELETE_PROBLEM 45 -#define STATUS_GET_BOOL 46 -#define STATUS_GET_LINE 47 -#define STATUS_GET_HIDDEN 48 -#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 -#define STATUS_IMPORT_OK 68 - -/*-- 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 ); -#endif /*USE_SHM_COPROCESSING*/ - -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); -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 /*G10_STATUS_H*/ diff --git a/g10/tdbio.c b/g10/tdbio.c deleted file mode 100644 index 62ff26774..000000000 --- a/g10/tdbio.c +++ /dev/null @@ -1,1578 +0,0 @@ -/* tdbio.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.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 "memory.h" -#include "util.h" -#include "options.h" -#include "main.h" -#include "i18n.h" -#include "trustdb.h" -#include "tdbio.h" - -#if defined(HAVE_DOSISH_SYSTEM) && !defined(__CYGWIN32__) -#define ftruncate chsize -#endif - -#ifdef HAVE_DOSISH_SYSTEM -#define MY_O_BINARY O_BINARY -#else -#define MY_O_BINARY 0 -#endif - - -/**************** - * Yes, this is a very simple implementation. We should really - * use a page aligned buffer and read complete pages. - * To implement a simple trannsaction system, this is sufficient. - */ -typedef struct cache_ctrl_struct *CACHE_CTRL; -struct cache_ctrl_struct { - CACHE_CTRL next; - struct { - unsigned used:1; - unsigned dirty:1; - } flags; - ulong recno; - char data[TRUST_RECORD_LEN]; -}; - -#define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased while in a */ -#define MAX_CACHE_ENTRIES_HARD 10000 /* transaction to this one */ -static CACHE_CTRL cache_list; -static int cache_entries; -static int cache_is_dirty; - -/* a type used to pass infomation to cmp_krec_fpr */ -struct cmp_krec_fpr_struct { - int pubkey_algo; - const char *fpr; - int fprlen; -}; - -/* a type used to pass infomation to cmp_[s]dir */ -struct cmp_xdir_struct { - int pubkey_algo; - u32 keyid[2]; -}; - - -static char *db_name; -static DOTLOCK lockhandle; -static int is_locked; -static int db_fd = -1; -static int in_transaction; - -static void open_db(void); -static void migrate_from_v2 (void); - - - -/************************************* - ************* record cache ********** - *************************************/ - -/**************** - * Get the data from therecord cache and return a - * pointer into that cache. Caller should copy - * the return data. NULL is returned on a cache miss. - */ -static const char * -get_record_from_cache( ulong recno ) -{ - CACHE_CTRL r; - - for( r = cache_list; r; r = r->next ) { - if( r->flags.used && r->recno == recno ) - return r->data; - } - return NULL; -} - - -static int -write_cache_item( CACHE_CTRL r ) -{ - int n; - - 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 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 G10ERR_WRITE_FILE; - } - r->flags.dirty = 0; - return 0; -} - -/**************** - * Put data into the cache. This function may flush the - * some cache entries if there is not enough space available. - */ -int -put_record_into_cache( ulong recno, const char *data ) -{ - CACHE_CTRL r, unused; - int dirty_count = 0; - int clean_count = 0; - - /* see whether we already cached this one */ - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( !r->flags.used ) { - if( !unused ) - unused = r; - } - else if( r->recno == recno ) { - if( !r->flags.dirty ) { - /* Hmmm: should we use a a copy and compare? */ - if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) { - r->flags.dirty = 1; - cache_is_dirty = 1; - } - } - memcpy( r->data, data, TRUST_RECORD_LEN ); - return 0; - } - if( r->flags.used ) { - if( r->flags.dirty ) - dirty_count++; - else - clean_count++; - } - } - /* not in the cache: add a new entry */ - if( unused ) { /* reuse this entry */ - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; - } - /* see whether we reached the limit */ - if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */ - r = m_alloc( sizeof *r ); - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - r->next = cache_list; - cache_list = r; - cache_is_dirty = 1; - cache_entries++; - return 0; - } - /* cache is full: discard some clean entries */ - if( clean_count ) { - int n = clean_count / 3; /* discard a third of the clean entries */ - if( !n ) - n = 1; - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( r->flags.used && !r->flags.dirty ) { - if( !unused ) - unused = r; - r->flags.used = 0; - cache_entries--; - if( !--n ) - break; - } - } - assert( unused ); - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; - } - /* no clean entries: have to flush some dirty entries */ - if( in_transaction ) { - /* but we can't do this while in a transaction - * we increase the cache size instead */ - if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */ - if( opt.debug && !(cache_entries % 100) ) - log_debug("increasing tdbio cache size\n"); - r = m_alloc( sizeof *r ); - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - r->next = cache_list; - cache_list = r; - cache_is_dirty = 1; - cache_entries++; - return 0; - } - log_info(_("trustdb transaction too large\n")); - return G10ERR_RESOURCE_LIMIT; - } - if( dirty_count ) { - int n = dirty_count / 5; /* discard some dirty entries */ - if( !n ) - n = 1; - if( !is_locked ) { - if( make_dotlock( lockhandle, -1 ) ) - log_fatal("can't acquire lock - giving up\n"); - else - is_locked = 1; - } - for( unused = NULL, r = cache_list; r; r = r->next ) { - if( r->flags.used && r->flags.dirty ) { - int rc = write_cache_item( r ); - if( rc ) - return rc; - if( !unused ) - unused = r; - r->flags.used = 0; - cache_entries--; - if( !--n ) - break; - } - } - if( !opt.lock_once ) { - if( !release_dotlock( lockhandle ) ) - is_locked = 0; - } - assert( unused ); - r = unused; - r->flags.used = 1; - r->recno = recno; - memcpy( r->data, data, TRUST_RECORD_LEN ); - r->flags.dirty = 1; - cache_is_dirty = 1; - cache_entries++; - return 0; - } - BUG(); -} - - -int -tdbio_is_dirty() -{ - return cache_is_dirty; -} - - -/**************** - * Flush the cache. This cannot be used while in a transaction. - */ -int -tdbio_sync() -{ - CACHE_CTRL r; - int did_lock = 0; - - if( db_fd == -1 ) - open_db(); - if( in_transaction ) - log_bug("tdbio: syncing while in transaction\n"); - - if( !cache_is_dirty ) - return 0; - - if( !is_locked ) { - if( make_dotlock( lockhandle, -1 ) ) - log_fatal("can't acquire lock - giving up\n"); - else - is_locked = 1; - did_lock = 1; - } - for( r = cache_list; r; r = r->next ) { - if( r->flags.used && r->flags.dirty ) { - int rc = write_cache_item( r ); - if( rc ) - return rc; - } - } - cache_is_dirty = 0; - if( did_lock && !opt.lock_once ) { - if( !release_dotlock( lockhandle ) ) - is_locked = 0; - } - - return 0; -} - - - -/**************** - * Simple transactions system: - * Everything between begin_transaction and end/cancel_transaction - * is not immediatly written but at the time of end_transaction. - * - */ -int -tdbio_begin_transaction() -{ - int rc; - - if( in_transaction ) - log_bug("tdbio: nested transactions\n"); - /* flush everything out */ - rc = tdbio_sync(); - if( rc ) - return rc; - in_transaction = 1; - return 0; -} - -int -tdbio_end_transaction() -{ - int rc; - - if( !in_transaction ) - log_bug("tdbio: no active transaction\n"); - if( !is_locked ) { - if( make_dotlock( lockhandle, -1 ) ) - log_fatal("can't acquire lock - giving up\n"); - else - is_locked = 1; - } - block_all_signals(); - in_transaction = 0; - rc = tdbio_sync(); - unblock_all_signals(); - if( !opt.lock_once ) { - if( !release_dotlock( lockhandle ) ) - is_locked = 0; - } - return rc; -} - -int -tdbio_cancel_transaction() -{ - CACHE_CTRL r; - - if( !in_transaction ) - log_bug("tdbio: no active transaction\n"); - - /* remove all dirty marked entries, so that the original ones - * are read back the next time */ - if( cache_is_dirty ) { - for( r = cache_list; r; r = r->next ) { - if( r->flags.used && r->flags.dirty ) { - r->flags.used = 0; - cache_entries--; - } - } - cache_is_dirty = 0; - } - - in_transaction = 0; - return 0; -} - - - -/******************************************************** - **************** cached I/O functions ****************** - ********************************************************/ - -static void -cleanup(void) -{ - if( is_locked ) { - if( !release_dotlock(lockhandle) ) - is_locked = 0; - } -} - -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 ) -{ - char *fname; - static int initialized = 0; - - if( !initialized ) { - atexit( cleanup ); - initialized = 1; - } - fname = new_dbname? m_strdup( new_dbname ) - : make_filename(opt.homedir, - "trustdb" EXTSEP_S "gpg", NULL ); - - if( access( fname, R_OK ) ) { - if( errno != ENOENT ) { - log_error( _("%s: can't access: %s\n"), fname, strerror(errno) ); - m_free(fname); - return G10ERR_TRUSTDB; - } - if( create ) { - FILE *fp; - TRUSTREC rec; - int rc; - char *p = strrchr( fname, DIRSEP_C ); - mode_t oldmask; - - assert(p); - *p = 0; - if( access( fname, F_OK ) ) { - try_make_homedir( fname ); - log_fatal( _("%s: directory does not exist!\n"), fname ); - } - *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__ */ - oldmask=umask(077); - fp =fopen( fname, "wb" ); - umask(oldmask); - if( !fp ) - log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) ); - fclose(fp); - db_fd = open( db_name, O_RDWR | MY_O_BINARY ); - 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__ */ - - rc = create_version_record (); - if( rc ) - log_fatal( _("%s: failed to create version record: %s"), - 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 ); - - if( !opt.quiet ) - log_info(_("%s: trustdb created\n"), db_name); - - return 0; - } - } - m_free(db_name); - db_name = fname; - return 0; -} - - -const char * -tdbio_get_dbname() -{ - return db_name; -} - - - -static void -open_db() -{ - 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__ */ - db_fd = open (db_name, O_RDWR | MY_O_BINARY ); - if (db_fd == -1 && errno == EACCES) { - db_fd = open (db_name, O_RDONLY | MY_O_BINARY ); - if (db_fd != -1) - log_info (_("NOTE: trustdb not writable\n")); - } - 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 = trust hash - */ -static void -create_hashtable( TRUSTREC *vr, int type ) -{ - TRUSTREC rec; - off_t offset; - ulong recnum; - int i, n, rc; - - offset = lseek( db_fd, 0, SEEK_END ); - if( offset == -1 ) - log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) ); - recnum = offset / TRUST_RECORD_LEN; - assert(recnum); /* this is will never be the first record */ - - if( !type ) - 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++ ) { - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HTBL; - rec.recnum = recnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_fatal( _("%s: failed to create hashtable: %s\n"), - db_name, g10_errstr(rc)); - } - /* update the version record */ - rc = tdbio_write_record( vr ); - if( !rc ) - rc = tdbio_sync(); - if( rc ) - log_fatal( _("%s: error updating version record: %s\n"), - db_name, g10_errstr(rc)); -} - - -int -tdbio_db_matches_options() -{ - static int yes_no = -1; - - if( yes_no == -1 ) { - 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, g10_errstr(rc) ); - - if( !vr.r.ver.marginals && !vr.r.ver.completes - && !vr.r.ver.cert_depth ) - { /* special hack for trustdbs created by old versions of GnuPG */ - vr.r.ver.marginals = opt.marginals_needed; - vr.r.ver.completes = opt.completes_needed; - vr.r.ver.cert_depth = opt.max_cert_depth; - rc = tdbio_write_record( &vr ); - if( !rc && !in_transaction ) - rc = tdbio_sync(); - if( rc ) - log_error( _("%s: error writing version record: %s\n"), - db_name, g10_errstr(rc) ); - } - - yes_no = vr.r.ver.marginals == opt.marginals_needed - && vr.r.ver.completes == opt.completes_needed - && vr.r.ver.cert_depth == opt.max_cert_depth; - } - return yes_no; -} - - -/**************** - * Return the nextstamp value. - */ -ulong -tdbio_read_nextcheck () -{ - 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, g10_errstr(rc) ); - return vr.r.ver.nextcheck; -} - -/* Return true when the stamp was actually changed. */ -int -tdbio_write_nextcheck (ulong stamp) -{ - 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, g10_errstr(rc) ); - - 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, g10_errstr(rc) ); - return 1; -} - - - -/**************** - * Return the record number of the trusthash tbl or create a new one. - */ -static ulong -get_trusthashrec(void) -{ - static ulong trusthashtbl; /* record number of the trust hashtable */ - - 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, g10_errstr(rc) ); - if( !vr.r.ver.trusthashtbl ) - create_hashtable( &vr, 0 ); - - trusthashtbl = vr.r.ver.trusthashtbl; - } - return trusthashtbl; -} - - - -/**************** - * Update a hashtable. - * table gives the start of the table, key and keylen is the key, - * newrecnum is the record number to insert. - */ -static int -upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum ) -{ - TRUSTREC lastrec, rec; - ulong hashrec, item; - int msb; - int level=0; - int rc, i; - - hashrec = table; - next_level: - msb = key[level]; - hashrec += msb / ITEMS_PER_HTBL_RECORD; - rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); - if( rc ) { - log_error( db_name, "upd_hashtable: read failed: %s\n", - g10_errstr(rc) ); - return rc; - } - - item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) { /* insert a new item into the hash table */ - rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error( db_name, "upd_hashtable: write htbl failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - else if( item != newrecnum ) { /* must do an update */ - lastrec = rec; - rc = tdbio_read_record( item, &rec, 0 ); - if( rc ) { - log_error( "upd_hashtable: read item failed: %s\n", - g10_errstr(rc) ); - return rc; - } - - if( rec.rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error( "hashtable has invalid indirections.\n"); - return G10ERR_TRUSTDB; - } - goto next_level; - } - else if( rec.rectype == RECTYPE_HLST ) { /* extend list */ - /* see whether the key is already in this list */ - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec.r.hlst.rnum[i] == newrecnum ) { - return 0; /* okay, already in the list */ - } - } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST); - if( rc ) { - log_error( "upd_hashtable: read hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - else - break; /* not there */ - } - /* find the next free entry and put it in */ - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( !rec.r.hlst.rnum[i] ) { - rec.r.hlst.rnum[i] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error( "upd_hashtable: write hlst failed: %s\n", - g10_errstr(rc) ); - return rc; /* done */ - } - } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST ); - if( rc ) { - log_error( "upd_hashtable: read hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - else { /* add a new list record */ - rec.r.hlst.next = item = tdbio_new_recnum(); - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error( "upd_hashtable: write hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HLST; - rec.recnum = item; - rec.r.hlst.rnum[0] = newrecnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error( "upd_hashtable: write ext hlst failed: %s\n", - g10_errstr(rc) ); - return rc; /* done */ - } - } /* end loop over hlst slots */ - } - else if( rec.rectype == RECTYPE_TRUST ) { /* insert a list record */ - if( rec.recnum == newrecnum ) { - return 0; - } - item = rec.recnum; /* save number of key record */ - memset( &rec, 0, sizeof rec ); - rec.rectype = RECTYPE_HLST; - rec.recnum = tdbio_new_recnum(); - rec.r.hlst.rnum[0] = item; /* old keyrecord */ - rec.r.hlst.rnum[1] = newrecnum; /* and new one */ - rc = tdbio_write_record( &rec ); - if( rc ) { - log_error( "upd_hashtable: write new hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - /* update the hashtable record */ - lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum; - rc = tdbio_write_record( &lastrec ); - if( rc ) - log_error( "upd_hashtable: update htbl failed: %s\n", - 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 G10ERR_TRUSTDB; - } - } - - return 0; -} - - -/**************** - * Drop an entry from a hashtable - * table gives the start of the table, key and keylen is the key, - */ -static int -drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum ) -{ - TRUSTREC rec; - ulong hashrec, item; - int msb; - int level=0; - int rc, i; - - hashrec = table; - next_level: - msb = key[level]; - hashrec += msb / ITEMS_PER_HTBL_RECORD; - rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL ); - if( rc ) { - log_error( db_name, "drop_from_hashtable: read failed: %s\n", - g10_errstr(rc) ); - return rc; - } - - item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) /* not found - forget about it */ - return 0; - - if( item == recnum ) { /* tables points direct to the record */ - rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0; - rc = tdbio_write_record( &rec ); - if( rc ) - log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n", - g10_errstr(rc) ); - return rc; - } - - rc = tdbio_read_record( item, &rec, 0 ); - if( rc ) { - log_error( "drop_from_hashtable: read item failed: %s\n", - g10_errstr(rc) ); - return rc; - } - - if( rec.rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error( "hashtable has invalid indirections.\n"); - return G10ERR_TRUSTDB; - } - goto next_level; - } - - if( rec.rectype == RECTYPE_HLST ) { - for(;;) { - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec.r.hlst.rnum[i] == recnum ) { - rec.r.hlst.rnum[i] = 0; /* drop */ - rc = tdbio_write_record( &rec ); - if( rc ) - log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - if( rec.r.hlst.next ) { - rc = tdbio_read_record( rec.r.hlst.next, - &rec, RECTYPE_HLST); - if( rc ) { - log_error( "drop_from_hashtable: read hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - else - return 0; /* key not in table */ - } - } - - log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n", - table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item); - return G10ERR_TRUSTDB; -} - - - -/**************** - * Lookup a record via the hashtable tablewith key/keylen and return the - * result in rec. cmp() should return if the record is the desired one. - * Returns -1 if not found, 0 if found or another errocode - */ -static int -lookup_hashtable( ulong table, const byte *key, size_t keylen, - int (*cmpfnc)(void*, const TRUSTREC *), void *cmpdata, - TRUSTREC *rec ) -{ - int rc; - ulong hashrec, item; - int msb; - int level=0; - - hashrec = table; - next_level: - msb = key[level]; - 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", g10_errstr(rc) ); - return rc; - } - - item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD]; - if( !item ) - return -1; /* not found */ - - rc = tdbio_read_record( item, rec, 0 ); - if( rc ) { - log_error( db_name, "hashtable read failed: %s\n", g10_errstr(rc) ); - return rc; - } - if( rec->rectype == RECTYPE_HTBL ) { - hashrec = item; - level++; - if( level >= keylen ) { - log_error( db_name, "hashtable has invalid indirections\n"); - return G10ERR_TRUSTDB; - } - goto next_level; - } - else if( rec->rectype == RECTYPE_HLST ) { - for(;;) { - int i; - - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - if( rec->r.hlst.rnum[i] ) { - TRUSTREC tmp; - - rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 ); - if( rc ) { - log_error( "lookup_hashtable: read item failed: %s\n", - g10_errstr(rc) ); - return rc; - } - if( (*cmpfnc)( cmpdata, &tmp ) ) { - *rec = tmp; - return 0; - } - } - } - if( rec->r.hlst.next ) { - rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST ); - if( rc ) { - log_error( "lookup_hashtable: read hlst failed: %s\n", - g10_errstr(rc) ); - return rc; - } - } - else - return -1; /* not found */ - } - } - - - if( (*cmpfnc)( cmpdata, rec ) ) - return 0; /* really found */ - - return -1; /* no: not found */ -} - - -/**************** - * Update the trust hashtbl or create the table if it does not exist - */ -static int -update_trusthashtbl( TRUSTREC *tr ) -{ - return upd_hashtable( get_trusthashrec(), - tr->r.trust.fingerprint, 20, tr->recnum ); -} - - - -void -tdbio_dump_record( TRUSTREC *rec, FILE *fp ) -{ - int i; - ulong rnum = rec->recnum; - - fprintf(fp, "rec %5lu, ", rnum ); - - switch( rec->rectype ) { - case 0: fprintf(fp, "blank\n"); - break; - case RECTYPE_VER: fprintf(fp, - "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, - 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_HTBL: - fprintf(fp, "htbl,"); - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) - fprintf(fp, " %lu", rec->r.htbl.item[i] ); - putc('\n', fp); - break; - case RECTYPE_HLST: - fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next ); - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) - 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; - } -} - -/**************** - * read the record with number recnum - * returns: -1 on error, 0 on success - */ -int -tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected ) -{ - byte readbuf[TRUST_RECORD_LEN]; - const byte *buf, *p; - int rc = 0; - int n, i; - - if( db_fd == -1 ) - open_db(); - buf = get_record_from_cache( recnum ); - if( !buf ) { - if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { - log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) ); - return G10ERR_READ_FILE; - } - n = read( db_fd, readbuf, TRUST_RECORD_LEN); - if( !n ) { - return -1; /* eof */ - } - else if( n != TRUST_RECORD_LEN ) { - log_error(_("trustdb: read failed (n=%d): %s\n"), n, - strerror(errno) ); - return G10ERR_READ_FILE; - } - buf = readbuf; - } - rec->recnum = recnum; - rec->dirty = 0; - p = buf; - rec->rectype = *p++; - if( expected && rec->rectype != expected ) { - log_error("%lu: read expected rec type %d, got %d\n", - recnum, expected, rec->rectype ); - return G10ERR_TRUSTDB; - } - p++; /* skip reserved byte */ - switch( rec->rectype ) { - case 0: /* unused (free) record */ - break; - case RECTYPE_VER: /* version record */ - if( memcmp(buf+1, "gpg", 3 ) ) { - log_error( _("%s: not a trustdb file\n"), db_name ); - rc = G10ERR_TRUSTDB; - } - 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.nextcheck = buftoulong(p); p += 4; - p += 4; - p += 4; - rec->r.ver.firstfree =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 = G10ERR_TRUSTDB; - } - else if( rec->r.ver.version != 3 ) { - log_error( _("%s: invalid file version %d\n"), db_name, - rec->r.ver.version ); - rc = G10ERR_TRUSTDB; - } - break; - case RECTYPE_FREE: - rec->r.free.next = buftoulong(p); p += 4; - break; - case RECTYPE_HTBL: - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) { - rec->r.htbl.item[i] = buftoulong(p); p += 4; - } - break; - case RECTYPE_HLST: - rec->r.hlst.next = buftoulong(p); p += 4; - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - 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 = G10ERR_TRUSTDB; - break; - } - - return rc; -} - -/**************** - * Write the record at RECNUM - */ -int -tdbio_write_record( TRUSTREC *rec ) -{ - byte buf[TRUST_RECORD_LEN], *p; - int rc = 0; - int i; - ulong recnum = rec->recnum; - - if( db_fd == -1 ) - open_db(); - - memset(buf, 0, TRUST_RECORD_LEN); - p = buf; - *p++ = rec->rectype; p++; - switch( rec->rectype ) { - case 0: /* unused record */ - break; - case RECTYPE_VER: /* version record */ - if( recnum ) - BUG(); - memcpy(p-1, "gpg", 3 ); p += 2; - *p++ = rec->r.ver.version; - *p++ = rec->r.ver.marginals; - *p++ = rec->r.ver.completes; - *p++ = rec->r.ver.cert_depth; - p += 4; /* skip lock flags */ - ulongtobuf(p, rec->r.ver.created); p += 4; - ulongtobuf(p, rec->r.ver.nextcheck); p += 4; - p += 4; - p += 4; - ulongtobuf(p, rec->r.ver.firstfree ); 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_HTBL: - for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) { - ulongtobuf( p, rec->r.htbl.item[i]); p += 4; - } - break; - - case RECTYPE_HLST: - ulongtobuf( p, rec->r.hlst.next); p += 4; - for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) { - ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4; - } - 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(); - } - - rc = put_record_into_cache( recnum, buf ); - if( rc ) - ; - else if( rec->rectype == RECTYPE_TRUST ) - rc = update_trusthashtbl( rec ); - - return rc; -} - -int -tdbio_delete_record( ulong recnum ) -{ - TRUSTREC vr, rec; - int rc; - - /* Must read the record fist, so we can drop it from the hash tables */ - rc = tdbio_read_record( recnum, &rec, 0 ); - if( rc ) - ; - else if( rec.rectype == RECTYPE_TRUST ) { - rc = drop_from_hashtable( get_trusthashrec(), - rec.r.trust.fingerprint, 20, rec.recnum ); - } - - if( rc ) - return rc; - - /* now we can chnage it to a free record */ - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - db_name, g10_errstr(rc) ); - - rec.recnum = recnum; - rec.rectype = RECTYPE_FREE; - rec.r.free.next = vr.r.ver.firstfree; - vr.r.ver.firstfree = recnum; - rc = tdbio_write_record( &rec ); - if( !rc ) - rc = tdbio_write_record( &vr ); - return rc; -} - -/**************** - * create a new record and return its record number - */ -ulong -tdbio_new_recnum() -{ - off_t offset; - ulong recnum; - TRUSTREC vr, rec; - int rc; - - /* look for unused records */ - rc = tdbio_read_record( 0, &vr, RECTYPE_VER ); - if( rc ) - log_fatal( _("%s: error reading version record: %s\n"), - 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, g10_errstr(rc) ); - return rc; - } - /* update dir record */ - vr.r.ver.firstfree = rec.r.free.next; - rc = tdbio_write_record( &vr ); - if( rc ) { - log_error( _("%s: error writing dir record: %s\n"), - db_name, g10_errstr(rc) ); - return rc; - } - /*zero out the new record */ - memset( &rec, 0, sizeof rec ); - rec.rectype = 0; /* unused record */ - rec.recnum = recnum; - rc = tdbio_write_record( &rec ); - if( rc ) - log_fatal(_("%s: failed to zero a record: %s\n"), - db_name, g10_errstr(rc)); - } - else { /* not found, append a new record */ - offset = lseek( db_fd, 0, SEEK_END ); - if( offset == -1 ) - log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) ); - recnum = offset / TRUST_RECORD_LEN; - assert(recnum); /* this is will never be the first record */ - /* we must write a record, so that the next call to this function - * returns another recnum */ - memset( &rec, 0, sizeof rec ); - rec.rectype = 0; /* unused record */ - rec.recnum = recnum; - rc = 0; - if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) { - log_error(_("trustdb rec %lu: lseek failed: %s\n"), - recnum, strerror(errno) ); - 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 = G10ERR_WRITE_FILE; - } - } - - if( rc ) - log_fatal(_("%s: failed to append a record: %s\n"), - db_name, g10_errstr(rc)); - } - return recnum ; -} - - - -static int -cmp_trec_fpr ( void *fpr, const TRUSTREC *rec ) -{ - return rec->rectype == RECTYPE_TRUST - && !memcmp( rec->r.trust.fingerprint, fpr, 20); -} - - -int -tdbio_search_trust_byfpr( const byte *fingerprint, TRUSTREC *rec ) -{ - int rc; - - /* locate the trust record using the hash table */ - rc = lookup_hashtable( get_trusthashrec(), fingerprint, 20, - cmp_trec_fpr, (void*)fingerprint, rec ); - return rc; -} - -int -tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec) -{ - byte fingerprint[MAX_FINGERPRINT_LEN]; - size_t fingerlen; - - fingerprint_from_pk( pk, fingerprint, &fingerlen ); - for (; fingerlen < 20; fingerlen++ ) - fingerprint[fingerlen] = 0; - return tdbio_search_trust_byfpr (fingerprint, rec); -} - - - -void -tdbio_invalid(void) -{ - log_error(_( - "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n") ); - 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 deleted file mode 100644 index f2c6bec1b..000000000 --- a/g10/tdbio.h +++ /dev/null @@ -1,111 +0,0 @@ -/* tdbio.h - Trust database I/O functions - * 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 - */ - -#ifndef G10_TDBIO_H -#define G10_TDBIO_H - -#include "host2net.h" - -#define TRUST_RECORD_LEN 40 -#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5) -#define ITEMS_PER_HTBL_RECORD ((TRUST_RECORD_LEN-2)/4) -#define ITEMS_PER_HLST_RECORD ((TRUST_RECORD_LEN-6)/5) -#define ITEMS_PER_PREF_RECORD (TRUST_RECORD_LEN-10) -#if ITEMS_PER_PREF_RECORD % 2 - #error ITEMS_PER_PREF_RECORD must be even -#endif -#define MAX_LIST_SIGS_DEPTH 20 - - -#define RECTYPE_VER 1 -#define RECTYPE_HTBL 10 -#define RECTYPE_HLST 11 -#define RECTYPE_TRUST 12 -#define RECTYPE_VALID 13 -#define RECTYPE_FREE 254 - - -struct trust_record { - int rectype; - int mark; - int dirty; /* for now only used internal by functions */ - struct trust_record *next; /* help pointer to build lists in memory */ - ulong recnum; - union { - struct { /* version record: */ - byte version; /* should be 3 */ - byte marginals; - byte completes; - byte cert_depth; - ulong created; /* timestamp of trustdb creation */ - ulong nextcheck; /* timestamp of next scheduled check */ - ulong reserved; - ulong reserved2; - ulong firstfree; - ulong reserved3; - ulong trusthashtbl; - } ver; - struct { /* free record */ - ulong next; - } free; - struct { - ulong item[ITEMS_PER_HTBL_RECORD]; - } htbl; - struct { - 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; - -/*-- tdbio.c --*/ -int tdbio_set_dbname( const char *new_dbname, int create ); -const char *tdbio_get_dbname(void); -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_nextcheck (void); -int tdbio_write_nextcheck (ulong stamp); -int tdbio_is_dirty(void); -int tdbio_sync(void); -int tdbio_begin_transaction(void); -int tdbio_end_transaction(void); -int tdbio_cancel_transaction(void); -int tdbio_delete_record( ulong recnum ); -ulong tdbio_new_recnum(void); -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 /*G10_TDBIO_H*/ diff --git a/g10/textfilter.c b/g10/textfilter.c deleted file mode 100644 index ded030d79..000000000 --- a/g10/textfilter.c +++ /dev/null @@ -1,235 +0,0 @@ -/* textfilter.c - * Copyright (C) 1998, 1999, 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 "errors.h" -#include "iobuf.h" -#include "memory.h" -#include "util.h" -#include "filter.h" -#include "i18n.h" -#include "options.h" - -#ifdef HAVE_DOSISH_SYSTEM - #define LF "\r\n" -#else - #define LF "\n" -#endif - -#define MAX_LINELEN 19995 /* a little bit smaller than in armor.c */ - /* to make sure that a warning is displayed while */ - /* creating a message */ - -static unsigned -len_without_trailing_chars( byte *line, unsigned len, const char *trimchars ) -{ - byte *p, *mark; - unsigned n; - - for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { - if( strchr( trimchars, *p ) ) { - if( !mark ) - mark = p; - } - else - mark = NULL; - } - - return mark? (mark - line) : len; -} - -unsigned -len_without_trailing_ws( byte *line, unsigned len ) -{ - return len_without_trailing_chars( line, len, " \t\r\n" ); -} - - - - -static int -standard( text_filter_context_t *tfx, IOBUF a, - byte *buf, size_t size, size_t *ret_len) -{ - int rc=0; - size_t len = 0; - unsigned maxlen; - - assert( size > 10 ); - size -= 2; /* reserve 2 bytes to append CR,LF */ - while( !rc && len < size ) { - int lf_seen; - - while( len < size && tfx->buffer_pos < tfx->buffer_len ) - buf[len++] = tfx->buffer[tfx->buffer_pos++]; - if( len >= size ) - continue; - - /* read the next line */ - maxlen = MAX_LINELEN; - tfx->buffer_pos = 0; - tfx->buffer_len = iobuf_read_line( a, &tfx->buffer, - &tfx->buffer_size, &maxlen ); - if( !maxlen ) - tfx->truncated++; - if( !tfx->buffer_len ) { - if( !len ) - rc = -1; /* eof */ - break; - } - lf_seen = tfx->buffer[tfx->buffer_len-1] == '\n'; - tfx->buffer_len = trim_trailing_ws( tfx->buffer, tfx->buffer_len ); - if( lf_seen ) { - tfx->buffer[tfx->buffer_len++] = '\r'; - tfx->buffer[tfx->buffer_len++] = '\n'; - } - } - *ret_len = len; - return rc; -} - - - - -/**************** - * The filter is used to make canonical text: Lines are terminated by - * CR, LF, trailing white spaces are removed. - */ -int -text_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) -{ - size_t size = *ret_len; - text_filter_context_t *tfx = opaque; - int rc=0; - - if( control == IOBUFCTRL_UNDERFLOW ) { - rc = standard( tfx, a, buf, size, ret_len ); - } - else if( control == IOBUFCTRL_FREE ) { - if( tfx->truncated ) - log_error(_("can't handle text lines longer than %d characters\n"), - MAX_LINELEN ); - m_free( tfx->buffer ); - tfx->buffer = NULL; - } - else if( control == IOBUFCTRL_DESC ) - *(char**)buf = "text_filter"; - return rc; -} - - -/**************** - * Copy data from INP to OUT and do some escaping if requested. - * md is updated as required by rfc2440 - */ -int -copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md, - int escape_dash, int escape_from, int pgp2mode ) -{ - unsigned maxlen; - byte *buffer = NULL; /* malloced buffer */ - unsigned bufsize; /* and size of this buffer */ - unsigned n; - int truncated = 0; - int pending_lf = 0; - - if( !opt.pgp2_workarounds ) - pgp2mode = 0; - - if( !escape_dash ) - escape_from = 0; - - for(;;) { - maxlen = MAX_LINELEN; - n = iobuf_read_line( inp, &buffer, &bufsize, &maxlen ); - if( !maxlen ) - truncated++; - - if( !n ) - break; /* read_line has returned eof */ - - /* update the message digest */ - if( escape_dash ) { - if( pending_lf ) { - md_putc( md, '\r' ); - md_putc( md, '\n' ); - } - md_write( md, buffer, - len_without_trailing_chars( buffer, n, - pgp2mode? " \r\n":" \t\r\n")); - } - else - md_write( md, buffer, n ); - pending_lf = buffer[n-1] == '\n'; - - /* write the output */ - if( ( escape_dash && *buffer == '-') - || ( escape_from && n > 4 && !memcmp(buffer, "From ", 5 ) ) ) { - iobuf_put( out, '-' ); - iobuf_put( out, ' ' ); - } - - #if 0 /*defined(HAVE_DOSISH_SYSTEM)*/ - /* We don't use this anymore because my interpretation of rfc2440 7.1 - * is that there is no conversion needed. If one decides to - * clearsign a unix file on a DOS box he will get a mixed line endings. - * If at some point it turns out, that a conversion is a nice feature - * we can make an option out of it. - */ - /* make sure the lines do end in CR,LF */ - if( n > 1 && ( (buffer[n-2] == '\r' && buffer[n-1] == '\n' ) - || (buffer[n-2] == '\n' && buffer[n-1] == '\r'))) { - iobuf_write( out, buffer, n-2 ); - iobuf_put( out, '\r'); - iobuf_put( out, '\n'); - } - else if( n && buffer[n-1] == '\n' ) { - iobuf_write( out, buffer, n-1 ); - iobuf_put( out, '\r'); - iobuf_put( out, '\n'); - } - else - iobuf_write( out, buffer, n ); - - #else - iobuf_write( out, buffer, n ); - #endif - } - - /* at eof */ - if( !pending_lf ) { /* make sure that the file ends with a LF */ - iobuf_writestr( out, LF ); - if( !escape_dash ) - md_putc( md, '\n' ); - } - - if( truncated ) - log_info(_("input line longer than %d characters\n"), MAX_LINELEN ); - - return 0; /* okay */ -} - diff --git a/g10/trustdb.c b/g10/trustdb.c deleted file mode 100644 index fe2ad34e3..000000000 --- a/g10/trustdb.c +++ /dev/null @@ -1,1642 +0,0 @@ -/* trustdb.c - * 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 <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "options.h" -#include "packet.h" -#include "main.h" -#include "i18n.h" -#include "tdbio.h" -#include "trustdb.h" - - -/* - * 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 key_item **KeyHashTable; /* see new_key_hash_table() */ - -/* - * 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; -}; - - -/* control information for the trust DB */ -static struct { - int init; - int level; - char *dbname; -} trustdb_args; - -/* 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; - -static int validate_keys (int interactive); - - -/********************************************** - ************* some helpers ******************* - **********************************************/ - -static struct key_item * -new_key_item (void) -{ - struct key_item *k; - - k = m_alloc_clear (sizeof *k); - return k; -} - -static void -release_key_items (struct key_item *k) -{ - struct key_item *k2; - - for (; k; k = k2) - { - k2 = k->next; - m_free (k); - } -} - -/* - * 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 KeyHashTable -new_key_hash_table (void) -{ - struct key_item **tbl; - - tbl = m_alloc_clear (1024 * sizeof *tbl); - return tbl; -} - -static void -release_key_hash_table (KeyHashTable tbl) -{ - int i; - - if (!tbl) - return; - for (i=0; i < 1024; i++) - release_key_items (tbl[i]); - m_free (tbl); -} - -/* - * Returns: True if the keyID is in the given hash table - */ -static int -test_key_hash_table (KeyHashTable tbl, u32 *kid) -{ - struct key_item *k; - - 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 -add_key_hash_table (KeyHashTable tbl, u32 *kid) -{ - 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_key_array ( struct key_array *keys ) -{ - struct key_array *k; - - if (keys) { - for (k=keys; k->keyblock; k++) - release_kbnode (k->keyblock); - m_free (keys); - } -} - - -/********************************************* - ********** Initialization ***************** - *********************************************/ - - - -/* - * 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. - */ -void -register_trusted_key( const char *string ) -{ - 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; - } - - 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 -add_utk (u32 *kid) -{ - struct key_item *k; - - for (k = utk_list; k; k = k->next) - { - if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) - { - return 0; - } - } - - 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; -} - - -/**************** - * Verify that all our secret keys are usable and put them into the utk_list. - */ -static void -verify_own_keys(void) -{ - TRUSTREC rec; - ulong recnum; - int rc; - struct key_item *k; - - if (utk_list) - 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); - } - log_info (_("key %08lX marked as ultimately trusted\n"), - (ulong)k->kid[1]); - } - } - - - /* 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 -read_record (ulong recno, TRUSTREC *rec, int rectype ) -{ - 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(); - } - if (rectype != rec->rectype) - { - log_error(_("trust record %lu is not of requested type %d\n"), - rec->recnum, rectype); - tdbio_invalid(); - } -} - -/* - * Write a record and die on error - */ -static void -write_record (TRUSTREC *rec) -{ - 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(); - } -} - -/* - * 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); - } -} - - -/**************** - * Perform some checks over the trustdb - * level 0: only open the db - * 1: used for initial program startup - */ -int -setup_trustdb( int level, const char *dbname ) -{ - /* just store the args */ - if( trustdb_args.init ) - return 0; - trustdb_args.level = level; - 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; - - trustdb_args.init = 1; - - 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", g10_errstr(rc) ); -} - - - - -/*********************************************** - ************* Print helpers **************** - ***********************************************/ - -/**************** - * This function returns a letter for a trustvalue Trust flags - * are ignore. - */ -int -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; - } -} - - -/**************** - * 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; - } - - if (scheduled > make_timestamp ()) - { - log_info (_("next trustdb check due at %s\n"), - strtimestamp (scheduled)); - return; - } - } - - validate_keys (0); -} - - -/* - * Recreate the WoT. - */ -void -update_trustdb() -{ - init_trustdb(); - validate_keys (1); -} - -void -revalidation_mark (void) -{ - 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; -} - - -/*********************************************** - *********** Ownertrust et al. **************** - ***********************************************/ - -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; -} - - -/**************** - * Return the assigned ownertrust value for the given public key. - * The key should be the primary key. - */ -unsigned int -get_ownertrust ( PKT_public_key *pk) -{ - 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 rec.r.trust.ownertrust; -} - -/* - * Same as get_ownertrust but return a trust letter instead of an value. - */ -int -get_ownertrust_info (PKT_public_key *pk) -{ - unsigned int otrust; - int c; - - otrust = get_ownertrust (pk); - c = trust_letter( (otrust & TRUST_MASK) ); - if( !c ) - c = '?'; - return c; -} - -/* - * Set the trust value of the given public key to the new value. - * The key should be a primary one. - */ -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; - - if (DBG_TRUST) - log_debug ("insert ownertrust %u\n", new_trust ); - - 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 (); - } -} - -/* 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 if (rc != -1) - { - tdbio_invalid (); - } - return 0; -} - -/* - * Note: Caller has to do a sync - */ -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; - - /* 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; - } - - return any; -} - - - -/*********************************************** - ********* Query trustdb values ************** - ***********************************************/ - -/* - * 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. - */ -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); - } - } - } - - 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; - } - } - 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; -} - - -int -get_validity_info (PKT_public_key *pk, const byte *namehash) -{ - int trustlevel; - int c; - - 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; -} - - - - -void -list_trust_path( const char *username ) -{ -} - - - - -/**************** - * 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 -enum_cert_paths( void **context, ulong *lid, - unsigned *ownertrust, unsigned *validity ) -{ - return -1; -} - - -/**************** - * Print the current path - */ -void -enum_cert_paths_print( void **context, FILE *fp, - int refresh, ulong selected_lid ) -{ - return; -} - - - -/**************************************** - *********** NEW NEW NEW **************** - ****************************************/ - -static int -ask_ownertrust (u32 *kid) -{ - PKT_public_key *pk; - int rc; - int ot; - - 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; - } - - 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; -} - - -static void -mark_keyblock_seen (KeyHashTable tbl, KBNODE node) -{ - 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); - add_key_hash_table (tbl, aki); - } -} - - - -static void -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'); - } - } - } -} - - -static void -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; - } - } - } - - if (any) - do_sync (); -} - -/* - * check whether the signature sig is in the klist k - */ -static struct key_item * -is_in_klist (struct key_item *k, PKT_signature *sig) -{ - for (; k; k = k->next) - { - if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) - return k; - } - return NULL; -} - -/* - * 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 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; - - /* 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; - } - } - } -} - - -/* - * 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 -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 (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 any_signed; -} - - -static int -search_skipfnc (void *opaque, u32 *kid) -{ - return test_key_hash_table ((KeyHashTable)opaque, kid); -} - - -/* - * 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. - */ -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; - } - - /* 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; - } - - 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; - } - - keys[nkeys].keyblock = NULL; - return keys; -} - - -static void -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)); - } - if (opt.verbose) - log_info ("%d unconnected keys (%d trust records cleared)\n", - count, nreset); - do_sync (); -} - - -/* - * Run the key validation procedure. - * - * 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 - * - */ -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++; - } - - /* 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; - } - - - 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 rc; -} - - diff --git a/g10/trustdb.h b/g10/trustdb.h deleted file mode 100644 index c94a2daa1..000000000 --- a/g10/trustdb.h +++ /dev/null @@ -1,76 +0,0 @@ -/* trustdb.h - Trust database - * 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 - */ - -#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/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 */ -#define TRUST_MARGINAL 4 /* m: marginally trusted */ -#define TRUST_FULLY 5 /* f: fully trusted */ -#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 /* r: revoked but for subkeys */ -#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */ -#define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */ - -/*-- trustdb.c --*/ -void register_trusted_key( const char *string ); -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 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 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); -void export_ownertrust(void); -void import_ownertrust(const char *fname); - -/*-- pkclist.c --*/ -int edit_ownertrust (PKT_public_key *pk, int mode ); - -#endif /*G10_TRUSTDB_H*/ diff --git a/g10/verify.c b/g10/verify.c deleted file mode 100644 index 7ab20c140..000000000 --- a/g10/verify.c +++ /dev/null @@ -1,189 +0,0 @@ -/* verify.c - verify signed data - * Copyright (C) 1998, 1999, 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 <unistd.h> /* for isatty() */ - -#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" -#include "ttyio.h" -#include "i18n.h" - - - -/**************** - * Assume that the input is a signature and verify it without - * generating any output. With no arguments, the signature packet - * is read from stdin (it may be a detached signature when not - * used in batch mode). If only a sigfile is given, it may be a complete - * signature or a detached signature in which case the signed stuff - * is expected from stdin. With more than 1 argument, the first should - * be a detached signature and the remaining files are the signed stuff. - */ - -int -verify_signatures( int nfiles, char **files ) -{ - IOBUF fp; - armor_filter_context_t afx; - const char *sigfile; - int i, rc; - 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 G10ERR_OPEN_FILE; - } - - if( !opt.no_armor && use_armor_filter( fp ) ) - iobuf_push_filter( fp, armor_filter, &afx ); - - sl = NULL; - for(i=1 ; i < nfiles; i++ ) - add_to_strlist( &sl, files[i] ); - rc = proc_signature_packets( NULL, fp, sl, sigfile ); - free_strlist(sl); - iobuf_close(fp); - if( afx.no_openpgp_data && rc == -1 ) { - log_error(_("the signature could not be verified.\n" - "Please remember that the signature file (.sig or .asc)\n" - "should be the first file given on the command line.\n") ); - rc = 0; - } - - return rc; -} - - -void -print_file_status( int status, const char *name, int what ) -{ - char *p = m_alloc(strlen(name)+10); - sprintf(p, "%d %s", what, name ); - write_status_text( status, p ); - m_free(p); -} - - -static int -verify_one_file( const char *name ) -{ - IOBUF fp; - armor_filter_context_t afx; - int rc; - - print_file_status( STATUS_FILE_START, name, 1 ); - fp = iobuf_open(name); - if( !fp ) { - print_file_status( STATUS_FILE_ERROR, name, 1 ); - log_error(_("can't open `%s'\n"), print_fname_stdin(name)); - return G10ERR_OPEN_FILE; - } - - if( !opt.no_armor ) { - if( use_armor_filter( fp ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( fp, armor_filter, &afx ); - } - } - - rc = proc_signature_packets( NULL, fp, NULL, name ); - iobuf_close(fp); - write_status( STATUS_FILE_DONE ); - return rc; -} - -/**************** - * Verify each file given in the files array or read the names of the - * files from stdin. - * Note: This function can not handle detached signatures. - */ -int -verify_files( int nfiles, char **files ) -{ - int i; - - if( !nfiles ) { /* read the filenames from stdin */ - 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 G10ERR_GENERAL; - } - /* This code does not work on MSDOS but how cares there are - * also no script languages available. We don't strip any - * spaces, so that we can process nearly all filenames */ - line[strlen(line)-1] = 0; - verify_one_file( line ); - } - - } - else { /* take filenames from the array */ - for(i=0; i < nfiles; i++ ) - verify_one_file( files[i] ); - } - return 0; -} |