diff options
Diffstat (limited to 'g10')
60 files changed, 3703 insertions, 1272 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index 64056be69..6d3aa7cc4 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,231 +1,710 @@ -Thu May 25 18:39:11 CEST 2000 Werner Koch <wk@openit.de> +Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@> - * kbxio.c: New. + Replaced everything with the code from the STABLE-BRANCH-1-0 and + started to backport the changes from the 1.1 development branch + which are dated according to the ChangeLog of the 1.1 from + Sat Sep 18 12:16:08 CEST 1999 to Thu May 25 18:39:11 CEST 2000. + Here are those changes, some of them are duplicates because they + have been done on both branch simultaneously. - * kbxfile.c (print_kbxfile): Add a loop - (do_print_kbxfile): Fixed passing to kbx_dump_blob. + * gpg.c (print_mds): Add arg keys as a kludge to print hmacs + (main): New option --print-hmac. -Fri Mar 24 11:25:45 CET 2000 Werner Koch <wk@openit.de> + * trustdb.c (verify_own_keys): Do not print warning about unprotected + key when in quiet mode. - * gpg.c (print_mds): Add arg keys as a kludge to print hmacs - (main): New option --print-hmac. + * build-paket.c (do_user_id): Save offset where name has been stored. + + * ringedit.c : Add new access method KBXF + + * kbxfile.c: New. + + * kbx.h: New. + * kbxblob.c: Started to work on the keybox stuff. + + * keygen.c (gen_dsa): Modified to work with gcry_pk_genkey. + + * Removed dummy-cipher.h from all files. + + * keygen.c (gen_elg): Modified to work with gcry_pk_genkey. + (key_from_sexp): New. + (factors_from_sexp): New. + + * g10.c : Renamed to ... + * gpg.c : ... this + * Makefile.am: And fixed it here. + + * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_". + + * misc.c (mpi_read_opaque): Fixed double counting. + + * seckey-cert.c (do_check): Removed buffer and the unmotivated free + on it. + + * pubkey-enc.c (pk_decrypt): New wrapper for the gcry_ function. + * seckey-cert.c (pk_check_secret_key): Likewise. + * encode.c (pk_encrypt): Likewise. + + * parse-packet.c (parse_key): Fixed case of unencrypted secret keys. + + * misc.c (mpi_print): Use gcry_mpi_aprint. + (pubkey_nbits): Kludge to use the gcry_pk_ API. + + * seskey.c (encode_session_key): Replaced mpi_set_buffer by *_scan. + (do_encode_md): Ditto. + (encode_md_value): Ditto. + * seckey-cert.c (protect_secret_key): Ditto. + * comment.c (make_mpi_comment_node): Replaced mpi_get_buffer by _print. + * pubkey-enc.c (get_it): Ditto. + * sig-check.c (do_signature_check): Ditto. + + * keyid.c (do_fingerprint_md): Replaced mpi_get_buffer by gcry_mpi_print. + (v3_keyid): New. + (keyid_from_sk): And use it here. + (keyid_from_pk): Ditto. + (fingerprint_from_sk): Ditto. + (fingerprint_from_pk): Ditto. + + * misc.c (mpi_print): New. + + * misc.c (checksum_mpi): Now uses gcry_mpi_print to get the data. + + * seckey-cert.c (do_check): Replaced mpi_read_from_buffer. + + * armor.c (armor_filter): Made the "Comment:" header translatable. + + * seckey-cert.c: Removed obsolete mpi_*_protect_flag. + * parse-packet.c: Ditto. + + * misc.c (mpi_read): Removed the secure argumet becuase it is + never used. Changed all Callers. + (mpi_read_opaque): New. + (mpi_write_opaque): New. + * parse-packet.c (parse_key): Use the opaque method also for + v3 keys. + * build-packet.c (do_secret_key): Likewise. + + * g10.c (main): Check libgcrypt version. + + * packet.h: replaced inclusion of mpi.h by a plain typeedef of the + gcry_mpi structure and removed all inclusions of "mpi.h" in all + sources. + + * g10.c: Add --delete-secret-key to the help page. + + * g10.c (main): Changed the default homedir to "~/.gnupg-test" so + that we don't mess up with the stable version. + + * misc.c (mpi_write): New. + (mpi_write): New. + + * misc.c (checksum_u16_nobug): Removed. + (checksum_mpi_counted_nbits): Renamed to ... + (checksum_mpi): ... this to superseed the old one. Changed all + callers. This is because we do not emulate the old gpg bug anymore. + * g10.c (oEmuChecksumBug): Removed. + + * g10.c (register_extension): New... + (main): Use it here instead of register_cipher_extesnion. + (strusage): s/strusage/my_strusage/ . Made static. + (main): Use set_strusage(). + + * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that + traditional cpp don't mess up the macros. Suggested by Jos Backus. + + * armor.c (parse_header_line): Stop parsing on a only WS line too. + Suggested by Aric Cyr. + + * misc.c (pull_in_libs): Removed. + + * mainproc.c (list_node): Print the PK algo in the --with-colon mode. + * keylist.c (list_keyblock): Ditto. + + * misc.c (pull_in_libs): Removed pull in of g10c. + + * misc.c (map_gcry_rc): Removed here and chnaged all users. + + * getkey.c: Replaced check_pubkey_algo by openpgp_pk_test_algo. + * import.c (delete_inv_parts): Ditto. + * pkclist.c: Ditto. + * skclist.c: Ditto. + * pubkey-enc.c: Ditto. + + * g10.c (main): Replaced the function to diable PK algos. + + * g10.c (main): Replaced get_random_bits by gcry_random_bytes. + * seskey.c (encode_session_key): Likewise. + (make_session_key): Renamed randomize_buffer to gcry_randomize + and use the GCRY_xxx_RANDOM constants. + * cipher.c (write_header): Ditto. + * passphrase.c (hash_passphrase): Ditto. + * seckey-cert.c (protect_secret_key): Ditto. + + * getkey.c (find_by_name): Replaced rmd160_hash_buffer + by gcry_md_hash_buffer. + * keyedit.c (show_prefs): Ditto. + * keylist.c (list_keyblock): Ditto. + * trustdb.c (print_uid_from_keyblock): Ditto. + (make_uid_records): Ditto. + + * skclist.c (build_sk_list): Removed the test on faked RNGs. + (is_insecure): Removed. + * g10.c (--quick-random): Removed this option. + + * Replaced all PUBKEY_ALGO_xxx by GCRY_PK_xxxx. + + * misc.c (pubkey_algo_npkey): New as a wrapper around the gcry fucntion. + (pubkey_algo_nskey): Ditto. + (pubkey_algo_nsig): Ditto. + (pubkey_algo_nenc): Ditto. + + * Makefile.am (basicdefs.h): Added. + (install-data-local): Removed the handling for historic gpgm. + + * misc.c (openpgp_cipher_test_algo): New. + (openpgp_pk_test_algo): New. + (openpgp_md_test_algo): New. + + * g10.c (build_list): Changed to use the new functions from libgcrypt. + + * ringedit.c (enum_keyblocks): Set .rt to 0 on open. + + * 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. + + * 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. + + (clearsign_file): Use gcry_md_test_algo() and gcry_md_algo_name(). + + * openfile.c (make_outfile_name): Use case-insenstive compare for + DOS systems. Add ".pgp" to the list of know extensions. + (open_outfile): For DOS systems try to replace the suffix instead of + appending it. + + * encr-data.c (decrypt_data): Reset error on a weak key. + + * cipher.c: Replaced the cipher and digest functions by the gcry_ ones. + * seckey-cert.c: Ditto. + * seskey.c: Ditto. + * g10.c (print_mds): Replaced digst functions with the new gcry_ ones. + * keyid.c: Ditto. + * mainproc.c: Ditto. + * passphrase.c: Ditto. + * sig-check.c: Ditto. + * sign.c: Ditto. + + * pkclist.c (do_edit_ownertrust): Made the answer string const. + + * basicdefs.h: New. Move some defs and decl to this header. + + * 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. + + * filter.h: Changed cipher handle types to the the GCRY_xxx ones. + replaces include cipher by system header include gcrypt.h. + * cipher.c: replaced the cipher functions by the gcry_ ones. + Ditto for the md functions. + + * misc.c (map_gcry_rc): New. + +Wed Jun 28 11:54:44 CEST 2000 Werner Koch <wk@> + + * 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 paclets. + +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. -Mon Mar 13 19:22:46 CET 2000 Werner Koch <wk@openit.de> +Wed Mar 22 13:50:24 CET 2000 Werner Koch <wk@openit.de> - * build-paket.c (do_user_id): Save offset where name has been stored. + * mainproc.c (print_userid): Do UTF8 conversion before printing. + * import.c (import_one): Ditto. + (import_secret_one): Ditto. + (delete_inv_parts): Ditto. - * ringedit.c : Add new access method KBXF +Thu Mar 16 16:20:23 CET 2000 Werner Koch <wk@openit.de> - * kbxfile.c: New. + * keylist.c (print_key_data): Handle a NULL pk gracefully. -Mon Feb 21 22:43:01 CET 2000 Werner Koch <wk@> + * 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. - * kbx.h: New. - * kbxblob.c: Started to work on the keybox stuff. + * 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. -Mon Jan 31 16:37:34 CET 2000 Werner Koch <wk@gnupg.de> + * keylist.c (list_keyblock): Print expiration time for "sub". + (list_one): Add missing merging for public keys. + * mainproc.c (list_node): Ditto. - * keygen.c (gen_dsa): Modified to work with gcry_pk_genkey. +2000-03-14 13:49:38 Werner Koch (wk@habibti.openit.de) - * Removed dummy-cipher.h from all files. + * keygen.c (keyedit_menu): Do not allow to use certain commands + while the secret key is selected. -Thu Jan 27 18:00:44 CET 2000 Werner Koch <wk@gnupg.de> +2000-03-09 12:53:09 Werner Koch (wk@habibti.openit.de) - * keygen.c (gen_elg): Modified to work with gcry_pk_genkey. - (key_from_sexp): New. - (factors_from_sexp): New. + * 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. - * g10.c : Renamed to ... - * gpg.c : ... this - * Makefile.am: And fixed it here. +2000-03-08 10:38:38 Werner Koch (wk@habibti.openit.de) - * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_". + * 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. -Mon Jan 24 22:24:38 CET 2000 Werner Koch <wk@gnupg.de> +Thu Mar 2 15:37:46 CET 2000 Werner Koch <wk@gnupg.de> - * misc.c (mpi_read_opaque): Fixed double counting. + * pubkey-enc.c (get_it): Print a note about unknown cipher algos. - * seckey-cert.c (do_check): Removed buffer and the unmotivated free - on it. + * g10.c (opts): Add a note to the help listing about the man page + and removed some options from the help listing. - * pubkey-enc.c (pk_decrypt): New wrapper for the gcry_ function. - * seckey-cert.c (pk_check_secret_key): Likewise. - * encode.c (pk_encrypt): Likewise. + * keyedit.c (print_and_check_one_sig): Use a new function to truncate + the output of the user ID. Suggested by Jan-Benedict Glaw. - * parse-packet.c (parse_key): Fixed case of unencrypted secret keys. +Wed Feb 23 10:07:57 CET 2000 Werner Koch <wk@gnupg.de> -Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de> + * helptext.c: typo fix. - * misc.c (mpi_print): Use gcry_mpi_aprint. - (pubkey_nbits): Kludge to use the gcry_pk_ API. +Thu Feb 17 13:39:32 CET 2000 Werner Koch <wk@gnupg.de> - * seskey.c (encode_session_key): Replaced mpi_set_buffer by *_scan. - (do_encode_md): Ditto. - (encode_md_value): Ditto. - * seckey-cert.c (protect_secret_key): Ditto. - * comment.c (make_mpi_comment_node): Replaced mpi_get_buffer by _print. - * pubkey-enc.c (get_it): Ditto. - * sig-check.c (do_signature_check): Ditto. + * revoke.c: Removed a bunch of commented code. -Fri Dec 31 12:48:31 CET 1999 Werner Koch <wk@gnupg.de> + * 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. - * keyid.c (do_fingerprint_md): Replaced mpi_get_buffer by gcry_mpi_print. - (v3_keyid): New. - (keyid_from_sk): And use it here. - (keyid_from_pk): Ditto. - (fingerprint_from_sk): Ditto. - (fingerprint_from_pk): Ditto. +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> - * misc.c (mpi_print): New. + * g10.c (g10_exit): Update the random seed_file. + (main): Set the random seed file. New option --no-random-seed-file. - * misc.c (checksum_mpi): Now uses gcry_mpi_print to get the data. +Thu Feb 10 17:39:44 CET 2000 Werner Koch <wk@gnupg.de> - * seckey-cert.c (do_check): Replaced mpi_read_from_buffer. + * 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. -Wed Dec 8 21:58:32 CET 1999 Werner Koch <wk@gnupg.de> + * 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. - * seckey-cert.c: Removed obsolete mpi_*_protect_flag. - * parse-packet.c: Ditto. +Thu Dec 16 10:07:58 CET 1999 Werner Koch <wk@gnupg.de> - * misc.c (mpi_read): Removed the secure argumet becuase it is - never used. Changed all Callers. - (mpi_read_opaque): New. - (mpi_write_opaque): New. - * parse-packet.c (parse_key): Use the opaque method also for - v3 keys. - * build-packet.c (do_secret_key): Likewise. + * mainproc.c (print_failed_pkenc): Fix for unknown algorithm. + Found by fygrave@epr0.org. - * g10.c (main): Check libgcrypt version. +Thu Dec 9 10:31:05 CET 1999 Werner Koch <wk@gnupg.de> - * packet.h: replaced inclusion of mpi.h by a plain typeedef of the - gcry_mpi structure and removed all inclusions of "mpi.h" in all - sources. + * 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. - * g10.c (main): Changed the default homedir to "~/.gnupg-test" so - that we don't mess up with the stable version. + * 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. - * misc.c (mpi_write): New. - (mpi_write): New. + * keygen.c (generate_user_id): Use m_alloc_clear() here. We should + better use an allocation function specific to the user_id packet. - * misc.c (checksum_u16_nobug): Removed. - (checksum_mpi_counted_nbits): Renamed to ... - (checksum_mpi): ... this to superseed the old one. Changed all - callers. This is because we do not emulate the old gpg bug anymore. - * g10.c (oEmuChecksumBug): Removed. + * keygen.c (keygen_add_std_prefs): Changed symmetric preferences + to include Blowfish again. This is due to it's better speed compared + to CAST5. -Fri Nov 19 17:15:20 CET 1999 Werner Koch <wk@gnupg.de> + * g10.c (strusage): Print the home directory. - * g10.c (register_extension): New... - (main): Use it here instead of register_cipher_extesnion. - (strusage): s/strusage/my_strusage/ . Made static. - (main): Use set_strusage(). + * armor.c (armor_filter): Take action on the cancel control msg. + * filter.h (armor_filter_context_t): Add cancel flag. - * tdbdump.c (HEXTOBIN): Changed the name of the argument, so that - traditional cpp don't mess up the macros. Suggested by Jos Backus. +Mon Nov 29 21:52:11 CET 1999 Werner Koch <wk@gnupg.de> - * armor.c (parse_header_line): Stop parsing on a only WS line too. - Suggested by Aric Cyr. + * g10.c: New option --fast-list-mode .. + * keylist.c (list_keyblock): .. and implemented. + * mainproc.c (list_node): Ditto. -Mon Nov 15 21:36:02 CET 1999 Werner Koch <wk@gnupg.de> + * import.c (mark_non_selfsigned_uids_valid): Fixed the case that there + is a uid without any packet following. - * misc.c (pull_in_libs): Removed. +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. -Sat Nov 13 17:44:23 CET 1999 Werner Koch <wk@gnupg.de> + * 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. - * misc.c (pull_in_libs): Removed pull in of g10c. + * 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. - * misc.c (map_gcry_rc): Removed here and chnaged all users. +Fri Nov 12 20:33:19 CET 1999 Werner Koch <wk@gnupg.de> - * getkey.c: Replaced check_pubkey_algo by openpgp_pk_test_algo. - * import.c (delete_inv_parts): Ditto. - * pkclist.c: Ditto. - * skclist.c: Ditto. - * pubkey-enc.c: Ditto. + * 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. - * g10.c (main): Replaced the function to diable PK algos. + * getkey.c (get_user_id_string_native): New and ... + * encode.c (write_pubkey_enc_from_list): ... use it here. - * g10.c (main): Replaced get_random_bits by gcry_random_bytes. - * seskey.c (encode_session_key): Likewise. - (make_session_key): Renamed randomize_buffer to gcry_randomize - and use the GCRY_xxx_RANDOM constants. - * cipher.c (write_header): Ditto. - * passphrase.c (hash_passphrase): Ditto. - * seckey-cert.c (protect_secret_key): Ditto. + * pubring.asc: Updated. - * getkey.c (find_by_name): Replaced rmd160_hash_buffer - by gcry_md_hash_buffer. + * 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. - * trustdb.c (print_uid_from_keyblock): Ditto. - (make_uid_records): Ditto. - * skclist.c (build_sk_list): Removed the test on faked RNGs. - (is_insecure): Removed. - * g10.c (--quick-random): Removed this option. +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> - * Replaced all PUBKEY_ALGO_xxx by GCRY_PK_xxxx. + * ringedit.c (enum_keyblocks): The last fix way really stupid; + reverted and set rt to Unknown. - * misc.c (pubkey_algo_npkey): New as a wrapper around the gcry fucntion. - (pubkey_algo_nskey): Ditto. - (pubkey_algo_nsig): Ditto. - (pubkey_algo_nenc): Ditto. +Fri Oct 8 20:32:01 CEST 1999 Werner Koch <wk@gnupg.de> -Tue Oct 26 20:03:44 CEST 1999 Werner Koch <wk@gnupg.de> + * ringedit.c (enum_keyblocks): Zero the entire kbpos out on open. - * Makefile.am (basicdefs.h): Added. - (install-data-local): Removed the handling for historic gpgm. + * g10.c (oEntropyDLL): Removed option. + (main): Made the warning on development versions more verbose. -Tue Oct 26 14:10:21 CEST 1999 Werner Koch <wk@gnupg.de> + * g10.c (oHonorHttpProxy): New option. + * hkp.c (hkp_ask_import,hkp_export): Implement this option. + * options.skel: Enable this option for new installations - * misc.c (openpgp_cipher_test_algo): New. - (openpgp_pk_test_algo): New. - (openpgp_md_test_algo): New. +Mon Oct 4 21:23:04 CEST 1999 Werner Koch <wk@gnupg.de> - * g10.c (build_list): Changed to use the new functions from libgcrypt. + * 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. - * ringedit.c (enum_keyblocks): Set .rt to 0 on open. + * 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. - * 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. - - (clearsign_file): Use gcry_md_test_algo() and gcry_md_algo_name(). + * armor.c (armor_filter): Set a flag if no OpenPGP data has been found. + * verify.c (verify_signatures): Add an error helptext. - * openfile.c (make_outfile_name): Use case-insenstive compare for - DOS systems. Add ".pgp" to the list of know extensions. - (open_outfile): For DOS systems try to replace the suffix instead of - appending it. - - * encr-data.c (decrypt_data): Reset error on a weak key. - - * cipher.c: Replaced the cipher and digest functions by the gcry_ ones. - * seckey-cert.c: Ditto. - * seskey.c: Ditto. - * g10.c (print_mds): Replaced digst functions with the new gcry_ ones. - * keyid.c: Ditto. - * mainproc.c: Ditto. - * passphrase.c: Ditto. - * sig-check.c: Ditto. - * sign.c: Ditto. - - * pkclist.c (do_edit_ownertrust): Made the answer string const. - - * basicdefs.h: New. Move some defs and decl to this header. +Thu Sep 23 19:24:30 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> * openfile.c (open_outfile): Fixed the 8dot3 handling. @@ -236,17 +715,33 @@ Tue Oct 26 14:10:21 CEST 1999 Werner Koch <wk@gnupg.de> * trustdb.c (print_user_id,check_uidsigs): Ditto. * revoke.c (gen_revoke,ask_revoke_sig): Ditto. -Sat Sep 18 12:16:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> +Thu Sep 23 09:52:58 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> - * filter.h: Changed cipher handle types to the the GCRY_xxx ones. - replaces include cipher by system header include gcrypt.h. - * cipher.c: replaced the cipher functions by the gcry_ ones. - Ditto for the md functions. + * 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 - * misc.c (map_gcry_rc): New. +Wed Sep 22 10:14:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> -Fri Sep 17 12:56:42 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 ;-) @@ -256,16 +751,13 @@ Fri Sep 17 12:56:42 CEST 1999 Werner Koch <wk@isil.d.shuttle.de> 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 diff --git a/g10/Makefile.am b/g10/Makefile.am index 55d0ed222..6b95ac3a5 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -6,10 +6,11 @@ OMIT_DEPENDENCIES = zlib.h zconf.h LDFLAGS = -static @LDFLAGS@ @DYNLINK_LDFLAGS@ # we need to add libutil.la a second time because we have to resolve # gpg_log_ in some libjnlib modules. - very ugly - should be removed soon. -needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la ../jnlib/libjnlib.la ../util/libutil.la +needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la \ + ../jnlib/libjnlib.la ../util/libutil.la #noinst_PROGRAMS = gpgd -bin_PROGRAMS = gpg kbxutil +bin_PROGRAMS = gpg kbxutil common_source = \ build-packet.c \ diff --git a/g10/armor.c b/g10/armor.c index 0661d76ef..819c951dc 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -1,5 +1,5 @@ /* armor.c - Armor flter - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -37,6 +37,11 @@ #include "status.h" #include "i18n.h" +#ifdef HAVE_DOSISH_SYSTEM + #define LF "\r\n" +#else + #define LF "\n" +#endif #define MAX_LINELEN 20000 @@ -162,6 +167,7 @@ is_armored( const byte *buf ) 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: @@ -485,13 +491,26 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, 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( afx->buffer, afx->buffer_len, + 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 - * a CR, LF, Nul */ - afx->buffer[afx->buffer_len++] = '\r'; + * the removed [CR], LF and a Nul + * The reason for this complicated procedure is to keep at least + * the original tupe of lineending - handling of the removed + * 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; } @@ -819,7 +838,8 @@ armor_filter( void *opaque, int control, hashes &= 1|2|4|8; if( !hashes ) { hashes |= 4; /* default to MD 5 */ - afx->pgp2mode = 1; + if( opt.pgp2_workarounds ) + afx->pgp2mode = 1; } n=0; do { @@ -827,7 +847,7 @@ armor_filter( void *opaque, int control, buf[n++] = 0x90; /* old format, type 4, 1 length byte */ buf[n++] = 13; /* length */ buf[n++] = 3; /* version */ - buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/ + buf[n++] = afx->not_dash_escaped? 0:1; /* sigclass */ if( hashes & 1 ) { hashes &= ~1; buf[n++] = GCRY_MD_RMD160; @@ -874,7 +894,7 @@ armor_filter( void *opaque, int control, #endif *ret_len = n; } - else if( control == IOBUFCTRL_FLUSH ) { + else if( control == IOBUFCTRL_FLUSH && !afx->cancel ) { if( !afx->status ) { /* write the header line */ const char *s; @@ -882,10 +902,10 @@ armor_filter( void *opaque, int control, log_bug("afx->what=%d", afx->what); iobuf_writestr(a, "-----"); iobuf_writestr(a, head_strings[afx->what] ); - iobuf_writestr(a, "-----\n"); + iobuf_writestr(a, "-----" LF ); if( !opt.no_version ) iobuf_writestr(a, "Version: GnuPG v" VERSION " (" - PRINTABLE_OS_NAME ")\n"); + PRINTABLE_OS_NAME ")" LF ); /* write the comment string or a default one */ s = opt.comment_string ? opt.comment_string @@ -902,16 +922,17 @@ armor_filter( void *opaque, int control, else iobuf_put(a, *s ); } - iobuf_put(a, '\n' ); + iobuf_writestr(a, LF ); } if( afx->hdrlines ) iobuf_writestr(a, afx->hdrlines); - iobuf_put(a, '\n'); + iobuf_writestr(a, LF ); afx->status++; afx->idx = 0; afx->idx2 = 0; afx->crc = CRCINIT; + } crc = afx->crc; idx = afx->idx; @@ -936,7 +957,7 @@ armor_filter( void *opaque, int control, c = bintoasc[radbuf[2]&077]; iobuf_put(a, c); if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */ - iobuf_put(a, '\n'); + iobuf_writestr(a, LF ); idx2=0; } } @@ -951,8 +972,13 @@ armor_filter( void *opaque, int control, if( !is_initialized ) initialize(); } + else if( control == IOBUFCTRL_CANCEL ) { + afx->cancel = 1; + } else if( control == IOBUFCTRL_FREE ) { - if( afx->status ) { /* pad, write cecksum, and bottom line */ + if( afx->cancel ) + ; + else if( afx->status ) { /* pad, write cecksum, and bottom line */ crc = afx->crc; idx = afx->idx; idx2 = afx->idx2; @@ -975,13 +1001,13 @@ armor_filter( void *opaque, int control, iobuf_put(a, '='); } if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */ - iobuf_put(a, '\n'); + iobuf_writestr(a, LF ); idx2=0; } } /* may need a linefeed */ if( idx2 ) - iobuf_put(a, '\n'); + iobuf_writestr(a, LF ); /* write the CRC */ iobuf_put(a, '='); radbuf[0] = crc >>16; @@ -995,16 +1021,17 @@ armor_filter( void *opaque, int control, iobuf_put(a, c); c = bintoasc[radbuf[2]&077]; iobuf_put(a, c); - iobuf_put(a, '\n'); + 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, "-----\n"); + 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 ) diff --git a/g10/build-packet.c b/g10/build-packet.c index 84912ac05..878158917 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -1,5 +1,5 @@ /* build-packet.c - assemble packets and write them - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,11 +24,11 @@ #include <string.h> #include <assert.h> +#include <gcrypt.h> #include "packet.h" #include "errors.h" #include "iobuf.h" #include "util.h" -#include <gcrypt.h> #include "options.h" #include "main.h" @@ -43,6 +43,7 @@ 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_mdc( IOBUF out, PKT_mdc *mdc ); 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 ); @@ -66,25 +67,31 @@ 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( pkt->pkttype ) { - case PKT_OLD_COMMENT: pkt->pkttype = PKT_COMMENT; break; + 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->photo ) + pkttype = PKT_PHOTO_ID; + break; default: break; } - if( new_ctb || pkt->pkttype > 15 ) /* new format */ - ctb = 0xc0 | (pkt->pkttype & 0x3f); + if( new_ctb || pkttype > 15 ) /* new format */ + ctb = 0xc0 | (pkttype & 0x3f); else - ctb = 0x80 | ((pkt->pkttype & 15)<<2); - switch( pkt->pkttype ) { + ctb = 0x80 | ((pkttype & 15)<<2); + switch( pkttype ) { + case PKT_PHOTO_ID: case PKT_USER_ID: rc = do_user_id( out, ctb, pkt->pkt.user_id ); break; @@ -114,6 +121,9 @@ build_packet( IOBUF out, PACKET *pkt ) case PKT_ENCRYPTED_MDC: rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted ); break; + case PKT_MDC: + rc = do_mdc( out, pkt->pkt.mdc ); + break; case PKT_COMPRESSED: rc = do_compressed( out, ctb, pkt->pkt.compressed ); break; @@ -148,6 +158,7 @@ calc_packet_length( PACKET *pkt ) n = calc_plaintext( pkt->pkt.plaintext ); new_ctb = pkt->pkt.plaintext->new_ctb; break; + case PKT_PHOTO_ID: case PKT_USER_ID: case PKT_COMMENT: case PKT_PUBLIC_KEY: @@ -172,11 +183,11 @@ static void write_fake_data( IOBUF out, MPI a ) { if( a ) { - size_t i; + int i; void *p; - p = gcry_mpi_get_opaque( a, &i ); - iobuf_write( out, p, (i+7)/8 ); + p = mpi_get_opaque( a, &i ); + iobuf_write( out, p, i ); } } @@ -195,11 +206,20 @@ do_comment( IOBUF out, int ctb, PKT_comment *rem ) static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) { - write_header(out, ctb, uid->len); - uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */ - /* ... and it does only work when used with a temp iobuf */ - if( iobuf_write( out, uid->name, uid->len ) ) - return GPGERR_WRITE_FILE; + if( uid->photo ) { + write_header(out, ctb, uid->photolen); + uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */ + /* ... and it does only work when used with a temp iobuf */ + if( iobuf_write( out, uid->photo, uid->photolen ) ) + return GPGERR_WRITE_FILE; + } + else { + write_header(out, ctb, uid->len); + uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */ + /* ... and it does only work when used with a temp iobuf */ + if( iobuf_write( out, uid->name, uid->len ) ) + return GPGERR_WRITE_FILE; + } return 0; } @@ -358,19 +378,30 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) else { iobuf_put(a, 0xff ); iobuf_put(a, sk->protect.algo ); - iobuf_put(a, sk->protect.s2k.mode ); - iobuf_put(a, sk->protect.s2k.hash_algo ); + if( sk->protect.s2k.mode >= 1000 ) { + 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 ); - iobuf_write(a, sk->protect.iv, sk->protect.ivlen ); + if( sk->protect.s2k.mode != 1001 ) + iobuf_write(a, sk->protect.iv, sk->protect.ivlen ); } } else iobuf_put(a, 0 ); - if( sk->is_protected && sk->version >= 4 ) { + if( sk->protect.s2k.mode == 1001 ) + ; + else if( sk->is_protected && sk->version >= 4 ) { byte *p; size_t n; assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) ); @@ -379,7 +410,7 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) } else { for( ; i < nskey; i++ ) - mpi_write_opaque(a, sk->skey[i] ); + mpi_write(a, sk->skey[i] ); write_16(a, sk->csum ); } @@ -527,13 +558,24 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed ) n = ed->len ? (ed->len + 10) : 0; write_header(out, ctb, n ); iobuf_put(out, 1 ); /* version */ - iobuf_put(out, ed->mdc_method ); /* This is all. The caller has to write the real data */ return rc; } + +static int +do_mdc( IOBUF out, PKT_mdc *mdc ) +{ + /* This packet requires a fixed header encoding */ + iobuf_put( out, 0xd3 ); /* packet ID and 1 byte length */ + iobuf_put( out, 0x14 ); /* length = 20 */ + if( iobuf_write( out, mdc->hash, sizeof(mdc->hash) ) ) + return GPGERR_WRITE_FILE; + return 0; +} + static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd ) { @@ -623,7 +665,6 @@ void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ) { - byte *data; size_t hlen, dlen, nlen; int found=0; @@ -659,6 +700,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, case SIGSUBPKT_KEY_EXPIRE: case SIGSUBPKT_NOTATION: case SIGSUBPKT_POLICY: + case SIGSUBPKT_REVOC_REASON: hashed = 1; break; default: hashed = 0; break; } diff --git a/g10/cipher.c b/g10/cipher.c index 8fc0d3815..cad6ff664 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -1,5 +1,5 @@ /* cipher.c - En-/De-ciphering filter - * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -33,6 +33,7 @@ #include "packet.h" #include "options.h" #include "main.h" +#include "status.h" #define MIN_PARTIAL_SIZE 512 @@ -44,10 +45,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) PACKET pkt; PKT_encrypted ed; byte temp[18]; - int blocksize; - unsigned nprefix; - int use_mdc = opt.force_mdc; + unsigned int blocksize; + unsigned int nprefix; int rc; + int use_mdc = opt.force_mdc; + + blocksize = gcry_cipher_get_algo_blklen( cfx->dek->algo ); + if( blocksize < 8 || blocksize > 16 ) + log_fatal("unsupported blocksize %u\n", blocksize ); + if( blocksize != 8 ) + use_mdc = 1; /* enable it for all modern ciphers */ + if( opt.rfc2440 ) + use_mdc = 0; /* override - rfc2440 does not know about MDC */ memset( &ed, 0, sizeof ed ); ed.len = cfx->datalen; @@ -55,18 +64,16 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) if( use_mdc ) { ed.mdc_method = GCRY_MD_SHA1; cfx->mdc_hash = gcry_md_open( GCRY_MD_SHA1, 0 ); - /*should we check the function works, or is it better to provide - a flag which makes the function die itself ?? FIXME */ - /*md_start_debug( cfx->mdc_hash, "mdccreat" );*/ + if( !cfx->mdc_hash ) + BUG(); + if ( DBG_HASHING ) + gcry_md_start_debug( cfx->mdc_hash, "creatmdc" ); } init_packet( &pkt ); pkt.pkttype = use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; pkt.pkt.encrypted = &ed; if( build_packet( a, &pkt )) log_bug("build_packet(ENCR_DATA) failed\n"); - blocksize = gcry_cipher_get_algo_blklen( cfx->dek->algo ); - if( blocksize < 8 || blocksize > 16 ) - log_fatal("unsupported blocksize %d\n", blocksize ); nprefix = blocksize; gcry_randomize( temp, nprefix, GCRY_STRONG_RANDOM ); temp[nprefix] = temp[nprefix-2]; @@ -75,7 +82,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) if( !(cfx->cipher_hd = gcry_cipher_open( cfx->dek->algo, GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE - | (cfx->dek->algo >= 100 ? + | ((use_mdc || cfx->dek->algo >= 100) ? 0 : GCRY_CIPHER_ENABLE_SYNC))) ) { /* we should never get an error here cause we already checked, that @@ -83,6 +90,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) BUG(); } + /* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/ rc = gcry_cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen ); if( !rc ) @@ -99,6 +107,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) log_fatal("encrypt failed: %s\n", gcry_strerror(rc) ); iobuf_write(a, temp, nprefix+2); cfx->header=1; + } @@ -120,6 +129,7 @@ cipher_filter( void *opaque, int control, else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ assert(a); if( !cfx->header ) { + write_status( STATUS_BEGIN_ENCRYPTION ); write_header( cfx, a ); } if( cfx->mdc_hash ) @@ -134,15 +144,26 @@ cipher_filter( void *opaque, int control, if( cfx->mdc_hash ) { byte *hash; int hashlen = gcry_md_get_algo_dlen( gcry_md_get_algo( cfx->mdc_hash ) ); + byte temp[22]; + + assert( hashlen == 20 ); + /* we must hash the prefix of the MDC packet here */ + temp[0] = 0xd3; + temp[1] = 0x14; + gcry_md_putc( cfx->mdc_hash, temp[0] ); + gcry_md_putc( cfx->mdc_hash, temp[1] ); + hash = gcry_md_read( cfx->mdc_hash, 0 ); - rc = gcry_cipher_encrypt( cfx->cipher_hd, hash, hashlen, NULL, 0 ); + memcpy(temp+2, hash, 20); + rc = gcry_cipher_encrypt( cfx->cipher_hd, temp, 22, NULL, 0 ); if( rc ) log_fatal("encrypt failed: %s\n", gcry_strerror(rc) ); - if( iobuf_write( a, hash, hashlen ) ) - rc = GPGERR_WRITE_FILE; gcry_md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL; + if( iobuf_write( a, temp, 22 ) ) + log_error("writing MDC packet failed\n" ); } gcry_cipher_close(cfx->cipher_hd); + write_status( STATUS_END_ENCRYPTION ); } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "cipher_filter"; diff --git a/g10/comment.c b/g10/comment.c index fe80a1cf8..f0d884979 100644 --- a/g10/comment.c +++ b/g10/comment.c @@ -1,5 +1,5 @@ /* comment.c - write comment stuff - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * diff --git a/g10/compress.c b/g10/compress.c index 48335ba89..2666e9051 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -1,5 +1,5 @@ /* compress.c - compress filter - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -27,8 +27,8 @@ #include <errno.h> #include <zlib.h> -#include "util.h" #include <gcrypt.h> +#include "util.h" #include "packet.h" #include "filter.h" #include "options.h" diff --git a/g10/dearmor.c b/g10/dearmor.c index 1c0a15bc6..937961e7f 100644 --- a/g10/dearmor.c +++ b/g10/dearmor.c @@ -1,5 +1,5 @@ /* dearmor.c - Armor utility - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,9 +25,9 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "errors.h" #include "iobuf.h" -#include <gcrypt.h> #include "util.h" #include "filter.h" #include "packet.h" diff --git a/g10/decrypt.c b/g10/decrypt.c index e9f1d2b93..981275602 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -1,5 +1,5 @@ /* decrypt.c - verify signed data - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,12 +25,12 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "options.h" #include "packet.h" #include "errors.h" #include "iobuf.h" #include "keydb.h" -#include <gcrypt.h> #include "util.h" #include "main.h" #include "i18n.h" diff --git a/g10/delkey.c b/g10/delkey.c index c452567a8..0c64d41a3 100644 --- a/g10/delkey.c +++ b/g10/delkey.c @@ -1,5 +1,5 @@ /* delkey.c - delete keys - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -62,6 +62,7 @@ delete_key( const char *username, int secret ) : find_keyblock_byname( &kbpos, username ); if( rc ) { log_error(_("%s: user not found\n"), username ); + write_status_text( STATUS_DELETE_PROBLEM, "1" ); goto leave; } @@ -93,10 +94,12 @@ delete_key( const char *username, int secret ) "there is a secret key for this public key!\n")); log_info(_( "use option \"--delete-secret-key\" to delete it first.\n")); + write_status_text( STATUS_DELETE_PROBLEM, "2" ); rc = -1; } - else if( rc != GPGERR_NO_SECKEY ) + else if( rc != GPGERR_NO_SECKEY ) { log_error("%s: get secret key: %s\n", username, gpg_errstr(rc) ); + } else rc = 0; } diff --git a/g10/encode.c b/g10/encode.c index ed4b1df0f..6195b533c 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -1,5 +1,5 @@ /* encode.c - encode data - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -41,6 +41,7 @@ static int encode_simple( const char *filename, int mode ); static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ); + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. @@ -162,7 +163,7 @@ encode_simple( const char *filename, int mode ) } if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) { - iobuf_close(inp); + iobuf_cancel(inp); gcry_free(cfx.dek); gcry_free(s2k); return rc; @@ -510,7 +511,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ) * 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 pk_encrypt + * 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 @@ -525,7 +526,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ) log_error("pubkey_encrypt failed: %s\n", gpg_errstr(rc) ); else { if( opt.verbose ) { - char *ustr = get_user_id_string( enc->keyid ); + char *ustr = get_user_id_string_native( enc->keyid ); log_info(_("%s/%s encrypted for: %s\n"), gcry_pk_algo_name(enc->pubkey_algo), gcry_cipher_algo_name(dek->algo), ustr ); diff --git a/g10/encr-data.c b/g10/encr-data.c index 7c90829e2..17d43e9d6 100644 --- a/g10/encr-data.c +++ b/g10/encr-data.c @@ -1,5 +1,5 @@ /* encr-data.c - process an encrypted data packet - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,6 +23,7 @@ #include <stdlib.h> #include <string.h> #include <assert.h> + #include <gcrypt.h> #include "util.h" #include "packet.h" @@ -30,9 +31,9 @@ #include "i18n.h" -static int decode_filter( void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len); static int mdc_decode_filter( void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len); +static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); typedef struct { @@ -54,8 +55,8 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) byte *p; int rc=0, c, i; byte temp[32]; - int blocksize; - unsigned nprefix; + unsigned int blocksize; + unsigned int nprefix; memset( &dfx, 0, sizeof dfx ); if( gcry_cipher_test_algo( dek->algo ) ) { @@ -68,7 +69,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) log_info(_("%s encrypted data\n"), gcry_cipher_algo_name( dek->algo ) ); blocksize = gcry_cipher_get_algo_blklen( dek->algo ); - if( blocksize < 1 || blocksize > 16 ) + if( !blocksize || blocksize > 16 ) log_fatal("unsupported blocksize %u\n", blocksize ); nprefix = blocksize; if( ed->len && ed->len < (nprefix+2) ) @@ -76,13 +77,13 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) if( ed->mdc_method ) { dfx.mdc_hash = gcry_md_open( ed->mdc_method, 0 ); - if( !dfx.mdc_hash ) - BUG(); + if ( DBG_HASHING ) + gcry_md_start_debug(dfx.mdc_hash, "checkmdc"); } if( !(dfx.cipher_hd = gcry_cipher_open( dek->algo, GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE - | (dek->algo >= 100 ? + | ((ed->mdc_method || dek->algo >= 100)? 0 : GCRY_CIPHER_ENABLE_SYNC) )) ) { /* we should never get an error here cause we already checked, that @@ -122,8 +123,6 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) temp[i] = c; } gcry_cipher_decrypt( dfx.cipher_hd, temp, nprefix+2, NULL, 0 ); - if( dfx.mdc_hash ) - gcry_md_write( dfx.mdc_hash, temp, nprefix+2 ); gcry_cipher_sync( dfx.cipher_hd ); p = temp; /* log_hexdump( "prefix", temp, nprefix+2 ); */ @@ -131,22 +130,30 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) rc = GPGERR_BAD_KEY; goto leave; } + + if( dfx.mdc_hash ) + gcry_md_write( dfx.mdc_hash, temp, nprefix+2 ); + if( ed->mdc_method ) iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx ); else iobuf_push_filter( ed->buf, decode_filter, &dfx ); - proc_packets( procctx, ed->buf); + + proc_packets( procctx, ed->buf ); ed->buf = NULL; if( ed->mdc_method && dfx.eof_seen == 2 ) rc = GPGERR_INVALID_PACKET; else if( ed->mdc_method ) { /* check the mdc */ int datalen = gcry_md_get_algo_dlen( ed->mdc_method ); + + gcry_cipher_decrypt( dfx.cipher_hd, dfx.defer, 20, NULL, 0); if( datalen != 20 || memcmp(gcry_md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) ) rc = GPGERR_BAD_SIGN; - log_hexdump("MDC calculated:", gcry_md_read( dfx.mdc_hash, 0), datalen); - log_hexdump("MDC message :", dfx.defer, 20); + /*log_hexdump("MDC calculated:", md_read( dfx.mdc_hash, 0), datalen);*/ + /*log_hexdump("MDC message :", dfx.defer, 20);*/ } + leave: gcry_cipher_close(dfx.cipher_hd); gcry_md_close( dfx.mdc_hash ); @@ -154,6 +161,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) } + /* I think we should merge this with cipher_filter */ static int mdc_decode_filter( void *opaque, int control, IOBUF a, @@ -180,11 +188,14 @@ mdc_decode_filter( void *opaque, int control, IOBUF a, } if( n == 40 ) { /* we have enough stuff - flush the deferred stuff */ - /* (we have asserted that the buffer is large enough */ - if( !dfx->defer_filled ) /* the first time */ + /* (we have asserted that the buffer is large enough) */ + if( !dfx->defer_filled ) { /* the first time */ memcpy(buf, buf+20, 20 ); - else + n = 20; + } + else { memcpy(buf, dfx->defer, 20 ); + } /* now fill up */ for(; n < size; n++ ) { if( (c = iobuf_get(a)) == -1 ) @@ -198,7 +209,7 @@ mdc_decode_filter( void *opaque, int control, IOBUF a, dfx->defer_filled = 1; } else if( !dfx->defer_filled ) { /* eof seen buf empty defer */ - /* this is very bad because there is an incomplete hash */ + /* this is bad because there is an incomplete hash */ n -= 20; memcpy(buf, buf+20, n ); dfx->eof_seen = 2; /* eof with incomplete hash */ @@ -238,7 +249,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) n = iobuf_read( a, buf, size ); if( n == -1 ) n = 0; if( n ) - gcry_cipher_decrypt( fc->cipher_hd, buf, n, NULL, 0); + gcry_cipher_decrypt( fc->cipher_hd, buf, n, NULL, 0 ); else rc = -1; /* eof */ *ret_len = n; diff --git a/g10/export.c b/g10/export.c index df81babf4..2de9f91bf 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1,5 +1,5 @@ /* export.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,11 +25,11 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "options.h" #include "packet.h" #include "errors.h" #include "keydb.h" -#include <gcrypt.h> #include "util.h" #include "main.h" #include "i18n.h" @@ -71,6 +71,12 @@ 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, int onlyrfc ) { @@ -168,6 +174,16 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any ) } } + /* we can't apply GNU mode 1001 on an unprotected key */ + if( secret == 2 + && (node = find_kbnode( keyblock, PKT_SECRET_KEY )) + && !node->pkt->pkt.secret_key->is_protected ) + { + log_info(_("key %08lX: not protected - skipped\n"), + (ulong)keyid_from_sk( node->pkt->pkt.secret_key, NULL) ); + continue; + } + /* and write it */ for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) { /* don't export any comment packets but those in the @@ -183,7 +199,20 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any ) continue; /* not exportable */ } - if( (rc = build_packet( out, node->pkt )) ) { + 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 { + rc = build_packet( out, node->pkt ); + } + + if( rc ) { log_error("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_errstr(rc) ); rc = GPGERR_WRITE_FILE; diff --git a/g10/filter.h b/g10/filter.h index 389026d2c..a29d2aa29 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -1,5 +1,5 @@ /* filter.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -26,7 +26,6 @@ #include "iobuf.h" - typedef struct { GCRY_MD_HD md; /* catch all */ GCRY_MD_HD md2; /* if we want to calculate an alternate hash */ @@ -39,6 +38,9 @@ typedef struct { 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 */ @@ -60,6 +62,7 @@ typedef struct { 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; @@ -83,6 +86,8 @@ typedef struct { GCRY_CIPHER_HD cipher_hd; int header; GCRY_MD_HD mdc_hash; + byte enchash[20]; + int create_mdc; /* flag will be set by the cipher filter */ } cipher_filter_context_t; @@ -93,7 +98,6 @@ typedef struct { } encrypt_filter_context_t; - typedef struct { byte *buffer; /* malloced buffer */ unsigned buffer_size; /* and size of this buffer */ @@ -108,8 +112,6 @@ typedef struct { } 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 ); diff --git a/g10/free-packet.c b/g10/free-packet.c index 173f8d812..1d9aacff6 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -1,5 +1,5 @@ /* free-packet.c - cleanup stuff for packets - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,10 +24,10 @@ #include <string.h> #include <assert.h> +#include <gcrypt.h> #include "packet.h" #include "iobuf.h" #include "util.h" -#include <gcrypt.h> #include "options.h" #include "main.h" @@ -219,6 +219,8 @@ free_comment( PKT_comment *rem ) void free_user_id( PKT_user_id *uid ) { + if( uid->photo ) + gcry_free( uid->photo ); gcry_free(uid); } diff --git a/g10/getkey.c b/g10/getkey.c index d0b9cc1dd..e9b4a231a 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1,5 +1,5 @@ /* getkey.c - Get a key from the database - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,9 +24,10 @@ #include <string.h> #include <assert.h> #include <ctype.h> -#include <gcrypt.h> + #include "util.h" #include "packet.h" +#include <gcrypt.h> #include "iobuf.h" #include "keydb.h" #include "options.h" @@ -45,7 +46,11 @@ * 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). */ + * 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, @@ -154,6 +159,7 @@ static int uid_cache_entries; /* number of entries in uid cache */ static char* prepare_word_match( const byte *name ); static int lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_kb ); static int lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_kb ); +static u32 subkeys_expiretime( KBNODE node, u32 *mainkid ); #if 0 @@ -696,6 +702,8 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, STRLIST r; GETKEY_CTX ctx; + if( retctx ) /* reset the returned context in case of error */ + *retctx = NULL; assert( !pk ^ !sk ); /* build the search context */ @@ -941,7 +949,7 @@ get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk, if( !sk ) { /* Performance Hint: key_byname should not need a sk here */ - sk = gcry_xcalloc_secure( 1, sizeof *sk ); + sk = gcry_xcalloc_secure( 1, sizeof *sk ); rc = key_byname( retctx, names, NULL, sk, ret_keyblock ); free_secret_key( sk ); } @@ -959,7 +967,7 @@ get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ) if( !sk ) { /* Performance Hint: lookup_read should not need a pk in this case */ - sk = gcry_xcalloc_secure( 1, sizeof *sk ); + sk = gcry_xcalloc_secure( 1, sizeof *sk ); rc = lookup_sk( ctx, sk, ret_keyblock ); free_secret_key( sk ); } @@ -1150,7 +1158,7 @@ merge_one_pk_and_selfsig( KBNODE keyblock, KBNODE knode, k = find_kbnode( keyblock, PKT_PUBLIC_KEY ); if( !k ) BUG(); /* keyblock without primary key!!! */ - keyid_from_pk( knode->pkt->pkt.public_key, kid ); + keyid_from_pk( k->pkt->pkt.public_key, kid ); } else keyid_from_pk( pk, kid ); @@ -1208,6 +1216,10 @@ merge_keys_and_selfsig( KBNODE keyblock ) 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 */ + pk->expiredate = subkeys_expiretime( k, kid ); + } sigdate = 0; } else if( k->pkt->pkttype == PKT_SECRET_KEY @@ -1222,8 +1234,11 @@ merge_keys_and_selfsig( KBNODE keyblock ) 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 @@ -1279,9 +1294,16 @@ find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name, u32 aki[2]; keyid_from_pk( kk->pkt->pkt.public_key, aki ); cache_user_id( k->pkt->pkt.user_id, aki ); - gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, - k->pkt->pkt.user_id->name, - k->pkt->pkt.user_id->len ); + if( k->pkt->pkt.user_id->photo ) { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, + k->pkt->pkt.user_id->photo, + k->pkt->pkt.user_id->photolen ); + } + else { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, + k->pkt->pkt.user_id->name, + k->pkt->pkt.user_id->len ); + } *use_namehash = 1; return kk; } @@ -1516,6 +1538,56 @@ find_by_fpr_sk( KBNODE keyblock, PKT_secret_key *sk, } +/**************** + * Return the expiretime of a subkey. + */ +static u32 +subkeys_expiretime( KBNODE node, u32 *mainkid ) +{ + KBNODE k; + PKT_signature *sig; + u32 expires = 0, sigdate = 0; + + assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ); + for(k=node->next; k; k = k->next ) { + if( k->pkt->pkttype == PKT_SIGNATURE + && (sig=k->pkt->pkt.signature)->sig_class == 0x18 + && sig->keyid[0] == mainkid[0] + && sig->keyid[1] == mainkid[1] + && sig->version > 3 + && sig->timestamp > sigdate ) { + /* okay this is a key-binding which can be used. + * We use the latest self-signature. + * FIXME: We should only use this if the binding 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_data, SIGSUBPKT_KEY_EXPIRE, NULL ); + ed = p? node->pkt->pkt.public_key->timestamp + buffer_to_u32(p):0; + sigdate = sig->timestamp; + expires = ed; + } + else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + break; /* stop at the next subkey */ + } + + return expires; +} + + +/**************** + * Check whether the subkey has expired. Node must point to the subkey + */ +static int +has_expired( KBNODE node, u32 *mainkid, u32 cur_time ) +{ + u32 expires = subkeys_expiretime( node, mainkid ); + return expires && expires <= cur_time; +} + static void finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash, int use_namehash, int primary ) @@ -1534,6 +1606,10 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash, pk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) { /* if the usage is not correct, try to use a subkey */ KBNODE save_k = k; + u32 mainkid[2]; + u32 cur_time = make_timestamp(); + + keyid_from_pk( keyblock->pkt->pkt.public_key, mainkid ); k = NULL; /* kludge for pgp 5: which doesn't accept type 20: @@ -1545,7 +1621,8 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash, == GCRY_PK_ELG_E && !openpgp_pk_test_algo( k->pkt->pkt.public_key->pubkey_algo, - pk->pubkey_usage ) ) + pk->pubkey_usage ) + && !has_expired(k, mainkid, cur_time) ) break; } } @@ -1555,7 +1632,10 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash, if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY && !openpgp_pk_test_algo( k->pkt->pkt.public_key->pubkey_algo, - pk->pubkey_usage ) ) + pk->pubkey_usage ) + && ( pk->pubkey_usage != GCRY_PK_USAGE_ENCR + || !has_expired( k, mainkid, cur_time ) ) + ) break; } } @@ -1887,6 +1967,18 @@ get_user_id_string( u32 *keyid ) return p; } + +char* +get_user_id_string_native( u32 *keyid ) +{ + char *p = get_user_id_string( keyid ); + char *p2 = utf8_to_native( p, strlen(p) ); + + gcry_free(p); + return p2; +} + + char* get_long_user_id_string( u32 *keyid ) { @@ -1914,6 +2006,7 @@ 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 ) @@ -1924,9 +2017,8 @@ get_user_id( u32 *keyid, size_t *rn ) return p; } } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = gcry_xmalloc( 19 ); - memcpy(p, "[User id not found]", 19 ); - *rn = 19; + p = gcry_xstrdup( _("[User id not found]") ); + *rn = strlen(p); return p; } @@ -26,8 +26,8 @@ #include <ctype.h> #include <unistd.h> -#include <gcrypt.h> +#include <gcrypt.h> #include "packet.h" #include "iobuf.h" #include "util.h" @@ -77,6 +77,7 @@ enum cmd_and_opt_values { aNull = 0, aImport, aFastImport, aVerify, + aVerifyFiles, aListKeys, aListSigs, aListSecretKeys, @@ -85,12 +86,13 @@ enum cmd_and_opt_values { aNull = 0, aExport, aExportAll, aExportSecret, + aExportSecretSub, aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, - aPrintHMAC, aPrintMDs, + aPrintHMAC, aCheckTrustDB, aUpdateTrustDB, aFixTrustDB, @@ -130,6 +132,7 @@ enum cmd_and_opt_values { aNull = 0, oDigestAlgo, oCompressAlgo, oPasswdFD, + oCommandFD, oNoVerbose, oTrustDBName, oNoSecmemWarn, @@ -146,7 +149,6 @@ enum cmd_and_opt_values { aNull = 0, oCompressKeys, oCompressSigs, oAlwaysTrust, - oEmuChecksumBug, oRunAsShmCP, oSetFilename, oSetPolicyURL, @@ -164,6 +166,7 @@ enum cmd_and_opt_values { aNull = 0, oEscapeFrom, oLockOnce, oLockMultiple, + oLockNever, oKeyServer, oEncryptTo, oNoEncryptTo, @@ -175,7 +178,14 @@ enum cmd_and_opt_values { aNull = 0, oAllowNonSelfsignedUID, oNoLiteral, oSetFilesize, - oEntropyDLLName, + oHonorHttpProxy, + oFastListMode, + oListOnly, + oIgnoreTimeConflict, + oNoRandomSeedFile, + oNoAutoKeyRetrieve, + oEmu3DESS2KBug, /* will be removed in 1.1 */ + oEmuMDEncodeBug, aTest }; @@ -191,6 +201,7 @@ static ARGPARSE_OPTS opts[] = { { aStore, "store", 256, N_("store only")}, { aDecrypt, "decrypt", 256, N_("decrypt data (default)")}, { 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")}, @@ -210,6 +221,7 @@ static ARGPARSE_OPTS opts[] = { { aRecvKeys, "recv-keys" , 256, N_("import keys from a key server") }, { 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")}, @@ -266,12 +278,12 @@ static ARGPARSE_OPTS opts[] = { { oCharset, "charset" , 2, N_("|NAME|set terminal charset to NAME") }, { oOptions, "options" , 2, N_("read options from file")}, - { oDebug, "debug" ,4|16, N_("set debugging flags")}, - { oDebugAll, "debug-all" ,0, N_("enable full debugging")}, + { oDebug, "debug" ,4|16, "@"}, + { oDebugAll, "debug-all" ,0, "@"}, { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") }, - { oNoComment, "no-comment", 0, N_("do not write comment packets")}, - { oCompletesNeeded, "completes-needed", 1, N_("(default is 1)")}, - { oMarginalsNeeded, "marginals-needed", 1, N_("(default is 3)")}, + { oNoComment, "no-comment", 0, "@"}, + { oCompletesNeeded, "completes-needed", 1, "@"}, + { oMarginalsNeeded, "marginals-needed", 1, "@"}, { oMaxCertDepth, "max-cert-depth", 1, "@" }, { oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")}, { oRFC1991, "rfc1991", 0, N_("emulate the mode described in RFC1991")}, @@ -287,7 +299,11 @@ static ARGPARSE_OPTS opts[] = { { oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")}, { oNotation, "notation-data", 2, N_("|NAME=VALUE|use this notation data")}, - { 302, NULL, 0, N_("@\nExamples:\n\n" + { 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" @@ -301,6 +317,7 @@ static ARGPARSE_OPTS opts[] = { { aListTrustPath, "list-trust-path",0, "@"}, { oKOption, NULL, 0, "@"}, { oPasswdFD, "passphrase-fd",1, "@" }, + { oCommandFD, "command-fd",1, "@" }, { oNoVerbose, "no-verbose", 0, "@"}, { oTrustDBName, "trustdb-name", 2, "@" }, { oNoSecmemWarn, "no-secmem-warning", 0, "@" }, /* used only by regression tests */ @@ -331,6 +348,7 @@ static ARGPARSE_OPTS opts[] = { { oEscapeFrom, "escape-from-lines", 0, "@" }, { oLockOnce, "lock-once", 0, "@" }, { oLockMultiple, "lock-multiple", 0, "@" }, + { oLockNever, "lock-never", 0, "@" }, { oLoggerFD, "logger-fd",1, "@" }, { oUseEmbeddedFilename, "use-embedded-filename", 0, "@" }, { oUtf8Strings, "utf8-strings", 0, "@" }, @@ -341,7 +359,14 @@ static ARGPARSE_OPTS opts[] = { { oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", 0, "@" }, { oNoLiteral, "no-literal", 0, "@" }, { oSetFilesize, "set-filesize", 20, "@" }, - { oEntropyDLLName, "entropy-dll-name", 2, "@" }, + { oHonorHttpProxy,"honor-http-proxy", 0, "@" }, + { oFastListMode,"fast-list-mode", 0, "@" }, + { oListOnly, "list-only", 0, "@"}, + { oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" }, + { oNoRandomSeedFile, "no-random-seed-file", 0, "@" }, + { oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" }, + { oEmu3DESS2KBug, "emulate-3des-s2k-bug", 0, "@"}, + { oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"}, {0} }; @@ -351,8 +376,8 @@ int gpg_errors_seen = 0; static int utf8_strings = 0; static int maybe_setuid = 1; -static char *build_list( const char *text, const char * (*mapf)(int), - int (*chkf)(int) ); +static char *build_list( const char *text, + 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 ); @@ -360,13 +385,13 @@ static void print_mds( const char *fname, int algo, const char *key ); static void add_notation_data( const char *string ); static int check_policy_url( const char *s ); + static int our_pk_test_algo( int algo ) { return openpgp_pk_test_algo( algo, 0 ); } - static const char * my_strusage( int level ) { @@ -390,26 +415,29 @@ my_strusage( int level ) "default operation depends on the input data\n"); break; - case 31: p = _("\nSupported algorithms:\n"); break; - case 32: + case 31: p = "\nHome: "; break; + case 32: p = opt.homedir; break; + case 33: p = _("\nSupported algorithms:\n"); break; + case 34: if( !ciphers ) ciphers = build_list("Cipher: ", gcry_cipher_algo_name, openpgp_cipher_test_algo ); p = ciphers; break; - case 33: + case 35: if( !pubkeys ) pubkeys = build_list("Pubkey: ", gcry_pk_algo_name, our_pk_test_algo ); p = pubkeys; break; - case 34: + case 36: if( !digests ) digests = build_list("Hash: ", gcry_md_algo_name, openpgp_md_test_algo ); p = digests; break; + default: p = NULL; } return p; @@ -465,27 +493,6 @@ i18n_init(void) #endif } -static void -wrong_args( const char *text) -{ - fputs(_("usage: gpg [options] "),stderr); - fputs(text,stderr); - putc('\n',stderr); - gpg_exit(2); -} - - -static char * -make_username( const char *string ) -{ - char *p; - if( utf8_strings ) - p = native_to_utf8( string ); - else - p = gcry_xstrdup(string); - return p; -} - static void register_extension( const char *mainpgm, const char *fname ) @@ -510,15 +517,37 @@ register_extension( const char *mainpgm, const char *fname ) static void +wrong_args( const char *text) +{ + fputs(_("usage: gpg [options] "),stderr); + fputs(text,stderr); + putc('\n',stderr); + gpg_exit(2); +} + + +static char * +make_username( const char *string ) +{ + char *p; + if( utf8_strings ) + p = gcry_xstrdup(string); + else + p = native_to_utf8( string ); + return p; +} + + +static void set_debug(void) { - #if 0 - #warning memory debuggig not enabled + #if 0 + #warning memory debugging not enabled if( opt.debug & DBG_MEMORY_VALUE ) memory_debug_mode = 1; if( opt.debug & DBG_MEMSTAT_VALUE ) memory_stat_debug_mode = 1; - #endif + #endif if( opt.debug & DBG_MPI_VALUE ) gcry_control( GCRYCTL_SET_DEBUG_FLAGS, 2 ); @@ -579,6 +608,7 @@ main( int argc, char **argv ) 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; @@ -611,6 +641,7 @@ main( int argc, char **argv ) 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; @@ -622,7 +653,13 @@ main( int argc, char **argv ) opt.completes_needed = 1; opt.marginals_needed = 3; opt.max_cert_depth = 5; + opt.pgp2_workarounds = 1; + opt.auto_key_retrieve = 1; + #ifdef __MINGW32__ + opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" ); + #else opt.homedir = getenv("GNUPGHOME"); + #endif if( !opt.homedir || !*opt.homedir ) { #ifdef HAVE_DRIVE_LETTERS opt.homedir = "c:/gnupg-test"; @@ -679,7 +716,6 @@ main( int argc, char **argv ) if( default_config ) configname = make_filename(opt.homedir, "options", NULL ); - argc = orig_argc; argv = orig_argv; pargs.argc = &argc; @@ -721,13 +757,16 @@ main( int argc, char **argv ) case aListKeys: set_cmd( &cmd, aListKeys); break; case aListSigs: set_cmd( &cmd, aListSigs); break; case aExportSecret: set_cmd( &cmd, aExportSecret); break; + case aExportSecretSub: set_cmd( &cmd, aExportSecretSub); break; case aDeleteSecretKey: set_cmd( &cmd, aDeleteSecretKey); greeting=1; break; case aDeleteKey: set_cmd( &cmd, aDeleteKey); 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 aEncr: set_cmd( &cmd, aEncr); break; case aSign: set_cmd( &cmd, aSign ); break; case aKeygen: set_cmd( &cmd, aKeygen); greeting=1; break; @@ -738,11 +777,12 @@ main( int argc, char **argv ) case aClearsign: set_cmd( &cmd, aClearsign); break; case aGenRevoke: set_cmd( &cmd, aGenRevoke); 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 aPrintHMAC: set_cmd( &cmd, aPrintHMAC); break; case aPrintMDs: set_cmd( &cmd, aPrintMDs); break; + case aPrintHMAC: set_cmd( &cmd, aPrintHMAC); break; case aListTrustDB: set_cmd( &cmd, aListTrustDB); break; case aCheckTrustDB: set_cmd( &cmd, aCheckTrustDB); break; case aUpdateTrustDB: set_cmd( &cmd, aUpdateTrustDB); break; @@ -828,11 +868,14 @@ main( int argc, char **argv ) break; case oRFC1991: opt.rfc1991 = 1; + opt.rfc2440 = 0; opt.no_comment = 1; opt.escape_from = 1; break; case oOpenPGP: opt.rfc1991 = 0; + opt.rfc2440 = 1; + opt.pgp2_workarounds = 0; opt.escape_from = 0; opt.force_v3_sigs = 0; opt.compress_keys = 0; /* not mandated but we do it */ @@ -840,11 +883,13 @@ main( int argc, char **argv ) opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; opt.def_digest_algo = 0; - opt.def_compress_algo = 2; + opt.def_compress_algo = 1; opt.s2k_mode = 3; /* iterated+salted */ - opt.s2k_digest_algo = GCRY_MD_RMD160; - opt.s2k_cipher_algo = GCRY_CIPHER_BLOWFISH; + opt.s2k_digest_algo = GCRY_MD_SHA1; + opt.s2k_cipher_algo = GCRY_CIPHER_CAST5; break; + case oEmu3DESS2KBug: opt.emulate_bugs |= EMUBUG_3DESS2K; break; + case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break; case oCompressSigs: opt.compress_sigs = 1; break; case oRunAsShmCP: #ifndef USE_SHM_COPROCESSING @@ -880,6 +925,7 @@ main( int argc, char **argv ) break; case oCompress: opt.compress = pargs.r.ret_int; break; case oPasswdFD: pwfd = pargs.r.ret_int; break; + case oCommandFD: opt.command_fd = pargs.r.ret_int; break; case oCipherAlgo: def_cipher_string = gcry_xstrdup(pargs.r.ret_str); break; case oDigestAlgo: def_digest_string = gcry_xstrdup(pargs.r.ret_str); break; case oNoSecmemWarn: gcry_control( GCRYCTL_DISABLE_SECMEM_WARN ); break; @@ -891,6 +937,10 @@ main( int argc, char **argv ) case oNotDashEscaped: opt.not_dash_escaped = 1; break; case oEscapeFrom: opt.escape_from = 1; break; case oLockOnce: opt.lock_once = 1; break; + #if 0 + #warning no disable_dotlock() yet + case oLockNever: disable_dotlock(); break; + #endif case oLockMultiple: opt.lock_once = 0; break; case oKeyServer: opt.keyserver_name = pargs.r.ret_str; break; case oNotation: add_notation_data( pargs.r.ret_str ); break; @@ -908,22 +958,15 @@ main( int argc, char **argv ) &algo, sizeof algo ); } break; - case oAllowNonSelfsignedUID: - opt.allow_non_selfsigned_uid = 1; - break; - case oNoLiteral: - opt.no_literal = 1; - break; - case oSetFilesize: - opt.set_filesize = pargs.r.ret_ulong; - break; - - case oEntropyDLLName: - #ifdef USE_STATIC_RNDW32 - log_info("set dllname to `%s'\n", pargs.r.ret_str ); - rndw32_set_dll_name( pargs.r.ret_str ); - #endif - break; + case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break; + case oNoLiteral: opt.no_literal = 1; break; + case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break; + case oHonorHttpProxy: opt.honor_http_proxy = 1; break; + case oFastListMode: opt.fast_list_mode = 1; break; + case oListOnly: opt.list_only=1; break; + case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; + case oNoRandomSeedFile: use_random_seed = 0; break; + case oNoAutoKeyRetrieve: opt.auto_key_retrieve = 0; break; default : pargs.err = configfp? 1:2; break; } @@ -946,14 +989,12 @@ main( int argc, char **argv ) fprintf(stderr, "%s\n", strusage(15) ); } #ifdef IS_DEVELOPMENT_VERSION - if( !opt.batch ) - log_info("NOTE: this is a development version!\n"); - #endif - if( opt.force_mdc ) { - log_info("--force-mdc ignored because" - " the OpenPGP WG has not yet aggreed on MDCs\n"); - opt.force_mdc = 0; + 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.no_literal) { log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal"); if (opt.textmode) @@ -975,7 +1016,7 @@ main( int argc, char **argv ) * gpg_opt_homedir = opt.homedir; */ /* must do this after dropping setuid, because string_to... - * may try to load a module */ + * may try to load an module */ if( def_cipher_string ) { opt.def_cipher_algo = gcry_cipher_map_name(def_cipher_string); gcry_free(def_cipher_string); def_cipher_string = NULL; @@ -1025,8 +1066,19 @@ main( int argc, char **argv ) if( log_get_errorcount(0) ) gpg_exit(2); - if( !cmd && opt.fingerprint && !with_fpr ) + /* set the random seed file */ + if( use_random_seed ) { + char *p = make_filename(opt.homedir, "random_seed", NULL ); + #if 0 + #warning set_random_seed_file missing + set_random_seed_file(p); + #endif + gcry_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 ) { @@ -1077,8 +1129,8 @@ main( int argc, char **argv ) switch( cmd ) { case aPrimegen: case aPrintMD: - case aPrintHMAC: case aPrintMDs: + case aPrintHMAC: case aGenRandom: case aDeArmor: case aEnArmor: @@ -1167,6 +1219,11 @@ main( int argc, char **argv ) log_error("verify signatures failed: %s\n", gpg_errstr(rc) ); break; + case aVerifyFiles: + if( (rc = verify_files( argc, argv ) )) + log_error("verify files failed: %s\n", gpg_errstr(rc) ); + break; + case aDecrypt: if( argc > 1 ) wrong_args(_("--decrypt [filename]")); @@ -1225,16 +1282,28 @@ main( int argc, char **argv ) case aListSigs: opt.list_sigs = 1; case aListKeys: - /* fixme: we chnaged this in 1.0 */ - public_key_list( argc, argv ); + sl = NULL; + for( ; argc; argc--, argv++ ) + add_to_strlist2( &sl, *argv, utf8_strings ); + public_key_list( sl ); + free_strlist(sl); break; case aListSecretKeys: - secret_key_list( argc, argv ); + 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] */ - public_key_list( (argc && **argv)? 1:0, argv ); + 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"), @@ -1244,32 +1313,33 @@ main( int argc, char **argv ) /* add keyring (default keyrings are not registered in this * special case */ add_keyblock_resource( argv[1], 0, 0 ); - public_key_list( **argv?1:0, argv ); + 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 (interactive) */ - if( argc ) - wrong_args("--gen-key"); - generate_keypair(); + 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: case aImport: - if( !argc ) { - rc = import_keys( NULL, (cmd == aFastImport) ); - if( rc ) - log_error("import failed: %s\n", gpg_errstr(rc) ); - } - for( ; argc; argc--, argv++ ) { - rc = import_keys( *argv, (cmd == aFastImport) ); - if( rc ) - log_error("import from `%s' failed: %s\n", - *argv, gpg_errstr(rc) ); - } + import_keys( argc? argv:NULL, argc, (cmd == aFastImport) ); break; case aExport: @@ -1296,6 +1366,14 @@ main( int argc, char **argv ) 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"); @@ -1342,7 +1420,7 @@ main( int argc, char **argv ) mpi_print( stdout, factors[0], 1 ); /* print q */ } else if( mode == 4 && argc == 3 ) { - MPI g = mpi_new(8); + MPI g = mpi_alloc(1); mpi_print( stdout, generate_elg_prime( 0, atoi(argv[1]), atoi(argv[2]), g, NULL ), 1); @@ -1424,6 +1502,7 @@ main( int argc, char **argv ) } break; + case aPrintMDs: /* old option */ if( !argc ) print_mds(NULL,0,NULL); @@ -1461,11 +1540,9 @@ main( int argc, char **argv ) break; case aFixTrustDB: - log_error("this command is not yet implemented.\"\n"); + 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" ); - #warning removed the next line - export_as_kbxfile(); break; case aListTrustPath: @@ -1533,6 +1610,10 @@ main( int argc, char **argv ) void gpg_exit( int rc ) { + #if 0 + #warning no update_random_seed_file + update_random_seed_file(); + #endif if( opt.debug & DBG_MEMSTAT_VALUE ) { gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); gcry_control( GCRYCTL_DUMP_RANDOM_STATS ); @@ -1629,7 +1710,7 @@ print_mds( const char *fname, int algo, const char *key ) if( algo ) { if( fname ) fputs( pname, stdout ); - print_hex( gcry_md_read(md, algo), gcry_md_get_algo_dlen(algo) ); + print_hex(gcry_md_read(md, algo), gcry_md_get_algo_dlen(algo) ); } else { printf( "%s MD5 = ", fname?pname:"" ); diff --git a/g10/gpgd.c b/g10/gpgd.c index 99c91f6fc..8ca37d34a 100644 --- a/g10/gpgd.c +++ b/g10/gpgd.c @@ -1,4 +1,4 @@ -/* gpg.c - The GnuPG daemon (keyserver) +/* ggpd.c - The GnuPG daemon (keyserver) * Copyright (C) 1998 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -38,6 +38,7 @@ #include <sys/stat.h> #include "util.h" +#include "cipher.h" #include "options.h" #include "main.h" @@ -84,7 +85,7 @@ strusage( int level ) case 33: if( !pubkeys ) pubkeys = build_list("Supported pubkeys: ", pubkey_algo_to_string, - openpgp_pk_test_algo ); + check_pubkey_algo ); p = pubkeys; break; case 34: @@ -137,7 +138,7 @@ set_debug(void) if( opt.debug & DBG_MPI_VALUE ) mpi_debug_mode = 1; if( opt.debug & DBG_CIPHER_VALUE ) - gpgc_debug_mode = 1; + g10c_debug_mode = 1; if( opt.debug & DBG_IOBUF_VALUE ) iobuf_debug_mode = 1; } diff --git a/g10/helptext.c b/g10/helptext.c index e42902512..4a7a14fde 100644 --- a/g10/helptext.c +++ b/g10/helptext.c @@ -1,5 +1,5 @@ /* helptext.c - English help texts - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -224,6 +224,29 @@ static struct helptexts { const char *key; const char *help; } helptexts[] = { "file (which is shown in brackets) will be used." )}, +/* revoke.c (ask_revocation_reason) */ +{ "ask_revocation_reason.code", N_( + "You should specify a reason for the certification. Depending on the\n" + "context you have the ability to choose from this list:\n" + " \"Key has been compromised\"\n" + " Use this if you have a reason to believe that unauthorized persons\n" + " got access to your secret key.\n" + " \"Key is superseeded\"\n" + " Use this if you have replaced this key with a newer one.\n" + " \"Key is no longer used\"\n" + " Use this if you have retired this key.\n" + " \"User ID is no longer valid\"\n" + " Use this to state that the user ID should not longer be used;\n" + " this is normally used to mark an email address invalid.\n" +)}, + +/* revoke.c (ask_revocation_reason) */ +{ "ask_revocation_reason.text", N_( + "If you like, you can enter a text describing why you issue this\n" + "revocation certificate. Please keep this text concise.\n" + "An empty line ends the text.\n" +)}, + /* end of list */ { NULL, NULL } }; @@ -30,7 +30,6 @@ #include "util.h" #include "ttyio.h" #include "i18n.h" -#include <gcrypt.h> #include "options.h" #include "filter.h" #include "http.h" @@ -56,19 +55,24 @@ hkp_ask_import( u32 *keyid ) struct http_context hd; char *request; int rc; + unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0; if( !opt.keyserver_name ) return -1; - log_info("requesting key %08lX from %s ...\n", (ulong)keyid[1], + log_info(_("requesting key %08lX from %s ...\n"), (ulong)keyid[1], opt.keyserver_name ); request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 ); /* hkp does not accept the long keyid - we should really write a - * nicer one */ + * nicer one :-) + * FIXME: request binary mode - need to pass no_armor mode + * down to the import function. Marc told that there is such a + * binary mode ... how? + */ sprintf( request, "x-hkp://%s:11371/pks/lookup?op=get&search=0x%08lX", opt.keyserver_name, (ulong)keyid[1] ); - rc = http_open_document( &hd, request, 0 ); + rc = http_open_document( &hd, request, hflags ); if( rc ) { - log_info("can't get key from keyserver: %s\n", + log_info(_("can't get key from keyserver: %s\n"), rc == GPGERR_NETWORK? strerror(errno) : gpg_errstr(rc) ); } @@ -91,7 +95,7 @@ hkp_import( STRLIST users ) return -1; #else if( !opt.keyserver_name ) { - log_error("no keyserver known (use option --keyserver)\n"); + log_error(_("no keyserver known (use option --keyserver)\n")); return -1; } @@ -99,10 +103,15 @@ hkp_import( STRLIST users ) u32 kid[2]; int type = classify_user_id( users->d, kid, NULL, NULL, NULL ); if( type != 10 && type != 11 ) { - log_info("%s: not a valid key ID\n", users->d ); + log_info(_("%s: not a valid key ID\n"), users->d ); continue; } - hkp_ask_import( kid ); + /* because the function may use log_info in some situations, the + * errorcounter ist not increaed and the program will return + * with success - which is not good when this function is used. + */ + if( hkp_ask_import( kid ) ) + log_inc_errorcount(); } return 0; #endif @@ -121,9 +130,10 @@ hkp_export( STRLIST users ) struct http_context hd; char *request; unsigned int status; + unsigned int hflags = opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY : 0; if( !opt.keyserver_name ) { - log_error("no keyserver known (use option --keyserver)\n"); + log_error(_("no keyserver known (use option --keyserver)\n")); return -1; } @@ -143,9 +153,9 @@ hkp_export( STRLIST users ) request = gcry_xmalloc( strlen( opt.keyserver_name ) + 100 ); sprintf( request, "x-hkp://%s:11371/pks/add", opt.keyserver_name ); - rc = http_open( &hd, HTTP_REQ_POST, request , 0 ); + rc = http_open( &hd, HTTP_REQ_POST, request , hflags ); if( rc ) { - log_error("can't connect to `%s': %s\n", + log_error(_("can't connect to `%s': %s\n"), opt.keyserver_name, rc == GPGERR_NETWORK? strerror(errno) : gpg_errstr(rc) ); @@ -169,7 +179,7 @@ hkp_export( STRLIST users ) rc = http_wait_response( &hd, &status ); if( rc ) { - log_error("error sending to `%s': %s\n", + log_error(_("error sending to `%s': %s\n"), opt.keyserver_name, gpg_errstr(rc) ); } else { @@ -181,10 +191,10 @@ hkp_export( STRLIST users ) } #endif if( (status/100) == 2 ) - log_info("success sending to `%s' (status=%u)\n", + log_info(_("success sending to `%s' (status=%u)\n"), opt.keyserver_name, status ); else - log_error("failed sending to `%s': status=%u\n", + log_error(_("failed sending to `%s': status=%u\n"), opt.keyserver_name, status ); } http_close( &hd ); @@ -1,5 +1,5 @@ /* hkp.h - Horrowitz Keyserver Protocol - * Copyright (C) 1999 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * diff --git a/g10/import.c b/g10/import.c index 731351275..578082577 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1,5 +1,5 @@ /* import.c - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -38,6 +38,7 @@ static struct { + ulong count; ulong no_user_id; ulong imported; ulong imported_rsa; @@ -53,6 +54,7 @@ static struct { static int import( IOBUF inp, int fast, const char* fname ); +static void print_stats(void); static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ); static int import_one( const char *fname, KBNODE keyblock, int fast ); static int import_secret_one( const char *fname, KBNODE keyblock ); @@ -105,30 +107,51 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs, * Key revocation certificates have special handling. * */ -int -import_keys( const char *fname, int fast ) +void +import_keys( char **fnames, int nnames, int fast ) { - IOBUF inp = NULL; - int rc; + int i; - inp = iobuf_open(fname); - if( !fname ) - fname = "[stdin]"; - if( !inp ) { - log_error(_("can't open `%s': %s\n"), fname, strerror(errno) ); - return GPGERR_OPEN_FILE; - } + /* fixme: don't use static variables */ + memset( &stats, 0, sizeof( stats ) ); - rc = import( inp, fast, fname ); + if( !fnames && !nnames ) + nnames = 1; /* Ohh what a ugly hack to jump into the loop */ - iobuf_close(inp); - return rc; + for(i=0; i < nnames; i++ ) { + const char *fname = fnames? fnames[i] : NULL; + IOBUF inp = iobuf_open(fname); + if( !fname ) + fname = "[stdin]"; + if( !inp ) + log_error(_("can't open `%s': %s\n"), fname, strerror(errno) ); + else { + int rc = import( inp, fast, fname ); + iobuf_close(inp); + if( rc ) + log_error("import from `%s' failed: %s\n", fname, + gpg_errstr(rc) ); + } + if( !fname ) + break; + } + print_stats(); + if( !fast ) + sync_trustdb(); } int import_keys_stream( IOBUF inp, int fast ) { - return import( inp, fast, "[stream]" ); + int rc = 0; + + /* fixme: don't use static variables */ + memset( &stats, 0, sizeof( stats ) ); + rc = import( inp, fast, "[stream]" ); + print_stats(); + if( !fast ) + sync_trustdb(); + return rc; } static int @@ -137,10 +160,6 @@ import( IOBUF inp, int fast, const char* fname ) PACKET *pending_pkt = NULL; KBNODE keyblock; int rc = 0; - ulong count=0; - - /* fixme: don't use static variables */ - memset( &stats, 0, sizeof( stats ) ); getkey_disable_caches(); @@ -165,16 +184,23 @@ import( IOBUF inp, int fast, const char* fname ) release_kbnode(keyblock); if( rc ) break; - if( !(++count % 100) && !opt.quiet ) - log_info(_("%lu keys so far processed\n"), count ); + if( !(++stats.count % 100) && !opt.quiet ) + log_info(_("%lu keys so far processed\n"), stats.count ); } if( rc == -1 ) rc = 0; else if( rc && rc != GPGERR_INV_KEYRING ) log_error( _("error reading `%s': %s\n"), fname, gpg_errstr(rc)); + return rc; +} + + +static void +print_stats() +{ if( !opt.quiet ) { - log_info(_("Total number processed: %lu\n"), count ); + log_info(_("Total number processed: %lu\n"), stats.count ); if( stats.no_user_id ) log_info(_(" w/o user IDs: %lu\n"), stats.no_user_id ); if( stats.imported || stats.imported_rsa ) { @@ -202,9 +228,9 @@ import( IOBUF inp, int fast, const char* fname ) } if( is_status_enabled() ) { - char buf[12*16]; + char buf[12*20]; sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", - count, + stats.count, stats.no_user_id, stats.imported, stats.imported_rsa, @@ -218,8 +244,6 @@ import( IOBUF inp, int fast, const char* fname ) stats.secret_dups); write_status_text( STATUS_IMPORT_RES, buf ); } - - return rc; } @@ -354,8 +378,8 @@ import_one( const char *fname, KBNODE keyblock, int fast ) pubkey_letter( pk->pubkey_algo ), (ulong)keyid[1], datestr_from_pk(pk) ); if( uidnode ) - print_string( stderr, uidnode->pkt->pkt.user_id->name, - uidnode->pkt->pkt.user_id->len, 0 ); + print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name, + uidnode->pkt->pkt.user_id->len ); putc('\n', stderr); } if( !uidnode ) { @@ -545,8 +569,8 @@ import_secret_one( const char *fname, KBNODE keyblock ) pubkey_letter( sk->pubkey_algo ), (ulong)keyid[1], datestr_from_sk(sk) ); if( uidnode ) - print_string( stderr, uidnode->pkt->pkt.user_id->name, - uidnode->pkt->pkt.user_id->len, 0 ); + print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name, + uidnode->pkt->pkt.user_id->len ); putc('\n', stderr); } stats.secret_read++; @@ -678,6 +702,15 @@ import_revoke_cert( const char *fname, KBNODE node ) log_info( _("key %08lX: revocation certificate imported\n"), (ulong)keyid[1]); stats.n_revoc++; + if( clear_trust_checked_flag( pk ) ) { + /* seems that we have to insert the record first */ + rc = insert_trust_record( keyblock ); + if( rc ) + log_error("key %08lX: trustdb insert failed: %s\n", + (ulong)keyid[1], gpg_errstr(rc) ); + else + rc = clear_trust_checked_flag( pk ); + } leave: release_kbnode( keyblock ); @@ -764,7 +797,8 @@ mark_non_selfsigned_uids_valid( KBNODE keyblock, u32 *kid ) KBNODE node; for(node=keyblock->next; node; node = node->next ) { if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) ) { - if( node->next && node->next->pkt->pkttype == PKT_SIGNATURE ) { + if( (node->next && node->next->pkt->pkttype == PKT_SIGNATURE) + || !node->next ) { node->flag |= 1; log_info( _("key %08lX: accepted non self-signed user ID '"), (ulong)kid[1]); @@ -797,8 +831,8 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid ) if( opt.verbose ) { log_info( _("key %08lX: skipped user ID '"), (ulong)keyid[1]); - print_string( stderr, node->pkt->pkt.user_id->name, - node->pkt->pkt.user_id->len, 0 ); + 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 */ @@ -831,7 +865,7 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid ) } } else if( node->pkt->pkttype == PKT_SIGNATURE - && openpgp_pk_test_algo( node->pkt->pkt.signature->pubkey_algo, 0) + && openpgp_pk_test_algo( node->pkt->pkt.signature->pubkey_algo, 0 ) && node->pkt->pkt.signature->pubkey_algo != GCRY_PK_RSA ) delete_kbnode( node ); /* build_packet() can't handle this */ else if( node->pkt->pkttype == PKT_SIGNATURE diff --git a/g10/kbnode.c b/g10/kbnode.c index 79c1386aa..2c1e2ad3c 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -1,5 +1,5 @@ /* kbnode.c - keyblock node utility functions - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,8 +23,9 @@ #include <stdlib.h> #include <string.h> #include <assert.h> -#include "util.h" + #include <gcrypt.h> +#include "util.h" #include "packet.h" #include "keydb.h" @@ -165,7 +166,7 @@ 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 ) + if( !pkttype || root->pkt->pkttype == pkttype ) n1 = root; return n1; } diff --git a/g10/kbxblob.c b/g10/kbxblob.c index c298d587f..01d0dfe10 100644 --- a/g10/kbxblob.c +++ b/g10/kbxblob.c @@ -511,7 +511,7 @@ kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock ) KBXBLOB blob; *r_blob = NULL; - blob = gcry_calloc (1, sizeof *blob ); + blob = gcry_xcalloc (1, sizeof *blob ); if( !blob ) return GCRYERR_NO_MEM; @@ -529,9 +529,9 @@ kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock ) default: break; } } - blob->keys = gcry_calloc ( blob->nkeys, sizeof ( *blob->keys ) ); - blob->uids = gcry_calloc ( blob->nuids, sizeof ( *blob->uids ) ); - blob->sigs = gcry_calloc ( blob->nsigs, sizeof ( *blob->sigs ) ); + blob->keys = gcry_xcalloc ( blob->nkeys, sizeof ( *blob->keys ) ); + blob->uids = gcry_xcalloc ( blob->nuids, sizeof ( *blob->uids ) ); + blob->sigs = gcry_xcalloc ( blob->nsigs, sizeof ( *blob->sigs ) ); if ( !blob->keys || !blob->uids || !blob->sigs ) { rc = GCRYERR_NO_MEM; goto leave; @@ -581,7 +581,7 @@ kbx_new_blob ( KBXBLOB *r_blob, char *image, size_t imagelen ) KBXBLOB blob; *r_blob = NULL; - blob = gcry_calloc (1, sizeof *blob ); + blob = gcry_xcalloc (1, sizeof *blob ); if( !blob ) return GCRYERR_NO_MEM; blob->blob = image; diff --git a/g10/kbxfile.c b/g10/kbxfile.c index 7bf615098..457fb1716 100644 --- a/g10/kbxfile.c +++ b/g10/kbxfile.c @@ -321,7 +321,7 @@ print_kbxfile( const char *filename ) fp = fopen ( filename, "rb" ); if( !fp ) { log_error(_("can't open `%s': %s\n"), filename, strerror(errno) ); - return 1; + return; } while ( !do_print_kbxfile( filename, fp ) ) diff --git a/g10/keydb.h b/g10/keydb.h index 05aac77d3..e0af39aa0 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -1,5 +1,5 @@ /* keydb.h - Key database - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,6 +25,7 @@ #include <gdbm.h> #endif +#include "types.h" #include "basicdefs.h" #include "packet.h" @@ -156,6 +157,7 @@ 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_native( u32 *keyid ); char*get_long_user_id_string( u32 *keyid ); char*get_user_id( u32 *keyid, size_t *rn ); @@ -197,6 +199,7 @@ const char *enum_keyblock_resources( int *sequence, int secret ); int add_keyblock_resource( const char *resname, int force, int secret ); const char *keyblock_resource_name( KBPOS *kbpos ); int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ); +char *get_writable_keyblock_file( int secret ); int locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret ); int locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, diff --git a/g10/keyedit.c b/g10/keyedit.c index fdb8bf6ad..a64c7e86f 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,5 +1,5 @@ /* keyedit.c - keyedit stuff - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -74,8 +74,9 @@ static int enable_disable_key( KBNODE keyblock, int disable ); #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */ -struct sign_uid_attrib { +struct sign_attrib { int non_exportable; + struct revocation_reason_info *reason; }; @@ -157,7 +158,7 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node, else { size_t n; char *p = get_user_id( sig->keyid, &n ); - tty_print_utf8_string( p, n > 40? 40 : n ); + tty_print_utf8_string2( p, n, 40 ); gcry_free(p); } tty_printf("\n"); @@ -239,16 +240,18 @@ check_all_keysigs( KBNODE keyblock, int only_selected ) -int -sign_uid_mk_attrib( PKT_signature *sig, void *opaque ) +static int +sign_mk_attrib( PKT_signature *sig, void *opaque ) { - struct sign_uid_attrib *attrib = 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->reason ) + revocation_reason_build_cb( sig, attrib->reason ); return 0; } @@ -353,7 +356,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) && (node->flag & NODFLG_MARK_A) ) { PACKET *pkt; PKT_signature *sig; - struct sign_uid_attrib attrib; + struct sign_attrib attrib; assert( primary_pk ); memset( &attrib, 0, sizeof attrib ); @@ -364,7 +367,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local ) NULL, sk, 0x10, 0, - sign_uid_mk_attrib, + sign_mk_attrib, &attrib ); if( rc ) { log_error(_("signing failed: %s\n"), gpg_errstr(rc)); @@ -407,6 +410,7 @@ change_passphrase( KBNODE keyblock ) KBNODE node; PKT_secret_key *sk; char *passphrase = NULL; + int no_primary_secrets = 0; node = find_kbnode( keyblock, PKT_SECRET_KEY ); if( !node ) { @@ -423,10 +427,16 @@ change_passphrase( KBNODE keyblock ) 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(); + 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; } @@ -436,6 +446,8 @@ change_passphrase( KBNODE keyblock ) 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(); } } @@ -465,9 +477,12 @@ change_passphrase( KBNODE keyblock ) break; } else { /* okay */ - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); + 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; @@ -558,41 +573,42 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, 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,1, N_("quit this menu") }, - { N_("q") , cmdQUIT , 0,1, NULL }, - { N_("save") , cmdSAVE , 0,1, N_("save and quit") }, - { N_("help") , cmdHELP , 0,1, N_("show this help") }, - { "?" , cmdHELP , 0,1, NULL }, - { N_("fpr") , cmdFPR , 0,1, N_("show fingerprint") }, - { N_("list") , cmdLIST , 0,1, N_("list key and user IDs") }, - { N_("l") , cmdLIST , 0,1, NULL }, - { N_("uid") , cmdSELUID , 0,1, N_("select user ID N") }, - { N_("key") , cmdSELKEY , 0,0, N_("select secondary key N") }, - { N_("check") , cmdCHECK , 0,1, N_("list signatures") }, - { N_("c") , cmdCHECK , 0,1, NULL }, - { N_("sign") , cmdSIGN , 0,1, N_("sign the key") }, - { N_("s") , cmdSIGN , 0,1, NULL }, - { N_("lsign") , cmdLSIGN , 0,1, N_("sign the key locally") }, - { N_("debug") , cmdDEBUG , 0,0, NULL }, - { N_("adduid") , cmdADDUID , 1,0, N_("add a user ID") }, - { N_("deluid") , cmdDELUID , 0,0, N_("delete user ID") }, - { N_("addkey") , cmdADDKEY , 1,0, N_("add a secondary key") }, - { N_("delkey") , cmdDELKEY , 0,0, N_("delete a secondary key") }, - { N_("delsig") , cmdDELSIG , 0,0, N_("delete signatures") }, - { N_("expire") , cmdEXPIRE , 1,0, N_("change the expire date") }, - { N_("toggle") , cmdTOGGLE , 1,0, N_("toggle between secret " - "and public key listing") }, - { N_("t" ) , cmdTOGGLE , 1,0, NULL }, - { N_("pref") , cmdPREF , 0,0, N_("list preferences") }, - { N_("passwd") , cmdPASSWD , 1,0, N_("change the passphrase") }, - { N_("trust") , cmdTRUST , 0,0, N_("change the ownertrust") }, - { N_("revsig") , cmdREVSIG , 0,0, N_("revoke signatures") }, - { N_("revkey") , cmdREVKEY , 1,0, N_("revoke a secondary key") }, - { N_("disable") , cmdDISABLEKEY, 0,0, N_("disable a key") }, - { N_("enable") , cmdENABLEKEY , 0,0, N_("enable a key") }, + { 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_("debug") , cmdDEBUG , 0,1,0, NULL }, + { N_("adduid") , cmdADDUID , 1,1,0, N_("add a user ID") }, + { N_("deluid") , cmdDELUID , 0,1,0, N_("delete user ID") }, + { N_("addkey") , cmdADDKEY , 1,1,0, N_("add a secondary key") }, + { N_("delkey") , cmdDELKEY , 0,1,0, N_("delete a secondary key") }, + { N_("delsig") , cmdDELSIG , 0,1,0, N_("delete signatures") }, + { N_("expire") , cmdEXPIRE , 1,1,0, N_("change the expire date") }, + { N_("toggle") , cmdTOGGLE , 1,0,0, N_("toggle between secret " + "and public key listing") }, + { N_("t" ) , cmdTOGGLE , 1,0,0, NULL }, + { N_("pref") , cmdPREF , 0,1,0, N_("list preferences") }, + { N_("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") }, { NULL, cmdNONE } }; enum cmdids cmd = 0; @@ -678,7 +694,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, have_commands = 0; } if( !have_commands ) { - answer = cpr_get("", _("Command> ")); + answer = cpr_get("keyedit.prompt", _("Command> ")); cpr_kill_prompt(); } trim_spaces(answer); @@ -711,6 +727,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, 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; } @@ -763,6 +783,11 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands, if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN ) && sign_mode ) goto do_cmd_save; + /* Actually we should do a update_trust_record() here so that + * the trust gets displayed correctly. however this is not possible + * because we would have to save the keyblock first - something + * we don't want to do without an explicit save command. + */ break; case cmdDEBUG: @@ -1005,7 +1030,13 @@ show_prefs( KBNODE keyblock, PKT_user_id *uid ) return; } - gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->name, uid->len ); + if( uid->photo ) { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->photo, + uid->photolen ); + } + else { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, uid->name, uid->len ); + } p = get_pref_data( pk->local_id, namehash, &n ); if( !p ) @@ -1049,7 +1080,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, otrust = get_ownertrust_info( pk->local_id ); } - tty_printf("%s%c %4u%c/%08lX created: %s expires: %s", + 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 ), @@ -1058,7 +1089,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, datestr_from_pk(pk), expirestr_from_pk(pk) ); if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { - tty_printf(" trust: %c/%c", otrust, trust ); + tty_printf(_(" trust: %c/%c"), otrust, trust ); if( node->pkt->pkttype == PKT_PUBLIC_KEY && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) { tty_printf("\n*** "); @@ -1075,14 +1106,15 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, 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\n", - node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb", + 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 ) { @@ -1090,12 +1122,12 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, rc = check_key_signature( keyblock, node, NULL ); if( !rc ) - tty_printf( "rev! subkey has been revoked: %s\n", + tty_printf( _("rev! subkey has been revoked: %s\n"), datestr_from_sig( sig ) ); else if( rc == GPGERR_BAD_SIGN ) - tty_printf( "rev- faked revocation found\n" ); + tty_printf( _("rev- faked revocation found\n") ); else if( rc ) - tty_printf( "rev? problem checking revocation: %s\n", + tty_printf( _("rev? problem checking revocation: %s\n"), gpg_errstr(rc) ); } } @@ -1156,7 +1188,7 @@ show_fingerprint( PKT_public_key *pk ) fingerprint_from_pk( pk, array, &n ); p = array; - tty_printf(" Fingerprint:"); + tty_printf(_(" Fingerprint:")); if( n == 20 ) { for(i=0; i < n ; i++, i++, p += 2 ) { if( i == 10 ) @@ -1471,7 +1503,8 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ) } else if( node->pkt->pkttype == PKT_USER_ID ) uid = node->pkt->pkt.user_id; - else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) { + else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE + && sub_pk != NULL ) { 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) @@ -1535,6 +1568,7 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ) gcry_free( sn->pkt ); sn->pkt = newpkt; } + sub_pk = NULL; } } } @@ -1735,6 +1769,7 @@ menu_revsig( KBNODE keyblock ) int changed = 0; int upd_trust = 0; int rc, any; + struct revocation_reason_info *reason = NULL; /* FIXME: detect duplicates here */ tty_printf(_("You have signed these user IDs:\n")); @@ -1797,6 +1832,10 @@ menu_revsig( KBNODE keyblock ) _("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) */ @@ -1804,7 +1843,7 @@ menu_revsig( KBNODE keyblock ) for( node=keyblock; node; node = node->next ) { KBNODE unode; PACKET *pkt; - struct sign_uid_attrib attrib; + struct sign_attrib attrib; PKT_secret_key *sk; if( !(node->flag & NODFLG_MARK_A) @@ -1814,8 +1853,10 @@ menu_revsig( KBNODE keyblock ) assert( unode ); /* we already checked this */ memset( &attrib, 0, sizeof attrib ); + attrib.reason = reason; + node->flag &= ~NODFLG_MARK_A; - sk = gcry_xcalloc_secure( 1, sizeof *sk ); + sk = gcry_xcalloc_secure( 1, sizeof *sk ); if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) { log_info(_("no secret key\n")); continue; @@ -1825,11 +1866,12 @@ menu_revsig( KBNODE keyblock ) NULL, sk, 0x30, 0, - sign_uid_mk_attrib, + sign_mk_attrib, &attrib ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), gpg_errstr(rc)); + release_revocation_reason_info( reason ); return changed; } changed = 1; /* we changed the keyblock */ @@ -1844,7 +1886,7 @@ menu_revsig( KBNODE keyblock ) if( upd_trust ) clear_trust_checked_flag( primary_pk ); - + release_revocation_reason_info( reason ); return changed; } @@ -1861,6 +1903,13 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) int changed = 0; int upd_trust = 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; @@ -1871,14 +1920,20 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) 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, - NULL, NULL ); + sign_mk_attrib, + &attrib ); free_secret_key(sk); if( rc ) { log_error(_("signing failed: %s\n"), gpg_errstr(rc)); + release_revocation_reason_info( reason ); return changed; } changed = 1; /* we changed the keyblock */ @@ -1897,6 +1952,7 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ) if( upd_trust ) clear_trust_checked_flag( mainpk ); + release_revocation_reason_info( reason ); return changed; } diff --git a/g10/keygen.c b/g10/keygen.c index af288b3aa..b6c6cc7e3 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,5 +1,5 @@ /* keygen.c - generate a key pair - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -35,6 +35,58 @@ #include "status.h" #include "i18n.h" +enum para_name { + pKEYTYPE, + pKEYLENGTH, + pSUBKEYTYPE, + pSUBKEYLENGTH, + pNAMEREAL, + pNAMEEMAIL, + pNAMECOMMENT, + 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; + 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; +}; + + +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 ) @@ -43,7 +95,7 @@ write_uid( KBNODE root, const char *s ) size_t n = strlen(s); pkt->pkttype = PKT_USER_ID; - pkt->pkt.user_id = gcry_xmalloc( sizeof *pkt->pkt.user_id + n - 1 ); + pkt->pkt.user_id = gcry_xcalloc( 1, sizeof *pkt->pkt.user_id + n - 1 ); pkt->pkt.user_id->len = n; strcpy(pkt->pkt.user_id->name, s); add_kbnode( root, new_kbnode( pkt ) ); @@ -84,8 +136,9 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque ) keygen_add_key_expire( sig, opaque ); buf[0] = GCRY_CIPHER_TWOFISH; - buf[1] = GCRY_CIPHER_CAST5; - build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 2 ); + buf[1] = GCRY_CIPHER_BLOWFISH; + buf[2] = GCRY_CIPHER_CAST5; + build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 3 ); buf[0] = GCRY_MD_RMD160; buf[1] = GCRY_MD_SHA1; @@ -189,6 +242,7 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk ) } + static int key_from_sexp( GCRY_MPI *array, GCRY_SEXP sexp, const char *topname, const char *elems ) @@ -252,7 +306,7 @@ factors_from_sexp( MPI **retarray, GCRY_SEXP sexp ) for( n=0; (l2 = gcry_sexp_enum( list, &ctx, 0 )); n++ ) ; - array = gcry_calloc( n, sizeof *array ); + array = gcry_xcalloc( n, sizeof *array ); if( !array ) return GCRYERR_NO_MEM; @@ -275,10 +329,10 @@ factors_from_sexp( MPI **retarray, GCRY_SEXP sexp ) } + 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 version ) + STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval ) { int rc; int i; @@ -289,6 +343,18 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, char buf[100]; GCRY_SEXP s_parms, s_key; + 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 ); + } + sprintf(buf, "%u", nbits ); s_parms = SEXP_CONS( SEXP_NEW( "genkey", 0 ), SEXP_CONS( SEXP_NEW(algo == GCRY_PK_ELG_E ? "openpgp-elg" : @@ -303,10 +369,11 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, return rc; } + sk = gcry_xcalloc( 1, sizeof *sk ); pk = gcry_xcalloc( 1, sizeof *pk ); sk->timestamp = pk->timestamp = make_timestamp(); - sk->version = pk->version = version; + sk->version = pk->version = 4; if( expireval ) { sk->expiredate = pk->expiredate = sk->timestamp + expireval; } @@ -361,7 +428,6 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, for(i=0; factors[i]; i++ ) { add_kbnode( sec_root, make_mpi_comment_node("#:ELG_factor:", factors[i] )); - gcry_mpi_release(factors[i]); } return 0; @@ -372,7 +438,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, * Generate a DSA key */ static int -gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, +gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval ) { int rc; @@ -384,8 +450,15 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, char buf[100]; GCRY_SEXP s_parms, s_key; - if( nbits > 1024 ) + 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 ); + } sprintf(buf, "%u", nbits ); s_parms = SEXP_CONS( SEXP_NEW( "genkey", 0 ), @@ -400,6 +473,7 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, return rc; } + sk = gcry_xcalloc( 1, sizeof *sk ); pk = gcry_xcalloc( 1, sizeof *pk ); sk->timestamp = pk->timestamp = make_timestamp(); @@ -464,10 +538,91 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, make_mpi_comment_node("#:DSA_factor:", factors[i] )); /* fixme: Merge this with the elg-generate function and release - * some more stuff */ + * some more stuff (memory-leak) */ return 0; } +#if 0 +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[4]; + 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", gpg_errstr(rc) ); + return rc; + } + + sk = gcry_xcalloc( 1, sizeof *sk ); + pk = gcry_xcalloc( 1, 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_counted_nbits( sk->skey[2] ); + sk->csum += checksum_mpi_counted_nbits( sk->skey[3] ); + sk->csum += checksum_mpi_counted_nbits( sk->skey[4] ); + sk->csum += checksum_mpi_counted_nbits( 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", gpg_errstr(rc) ); + free_public_key(pk); + free_secret_key(sk); + return rc; + } + } + + pkt = gcry_xcalloc( 1,sizeof *pkt); + pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; + pkt->pkt.public_key = pk; + add_kbnode(pub_root, new_kbnode( pkt )); + + pkt = gcry_xcalloc( 1,sizeof *pkt); + pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY; + pkt->pkt.secret_key = sk; + add_kbnode(sec_root, new_kbnode( pkt )); + + return 0; +} +#endif /**************** @@ -502,7 +657,7 @@ check_valid_days( const char *s ) * Returns: 0 to create both a DSA and a ElGamal key. */ static int -ask_algo( int *ret_v4, int addmode ) +ask_algo( int addmode ) { char *answer; int algo; @@ -515,10 +670,9 @@ ask_algo( int *ret_v4, int addmode ) tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 ); tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 ); #if 0 - tty_printf( _(" (%d) ElGamal in a v3 packet\n"), 5 ); + tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 5 ); #endif - *ret_v4 = 1; for(;;) { answer = cpr_get("keygen.algo",_("Your selection? ")); cpr_kill_prompt(); @@ -528,6 +682,15 @@ ask_algo( int *ret_v4, int addmode ) algo = 0; /* create both keys */ break; } + #if 0 + else if( algo == 5 ) { + if( cpr_get_answer_is_yes("keygen.algo.rsa_se",_( + "Do you really want to create a sign and encrypt key? "))) { + algo = GCRY_PK_RSA; + break; + } + } + #endif else if( algo == 4 ) { if( cpr_get_answer_is_yes("keygen.algo.elg_se",_( "Do you really want to create a sign and encrypt key? "))) { @@ -543,13 +706,6 @@ ask_algo( int *ret_v4, int addmode ) algo = GCRY_PK_DSA; break; } - #if 0 - else if( algo == 5 ) { - algo = GCRY_PK_ELG_E; - *ret_v4 = 0; - break; - } - #endif else tty_printf(_("Invalid selection.\n")); } @@ -578,6 +734,9 @@ ask_keysize( int algo ) tty_printf(_("DSA only allows keysizes from 512 to 1024\n")); else if( nbits < 768 ) tty_printf(_("keysize too small; 768 is smallest value allowed.\n")); + else if( algo == GCRY_PK_RSA && nbits < 1024 ) + tty_printf(_("keysize too small;" + " 1024 is smallest value allowed for RSA.\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 @@ -602,7 +761,7 @@ ask_keysize( int algo ) break; } } - else if( nbits > 1536 && !cpr_enabled() ) { + else if( nbits > 1536 && !cpr_enabled() && algo != GCRY_PK_RSA ) { if( cpr_get_answer_is_yes("keygen.size.large.okay",_( "Do you really need such a large keysize? ")) ) break; @@ -623,6 +782,41 @@ ask_keysize( int algo ) } +/**************** + * 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; +} + + static u32 ask_expire_interval(void) { @@ -642,32 +836,14 @@ ask_expire_interval(void) answer = NULL; for(;;) { - int mult; - u32 abs_date=0; - u32 curtime=0;; + u32 curtime=make_timestamp(); gcry_free(answer); answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); cpr_kill_prompt(); trim_spaces(answer); - curtime = make_timestamp(); - if( !*answer ) - valid_days = 0; - else if( (abs_date = scan_isodatestr(answer)) && 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(answer)) ) { - valid_days = atoi(answer) * mult; - if( valid_days < 0 || valid_days > 32767 ) - valid_days = 0; - } - else { + valid_days = parse_expire_string( answer ); + if( valid_days < 0 ) { tty_printf(_("invalid value\n")); continue; } @@ -680,7 +856,10 @@ ask_expire_interval(void) interval = valid_days * 86400L; /* print the date when the key expires */ tty_printf(_("Key expires at %s\n"), - asctimestamp(curtime + interval ) ); + asctimestamp((ulong)(curtime + interval) ) ); + 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", @@ -734,6 +913,7 @@ ask_user_id( int mode ) uid = aname = acomment = amail = NULL; for(;;) { char *p; + int fail=0; if( !aname ) { for(;;) { @@ -785,6 +965,7 @@ ask_user_id( int mode ) } } + gcry_free(uid); uid = p = gcry_xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); p = stpcpy(p, aname ); @@ -812,8 +993,14 @@ ask_user_id( int mode ) 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"); + char *ansstr = _("NnCcEeOoQq"); if( strlen(ansstr) != 10 ) BUG(); @@ -822,8 +1009,9 @@ ask_user_id( int mode ) answer[1] = 0; } else { - answer = cpr_get("keygen.userid.cmd",_( - "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); + 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 ) @@ -841,10 +1029,15 @@ ask_user_id( int mode ) break; } else if( *answer == ansstr[6] || *answer == ansstr[7] ) { - gcry_free(aname); aname = NULL; - gcry_free(acomment); acomment = NULL; - gcry_free(amail); amail = NULL; - break; + if( fail ) { + tty_printf(_("Please correct the error first\n")); + } + else { + gcry_free(aname); aname = NULL; + gcry_free(acomment); acomment = NULL; + gcry_free(amail); amail = NULL; + break; + } } else if( *answer == ansstr[8] || *answer == ansstr[9] ) { gcry_free(aname); aname = NULL; @@ -904,22 +1097,25 @@ ask_passphrase( STRING2KEY **ret_s2k ) static int do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, - DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate, - int v4_packet ) + DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate ) { int rc=0; - tty_printf(_( + 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 == GCRY_PK_ELG || algo == GCRY_PK_ELG_E ) - rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, - sk, expiredate, v4_packet? 4:3 ); + rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate); else if( algo == GCRY_PK_DSA ) rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate); + #if 0 + else if( algo == GCRY_PK_RSA ) + rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate); + #endif else BUG(); @@ -951,61 +1147,553 @@ generate_user_id() if( !p ) return NULL; n = strlen(p); - uid = gcry_xmalloc( sizeof *uid + n - 1 ); + uid = gcry_xcalloc( 1, sizeof *uid + n - 1 ); uid->len = n; strcpy(uid->name, p); 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 ) + gcry_free( r->u.dek ); + else if( r->key == pPASSPHRASE_S2K ) + gcry_free( r->u.s2k ); + + gcry_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 ) +{ + struct para_data_s *r = get_parameter( para, key ); + if( !r ) + return -1; + if( isdigit( *r->u.value ) ) + return atoi( r->u.value ); + return gcry_pk_map_name( r->u.value ); +} + + +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; + + 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 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 || openpgp_pk_test_algo( i, GCRY_PK_USAGE_SIGN ) ) { + r = get_parameter( para, pKEYTYPE ); + log_error("%s:%d: invalid algorithm\n", fname, r->lnr ); + return -1; + } + + i = get_parameter_algo( para, pSUBKEYTYPE ); + if( i > 1 && openpgp_pk_test_algo( i, 0 ) ) { + r = get_parameter( para, pSUBKEYTYPE ); + log_error("%s:%d: invalid algorithm\n", fname, r->lnr ); + 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 = gcry_xcalloc( 1, 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; + } + } + + /* 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 = gcry_xmalloc_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 ); + set_next_passphrase( NULL ); + assert( dek ); + memset( r->u.value, 0, strlen(r->u.value) ); + + r = gcry_xcalloc( 1, sizeof *r ); + r->key = pPASSPHRASE_S2K; + r->u.s2k = s2k; + r->next = para; + para = r; + r = gcry_xcalloc( 1, 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 = gcry_xcalloc( 1, 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 }, + { "Subkey-Type", pSUBKEYTYPE }, + { "Subkey-Length", pSUBKEYLENGTH }, + { "Name-Real", pNAMEREAL }, + { "Name-Email", pNAMEEMAIL }, + { "Name-Comment", pNAMECOMMENT }, + { "Expire-Date", pEXPIREDATE }, + { "Passphrase", pPASSPHRASE }, + { 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(*p); p++ ) + ; + if( !*p || *p == '#' ) + continue; + keyword = p; + if( *keyword == '%' ) { + for( ; !isspace(*p); p++ ) + ; + if( *p ) + *p++ = 0; + for( ; isspace(*p); p++ ) + ; + value = p; + trim_trailing_ws( value, strlen(value) ); + if( !stricmp( keyword, "%echo" ) ) + log_info("%s\n", value ); + else if( !stricmp( keyword, "%dry-run" ) ) + outctrl.dryrun = 1; + else if( !stricmp( keyword, "%commit" ) ) { + outctrl.lnr = lnr; + proc_parameter_file( para, fname, &outctrl ); + release_parameter_list( para ); + para = NULL; + } + else if( !stricmp( keyword, "%pubring" ) ) { + if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) + ; /* still the same file - ignore it */ + else { + gcry_free( outctrl.pub.newfname ); + outctrl.pub.newfname = gcry_xstrdup( value ); + outctrl.use_files = 1; + } + } + else if( !stricmp( keyword, "%secring" ) ) { + if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) ) + ; /* still the same file - ignore it */ + else { + gcry_free( outctrl.sec.newfname ); + outctrl.sec.newfname = gcry_xstrdup( value ); + 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(*p); p++ ) + ; + if( !*p ) { + err = "missing argument"; + break; + } + value = p; + trim_trailing_ws( value, strlen(value) ); + + for(i=0; keywords[i].name; i++ ) { + if( !stricmp( 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 = gcry_xcalloc( 1, 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 ); + gcry_free( outctrl.pub.fname ); + gcry_free( outctrl.pub.newfname ); + gcry_free( outctrl.sec.fname ); + gcry_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() +generate_keypair( const char *fname ) { - unsigned nbits; - char *pub_fname = NULL; - char *sec_fname = NULL; + unsigned int nbits; char *uid = NULL; - KBNODE pub_root = NULL; - KBNODE sec_root = NULL; - PKT_secret_key *sk = NULL; DEK *dek; STRING2KEY *s2k; - int rc; int algo; - u32 expire; - int v4; 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 || opt.answer_yes || opt.answer_no ) { - log_error(_("Key generation can only be used in interactive mode\n")); + if( opt.batch ) { + read_parameter_file( fname ); return; } - algo = ask_algo( &v4, 0 ); - if( !algo ) { - algo = GCRY_PK_ELG_E; + algo = ask_algo( 0 ); + if( !algo ) { /* default: DSA with ElG subkey of the specified size */ both = 1; + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = pKEYTYPE; + sprintf( r->u.value, "%d", GCRY_PK_DSA ); + r->next = para; + para = r; tty_printf(_("DSA keypair will have 1024 bits.\n")); + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = pKEYLENGTH; + strcpy( r->u.value, "1024" ); + r->next = para; + para = r; + + algo = GCRY_PK_ELG_E; + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = pSUBKEYTYPE; + sprintf( r->u.value, "%d", algo ); + r->next = para; + para = r; + } + else { + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = pKEYTYPE; + sprintf( r->u.value, "%d", algo ); + r->next = para; + para = r; } + nbits = ask_keysize( algo ); + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = both? pSUBKEYLENGTH : pKEYLENGTH; + sprintf( r->u.value, "%u", nbits); + r->next = para; + para = r; + expire = ask_expire_interval(); + r = gcry_xcalloc( 1, sizeof *r + 20 ); + r->key = pKEYEXPIRE; + r->u.expire = expire; + r->next = para; + para = r; + r = gcry_xcalloc( 1, 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 = gcry_xcalloc( 1, sizeof *r + strlen(uid) ); + r->key = pUSERID; + strcpy( r->u.value, uid ); + r->next = para; + para = r; + dek = ask_passphrase( &s2k ); + if( dek ) { + r = gcry_xcalloc( 1, sizeof *r ); + r->key = pPASSPHRASE_DEK; + r->u.dek = dek; + r->next = para; + para = r; + r = gcry_xcalloc( 1, 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 ); +} - /* now check whether we are allowed to write to the keyrings */ - pub_fname = make_filename(opt.homedir, "pubring.gpg", NULL ); - sec_fname = make_filename(opt.homedir, "secring.gpg", NULL ); +static void +do_generate_keypair( struct para_data_s *para, + struct output_control_s *outctrl ) +{ + char *pub_fname = NULL; + char *sec_fname = NULL; + KBNODE pub_root = NULL; + KBNODE sec_root = NULL; + PKT_secret_key *sk = NULL; + const char *s; + int rc; + + 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; + gcry_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; + gcry_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 ); + } + } + pub_fname = outctrl->pub.fname; /* only for info output */ + sec_fname = outctrl->sec.fname; /* only for info output */ + assert( outctrl->pub.stream ); + assert( outctrl->sec.stream ); + } + else { + pub_fname = get_writable_keyblock_file( 0 ); + sec_fname = get_writable_keyblock_file( 1 ); + } + if( opt.verbose ) { - tty_printf(_("writing public certificate to `%s'\n"), pub_fname ); - tty_printf(_("writing secret certificate to `%s'\n"), sec_fname ); + log_info(_("writing public key to `%s'\n"), pub_fname ); + log_info(_("writing secret key to `%s'\n"), sec_fname ); } /* we create the packets as a tree of kbnodes. Because the structure @@ -1016,24 +1704,31 @@ generate_keypair() pub_root = make_comment_node("#"); delete_kbnode(pub_root); sec_root = make_comment_node("#"); delete_kbnode(sec_root); - if( both ) - rc = do_create( GCRY_PK_DSA, 1024, pub_root, sec_root, - dek, s2k, &sk, expire, 1); - else - rc = do_create( algo, nbits, pub_root, sec_root, - dek, s2k, &sk, expire, v4); - if( !rc ) - write_uid(pub_root, uid ); - if( !rc ) - write_uid(sec_root, uid ); - if( !rc ) - rc = write_selfsig(pub_root, pub_root, sk); - if( !rc ) - rc = write_selfsig(sec_root, pub_root, sk); + 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 && (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); + if( !rc ) + rc = write_selfsig(sec_root, pub_root, sk); + } - if( both ) { - rc = do_create( algo, nbits, pub_root, sec_root, - dek, s2k, NULL, expire, 1 ); + 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); if( !rc ) @@ -1041,7 +1736,18 @@ generate_keypair() } - if( !rc ) { + if( !rc && outctrl->use_files ) { /* direct write to specified files */ + rc = write_keyblock( outctrl->pub.stream, pub_root ); + if( rc ) + log_error("can't write public key: %s\n", gpg_errstr(rc) ); + if( !rc ) { + rc = write_keyblock( outctrl->sec.stream, sec_root ); + if( rc ) + log_error("can't write secret key: %s\n", gpg_errstr(rc) ); + } + + } + else if( !rc ) { /* write to the standard keyrings */ KBPOS pub_kbpos; KBPOS sec_kbpos; int rc1 = -1; @@ -1082,12 +1788,17 @@ generate_keypair() else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) ) log_error("can't write secret key: %s\n", gpg_errstr(rc) ); else { - tty_printf(_("public and secret key created and signed.\n") ); - if( algo == GCRY_PK_DSA ) + if( !opt.batch ) + tty_printf(_("public and secret key created and signed.\n") ); + if( !opt.batch + && get_parameter_algo( para, pKEYTYPE ) == GCRY_PK_DSA + && !get_parameter( 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( !rc1 ) @@ -1096,18 +1807,20 @@ generate_keypair() unlock_keyblock( &sec_kbpos ); } - - if( rc ) - tty_printf(_("Key generation failed: %s\n"), gpg_errstr(rc) ); + if( rc ) { + if( opt.batch ) + log_error("key generation failed: %s\n", gpg_errstr(rc) ); + else + tty_printf(_("Key generation failed: %s\n"), gpg_errstr(rc) ); + } release_kbnode( pub_root ); release_kbnode( sec_root ); if( sk ) /* the unprotected secret key */ free_secret_key(sk); - gcry_free(uid); - gcry_free(dek); - gcry_free(s2k); - gcry_free(pub_fname); - gcry_free(sec_fname); + if( !outctrl->use_files ) { + gcry_free(pub_fname); + gcry_free(sec_fname); + } } @@ -1121,7 +1834,7 @@ 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 v4, algo; + int algo; u32 expire; unsigned nbits; char *passphrase = NULL; @@ -1146,8 +1859,10 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); - rc = GPGERR_TIME_CONFLICT; - goto leave; + if( !opt.ignore_time_conflict ) { + rc = GPGERR_TIME_CONFLICT; + goto leave; + } } @@ -1170,7 +1885,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) goto leave; - algo = ask_algo( &v4, 1 ); + algo = ask_algo( 1 ); assert(algo); nbits = ask_keysize( algo ); expire = ask_expire_interval(); @@ -1187,7 +1902,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) } rc = do_create( algo, nbits, pub_keyblock, sec_keyblock, - dek, s2k, NULL, expire, v4 ); + dek, s2k, NULL, expire ); if( !rc ) rc = write_keybinding(pub_keyblock, pub_keyblock, sk); if( !rc ) @@ -1207,3 +1922,20 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) 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, gpg_errstr(rc) ); + return GPGERR_WRITE_FILE; + } + } + return 0; +} + diff --git a/g10/keyid.c b/g10/keyid.c index ddaf0d5d3..14406b60b 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -1,5 +1,5 @@ /* keyid.c - jeyid and fingerprint handling - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,12 +25,14 @@ #include <errno.h> #include <time.h> #include <assert.h> + #include <gcrypt.h> #include "util.h" #include "main.h" #include "packet.h" #include "options.h" #include "keydb.h" +#include "i18n.h" int @@ -52,7 +54,7 @@ static GCRY_MD_HD do_fingerprint_md( PKT_public_key *pk ) { GCRY_MD_HD md; - unsigned n; + unsigned int n; unsigned int nn[GNUPG_MAX_NPKEY]; byte *pp[GNUPG_MAX_NPKEY]; int i; @@ -339,7 +341,7 @@ expirestr_from_pk( PKT_public_key *pk ) time_t atime; if( !pk->expiredate ) - return "never "; + return _("never "); atime = pk->expiredate; tp = gmtime( &atime ); sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); @@ -354,7 +356,7 @@ expirestr_from_sk( PKT_secret_key *sk ) time_t atime; if( !sk->expiredate ) - return "never "; + return _("never "); atime = sk->expiredate; tp = gmtime( &atime ); sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday ); diff --git a/g10/keylist.c b/g10/keylist.c index 0cefa2d56..751a61c9b 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1,5 +1,5 @@ /* keylist.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -43,34 +43,24 @@ static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk ); /**************** * List the keys - * If NNAMES is 0; all available keys are listed + * If list is NULL, all available keys are listed */ void -public_key_list( int nnames, char **names ) +public_key_list( STRLIST list ) { - if( !nnames ) + if( !list ) list_all(0); - else { /* List by user id */ - STRLIST list = NULL; - for( ; nnames ; nnames--, names++ ) - add_to_strlist( &list, *names ); + else list_one( list, 0 ); - free_strlist( list ); - } } void -secret_key_list( int nnames, char **names ) +secret_key_list( STRLIST list ) { - if( !nnames ) + if( !list ) list_all(1); - else { /* List by user id */ - STRLIST list = NULL; - for( ; nnames ; nnames--, names++ ) - add_to_strlist( &list, *names ); + else /* List by user id */ list_one( list, 1 ); - free_strlist( list ); - } } @@ -145,6 +135,7 @@ list_one( STRLIST names, int secret ) return; } do { + merge_keys_and_selfsig( keyblock ); list_keyblock( keyblock, 0 ); release_kbnode( keyblock ); } while( !get_pubkey_next( ctx, NULL, &keyblock ) ); @@ -155,7 +146,7 @@ list_one( STRLIST names, int secret ) static void print_key_data( PKT_public_key *pk, u32 *keyid ) { - int n = pubkey_get_npkey( pk->pubkey_algo ); + int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0; int i; for(i=0; i < n; i++ ) { @@ -211,21 +202,26 @@ list_keyblock( KBNODE keyblock, int secret ) sk = NULL; keyid_from_pk( pk, keyid ); if( opt.with_colons ) { - trustletter = query_trust_info( pk, NULL ); - if( trustletter == 'u' ) - ulti_hack = 1; - printf("pub:%c:%u:%d:%08lX%08lX:%s:%s:", - trustletter, + if ( opt.fast_list_mode ) { + fputs( "pub::", stdout ); + trustletter = 0; + } + else { + trustletter = query_trust_info( pk, NULL ); + if( trustletter == 'u' ) + ulti_hack = 1; + printf("pub:%c:", trustletter ); + } + printf("%u:%d:%08lX%08lX:%s:%s:", nbits_from_pk( pk ), pk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], datestr_from_pk( pk ), - pk->expiredate? strtimestamp(pk->expiredate):"" - ); + pk->expiredate? strtimestamp(pk->expiredate):"" ); if( pk->local_id ) printf("%lu", pk->local_id ); putchar(':'); - if( pk->local_id ) + if( pk->local_id && !opt.fast_list_mode ) putchar( get_ownertrust_info( pk->local_id ) ); putchar(':'); } @@ -237,15 +233,22 @@ list_keyblock( KBNODE keyblock, int secret ) } for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) { - if( node->pkt->pkttype == PKT_USER_ID ) { + if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) { if( any ) { - if( opt.with_colons ) { + if ( opt.with_colons ) { byte namehash[20]; if( pk && !ulti_hack ) { - gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, - node->pkt->pkt.user_id->name, - node->pkt->pkt.user_id->len ); + if( node->pkt->pkt.user_id->photo ) { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, + node->pkt->pkt.user_id->name, + node->pkt->pkt.user_id->len ); + } + else { + gcry_md_hash_buffer( GCRY_MD_RMD160, namehash, + node->pkt->pkt.user_id->name, + node->pkt->pkt.user_id->len ); + } trustletter = query_trust_info( pk, namehash ); } else @@ -288,8 +291,13 @@ list_keyblock( KBNODE keyblock, int secret ) keyid_from_pk( pk2, keyid2 ); if( opt.with_colons ) { - printf("sub:%c:%u:%d:%08lX%08lX:%s:%s:", - trustletter, + if ( opt.fast_list_mode ) { + fputs( "sub::", stdout ); + } + else { + printf("sub:%c:", trustletter ); + } + printf("%u:%d:%08lX%08lX:%s:%s:", nbits_from_pk( pk2 ), pk2->pubkey_algo, (ulong)keyid2[0],(ulong)keyid2[1], @@ -303,11 +311,16 @@ list_keyblock( KBNODE keyblock, int secret ) putchar(':'); putchar('\n'); } - else - printf("sub %4u%c/%08lX %s\n", nbits_from_pk( pk2 ), + else { + printf("sub %4u%c/%08lX %s", nbits_from_pk( pk2 ), pubkey_letter( pk2->pubkey_algo ), (ulong)keyid2[1], datestr_from_pk( pk2 ) ); + if( pk2->expiredate ) { + printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) ); + } + putchar('\n'); + } if( opt.fingerprint > 1 ) fingerprint( pk2, NULL ); if( opt.with_key_data ) @@ -346,6 +359,7 @@ list_keyblock( KBNODE keyblock, int secret ) 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 ) @@ -363,11 +377,11 @@ list_keyblock( KBNODE keyblock, int secret ) if( sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30 ) - fputs("rev", stdout); + sigstr = "rev"; else if( (sig->sig_class&~3) == 0x10 ) - fputs("sig", stdout); + sigstr = "sig"; else if( sig->sig_class == 0x18 ) - fputs("sig", stdout); + sigstr = "sig"; else { if( opt.with_colons ) printf("sig::::::::::%02x:\n",sig->sig_class ); @@ -390,6 +404,7 @@ list_keyblock( KBNODE keyblock, int secret ) rc = 0; sigrc = ' '; } + fputs( sigstr, stdout ); if( opt.with_colons ) { putchar(':'); if( sigrc != ' ' ) @@ -405,7 +420,7 @@ list_keyblock( KBNODE keyblock, int secret ) printf("[%s] ", gpg_errstr(rc) ); else if( sigrc == '?' ) ; - else { + else if ( !opt.fast_list_mode ) { size_t n; char *p = get_user_id( sig->keyid, &n ); if( opt.with_colons ) diff --git a/g10/ks-proto.h b/g10/ks-proto.h index 2a3b2ddb1..6e8bbad0b 100644 --- a/g10/ks-proto.h +++ b/g10/ks-proto.h @@ -1,5 +1,5 @@ /* ks-proto.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * diff --git a/g10/main.h b/g10/main.h index 621fc57de..711f5b8d2 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,5 +1,5 @@ /* main.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -73,7 +73,6 @@ int pubkey_get_nsig( int algo ); int pubkey_get_nenc( int algo ); unsigned int pubkey_nbits( int algo, MPI *pkey ); - /*-- helptext.c --*/ void display_online_help( const char *keyword ); @@ -94,7 +93,7 @@ int clearsign_file( const char *fname, STRLIST locusr, const char *outfile ); /*-- sig-check.c --*/ int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); int check_key_signature2( KBNODE root, KBNODE node, - int *is_selfsig, u32 *r_expire ); + int *is_selfsig, u32 *r_expiredate, int *r_expired ); /*-- delkey.c --*/ int delete_key( const char *username, int secure ); @@ -105,7 +104,7 @@ void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds, /*-- keygen.c --*/ u32 ask_expiredate(void); -void generate_keypair(void); +void generate_keypair( const char *fname ); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); @@ -116,20 +115,20 @@ 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 copy_options_file( const char *destdir ); +void try_make_homedir( const char *fname ); /*-- seskey.c --*/ void make_session_key( DEK *dek ); MPI encode_session_key( DEK *dek, unsigned nbits ); MPI encode_md_value( int pubkey_algo, GCRY_MD_HD md, - int hash_algo, unsigned nbits ); + 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 --*/ -int import_keys( const char *filename, int fast ); +void import_keys( char **fnames, int nnames, int fast ); int import_keys_stream( IOBUF inp, int fast ); int collapse_uids( KBNODE *keyblock ); @@ -137,20 +136,27 @@ int collapse_uids( KBNODE *keyblock ); int export_pubkeys( STRLIST users, int onlyrfc ); int export_pubkeys_stream( IOBUF out, STRLIST users, int onlyrfc ); 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 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( int nnames, char **names ); -void secret_key_list( int nnames, char **names ); +void public_key_list( STRLIST list ); +void secret_key_list( STRLIST list ); /*-- verify.c --*/ int verify_signatures( int nfiles, char **files ); +int verify_files( int nfiles, char **files ); /*-- decrypt.c --*/ int decrypt_message( const char *filename ); diff --git a/g10/mainproc.c b/g10/mainproc.c index f2637340c..09c35db21 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,5 +1,5 @@ /* mainproc.c - handle packets - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -160,11 +160,11 @@ add_signature( CTX c, PACKET *pkt ) 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 + * 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.) */ + * from stdin. (GPG is able to read PGP stuff anyway.) */ node = new_kbnode( pkt ); c->list = node; return 1; @@ -224,10 +224,14 @@ proc_pubkey_enc( CTX c, PACKET *pkt ) || is_RSA(enc->pubkey_algo) ) { if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1]) || !seckey_available( enc->keyid )) ) { - c->dek = gcry_xmalloc_secure( sizeof *c->dek ); - if( (result = get_session_key( enc, c->dek )) ) { - /* error: delete the DEK */ - gcry_free(c->dek); c->dek = NULL; + if( opt.list_only ) + result = -1; + else { + c->dek = gcry_xmalloc_secure( sizeof *c->dek ); + if( (result = get_session_key( enc, c->dek )) ) { + /* error: delete the DEK */ + gcry_free(c->dek); c->dek = NULL; + } } } else @@ -267,6 +271,8 @@ print_failed_pkenc( struct kidlist_item *list ) PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); const char *algstr = gcry_pk_algo_name( list->pubkey_algo ); + if( !algstr ) + algstr = "[?]"; pk->pubkey_algo = list->pubkey_algo; if( !get_pubkey( pk, list->kid ) ) { size_t n; @@ -309,10 +315,14 @@ proc_encrypted( CTX c, PACKET *pkt ) print_failed_pkenc( c->failed_pkenc ); + write_status( STATUS_BEGIN_DECRYPTION ); + /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ - if( !c->dek && !c->last_was_session_key ) { + if( opt.list_only ) + result = -1; + else if( !c->dek && !c->last_was_session_key ) { /* assume this is old conventional encrypted data - * Actually we should use IDEA and MD5 in this case, but becuase + * Actually we should use IDEA and MD5 in this case, but because * IDEA is patented we can't do so */ c->dek = passphrase_to_dek( NULL, 0, opt.def_cipher_algo ? opt.def_cipher_algo @@ -322,6 +332,7 @@ proc_encrypted( CTX c, PACKET *pkt ) result = GPGERR_NO_SECKEY; if( !result ) result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); + gcry_free(c->dek); c->dek = NULL; if( result == -1 ) ; @@ -339,11 +350,12 @@ proc_encrypted( CTX c, PACKET *pkt ) else { write_status( STATUS_DECRYPTION_FAILED ); log_error(_("decryption failed: %s\n"), gpg_errstr(result)); - /* Hmmm: does this work when we have encrypted using a multiple + /* 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 ); } @@ -360,7 +372,8 @@ proc_plaintext( CTX c, PACKET *pkt ) else if( opt.verbose ) log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name); free_md_filter_context( &c->mfx ); - if( !(c->mfx.md = gcry_md_open( 0, 0)) ) + c->mfx.md = gcry_md_open( 0, 0); + if( !c->mfx.md ) BUG(); /* fixme: we may need to push the textfilter if we have sigclass 1 * and no armoring - Not yet tested @@ -372,8 +385,7 @@ proc_plaintext( CTX c, PACKET *pkt ) for(n=c->list; n; n = n->next ) { if( n->pkt->pkttype == PKT_ONEPASS_SIG ) { if( n->pkt->pkt.onepass_sig->digest_algo ) { - gcry_md_enable( c->mfx.md, - n->pkt->pkt.onepass_sig->digest_algo ); + gcry_md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo ); if( !any && n->pkt->pkt.onepass_sig->digest_algo == GCRY_MD_MD5 ) only_md5 = 1; @@ -398,24 +410,28 @@ proc_plaintext( CTX c, PACKET *pkt ) clearsig = 1; } } - if( !any ) { /* no onepass sig packet: enable all standard algos */ + + if( !any && !opt.skip_verify ) { + /* no onepass sig packet: enable all standard algos */ gcry_md_enable( c->mfx.md, GCRY_MD_RMD160 ); gcry_md_enable( c->mfx.md, GCRY_MD_SHA1 ); gcry_md_enable( c->mfx.md, GCRY_MD_MD5 ); } - if( only_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. */ - if( !(c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0)) ) + c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0); + if( !c->mfx.md2 ) BUG(); } - #if 0 - #warning md_start_debug is enabled - md_start_debug( c->mfx.md, "verify" ); - #endif + if ( DBG_HASHING ) { + gcry_md_start_debug( c->mfx.md, "verify" ); + if ( c->mfx.md2 ) + gcry_md_start_debug( c->mfx.md2, "verify2" ); + } rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); if( rc == GPGERR_CREATE_FILE && !c->sigs_only) { /* can't write output but we hash it anyway to @@ -494,12 +510,17 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig ) * in canonical mode ??? (calculating both modes???) */ if( c->mfx.md ) { md = gcry_md_copy( c->mfx.md ); - if( c->mfx.md2 ) + if( !md ) + BUG(); + if( c->mfx.md2 ) { md2 = gcry_md_copy( c->mfx.md2 ); + if( !md2 ) + BUG(); + } } else { /* detached signature */ - log_debug("Do we really need this here?"); - md = gcry_md_open( 0, 0 ); /* signature_check() will enable the md*/ + log_debug("Do we really need this here?"); + md = gcry_md_open( 0, 0 ); /* signature_check() will enable the md*/ md2 = gcry_md_open( 0, 0 ); if( !md || !md2 ) BUG(); @@ -513,6 +534,11 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig ) || 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 GPGERR_NOT_PROCESSED; + } else { log_error("invalid root packet for sigclass %02x\n", sig->sig_class); @@ -540,8 +566,12 @@ print_userid( PACKET *pkt ) printf("ERROR: unexpected packet type %d", pkt->pkttype ); return; } - print_string( stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len, - opt.with_colons ); + if( opt.with_colons ) + 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 ); } @@ -644,11 +674,13 @@ list_node( CTX c, KBNODE node ) keyid_from_pk( pk, keyid ); if( mainkey ) { c->local_id = pk->local_id; - c->trustletter = query_trust_info( pk, NULL ); + c->trustletter = opt.fast_list_mode? + 0 : query_trust_info( pk, NULL ); } - printf("%s:%c:%u:%d:%08lX%08lX:%s:%s:", - mainkey? "pub":"sub", - c->trustletter, + 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], @@ -657,7 +689,7 @@ list_node( CTX c, KBNODE node ) if( c->local_id ) printf("%lu", c->local_id ); putchar(':'); - if( c->local_id ) + if( c->local_id && !opt.fast_list_mode ) putchar( get_ownertrust_info( c->local_id ) ); putchar(':'); if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) { @@ -675,6 +707,7 @@ list_node( CTX c, KBNODE node ) 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 ) { @@ -717,6 +750,10 @@ list_node( CTX c, KBNODE node ) } } } + else if( pk->expiredate ) { /* of subkey */ + printf(_(" [expires: %s]"), expirestr_from_pk( pk ) ); + } + if( !any ) putchar('\n'); if( !mainkey && opt.fingerprint > 1 ) @@ -847,7 +884,7 @@ list_node( CTX c, KBNODE node ) if( opt.with_colons ) putchar(':'); } - else { + else if( !opt.fast_list_mode ) { p = get_user_id( sig->keyid, &n ); print_string( stdout, p, n, opt.with_colons ); gcry_free(p); @@ -861,6 +898,7 @@ list_node( CTX c, KBNODE node ) } + int proc_packets( void *anchor, IOBUF a ) { @@ -873,6 +911,8 @@ proc_packets( void *anchor, IOBUF a ) return rc; } + + int proc_signature_packets( void *anchor, IOBUF a, STRLIST signedfiles, const char *sigfilename ) @@ -1027,7 +1067,7 @@ static int check_sig_and_print( CTX c, KBNODE node ) { PKT_signature *sig = node->pkt->pkt.signature; - const char *tstr; + const char *astr, *tstr; int rc; if( opt.skip_verify ) { @@ -1036,12 +1076,12 @@ check_sig_and_print( CTX c, KBNODE node ) } tstr = asctimestamp(sig->timestamp); + astr = gcry_pk_algo_name( sig->pubkey_algo ); log_info(_("Signature made %.*s using %s key ID %08lX\n"), - (int)strlen(tstr), tstr, gcry_pk_algo_name( sig->pubkey_algo ), - (ulong)sig->keyid[1] ); + (int)strlen(tstr), tstr, astr? astr: "?", (ulong)sig->keyid[1] ); rc = do_check_sig(c, node, NULL ); - if( rc == GPGERR_NO_PUBKEY && opt.keyserver_name ) { + if( rc == GPGERR_NO_PUBKEY && opt.keyserver_name && opt.auto_key_retrieve) { if( !hkp_ask_import( sig->keyid ) ) rc = do_check_sig(c, node, NULL ); } @@ -1121,7 +1161,8 @@ check_sig_and_print( CTX c, KBNODE node ) buf[16] = 0; write_status_text( STATUS_NO_PUBKEY, buf ); } - log_error(_("Can't check signature: %s\n"), gpg_errstr(rc) ); + if( rc != GPGERR_NOT_PROCESSED ) + log_error(_("Can't check signature: %s\n"), gpg_errstr(rc) ); } return rc; } @@ -1136,7 +1177,7 @@ proc_tree( CTX c, KBNODE node ) KBNODE n1; int rc; - if( opt.list_packets ) + if( opt.list_packets || opt.list_only ) return; c->local_id = 0; @@ -1155,7 +1196,7 @@ proc_tree( CTX c, KBNODE node ) if( !c->have_data ) { free_md_filter_context( &c->mfx ); /* prepare to create all requested message digests */ - if( !(c->mfx.md = gcry_md_open(0, 0)) ) + if ( !(c->mfx.md = gcry_md_open(0, 0)) ) BUG(); /* fixme: why looking for the signature packet and not 1passpacket*/ @@ -1163,13 +1204,16 @@ proc_tree( CTX c, KBNODE node ) gcry_md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo); } /* ask for file and hash it */ - if( c->sigs_only ) + 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 + } + else { rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, - iobuf_get_fname(c->iobuf), 0 ); + iobuf_get_fname(c->iobuf), + n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); + } if( rc ) { log_error("can't hash datafile: %s\n", gpg_errstr(rc)); return; @@ -1182,15 +1226,22 @@ proc_tree( CTX c, KBNODE node ) else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; - if( !c->have_data ) { + 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 ); - if( !(c->mfx.md = gcry_md_open(sig->digest_algo, 0)) ) + c->mfx.md = gcry_md_open(sig->digest_algo, 0); + if ( !c->mfx.md ) BUG(); - if( sig->digest_algo == GCRY_MD_MD5 - && is_RSA( sig->pubkey_algo ) ) { + if( !opt.pgp2_workarounds ) + ; + else if( sig->digest_algo == GCRY_MD_MD5 + && is_RSA( sig->pubkey_algo ) ) { /* enable a workaround for a pgp2 bug */ - if( !(c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0 )) ) + c->mfx.md2 = gcry_md_open( GCRY_MD_MD5, 0 ); + if ( !c->mfx.md2 ) BUG(); } else if( sig->digest_algo == GCRY_MD_SHA1 @@ -1198,9 +1249,11 @@ proc_tree( CTX c, KBNODE node ) && sig->sig_class == 0x01 ) { /* enable the workaround also for pgp5 when the detached * signature has been created in textmode */ - if( !(c->mfx.md2 = gcry_md_open( sig->digest_algo, 0 )) ) + c->mfx.md2 = gcry_md_open( sig->digest_algo, 0 ); + if ( !c->mfx.md2 ) BUG(); } + #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 @@ -1208,14 +1261,18 @@ proc_tree( CTX c, KBNODE node ) * then produce the "correct" hash. This is very, very ugly * hack but it may help in some cases (and break others) */ - if( c->sigs_only ) + /* c->mfx.md2? 0 :(sig->sig_class == 0x01) */ + #endif + if( c->sigs_only ) { rc = hash_datafiles( c->mfx.md, c->mfx.md2, c->signed_data, c->sigfilename, - c->mfx.md2? 0 :(sig->sig_class == 0x01) ); - else + (sig->sig_class == 0x01) ); + } + else { rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, - iobuf_get_fname(c->iobuf), - c->mfx.md2? 0 :(sig->sig_class == 0x01) ); + iobuf_get_fname(c->iobuf), + (sig->sig_class == 0x01) ); + } if( rc ) { log_error("can't hash datafile: %s\n", gpg_errstr(rc)); return; diff --git a/g10/mdfilter.c b/g10/mdfilter.c index abb55d8c1..c41ad857e 100644 --- a/g10/mdfilter.c +++ b/g10/mdfilter.c @@ -1,5 +1,5 @@ /* mdfilter.c - filter data and calculate a message digest - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,9 +25,9 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "errors.h" #include "iobuf.h" -#include <gcrypt.h> #include "util.h" #include "filter.h" diff --git a/g10/misc.c b/g10/misc.c index d3c01f4ef..e7bd8fac6 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1,5 +1,5 @@ /* misc.c - miscellaneous functions - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <assert.h> #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #include <asm/sysinfo.h> #include <asm/unistd.h> @@ -32,6 +31,8 @@ #include <sys/time.h> #include <sys/resource.h> #endif +#include <assert.h> + #include <gcrypt.h> #include "util.h" #include "main.h" @@ -41,7 +42,6 @@ #define MAX_EXTERN_MPI_BITS 16384 - #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2 #warning using trap_unaligned static int @@ -246,6 +246,7 @@ mpi_print( FILE *fp, MPI a, int mode ) } + u16 checksum_u16( unsigned n ) { @@ -289,7 +290,6 @@ checksum_mpi( MPI a ) } - u32 buffer_to_u32( const byte *buffer ) { @@ -359,6 +359,7 @@ print_digest_algo_note( int algo ) } + /**************** * Wrapper around the libgcrypt function with addional checks on * openPGP contrainst for the algo ID. diff --git a/g10/openfile.c b/g10/openfile.c index 0b768fe5e..47dca0e76 100644 --- a/g10/openfile.c +++ b/g10/openfile.c @@ -1,5 +1,5 @@ /* openfile.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,6 +24,9 @@ #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 <gcrypt.h> @@ -39,13 +42,16 @@ #define SKELEXT ".skel" #endif - #ifdef HAVE_DRIVE_LETTERS #define CMP_FILENAME(a,b) stricmp( (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. */ @@ -78,7 +84,6 @@ overwrite_filep( const char *fname ) } - /**************** * Strip know extensions from iname and return a newly allocated * filename. Return NULL if we can't do that. @@ -176,7 +181,7 @@ open_outfile( const char *iname, int mode, IOBUF *a ) name = opt.outfile; else { #ifdef USE_ONLY_8DOT3 - /* It is quite common for DOS system to have only one dot in a + /* 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. @@ -195,7 +200,7 @@ open_outfile( const char *iname, int mode, IOBUF *a ) strcpy(dot, newsfx ); } else if( dot && !dot[1] ) /* don't duplicate a dot */ - strcat( dot, newsfx+1 ); + strcpy( dot, newsfx+1 ); else strcat( buf, newsfx ); #else @@ -253,7 +258,7 @@ open_sigfile( const char *iname ) /**************** * Copy the option file skeleton to the given directory. */ -void +static void copy_options_file( const char *destdir ) { const char *datadir = GNUPG_DATADIR; @@ -296,3 +301,23 @@ copy_options_file( const char *destdir ) gcry_free(fname); } + +void +try_make_homedir( const char *fname ) +{ + if( opt.dry_run ) + return; + if( strlen(fname) >= 7 + && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) { + 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 options file\n") ); + gpg_exit(1); + } +} + diff --git a/g10/options.h b/g10/options.h index cbe6c24e0..79b6bcd55 100644 --- a/g10/options.h +++ b/g10/options.h @@ -1,5 +1,5 @@ /* options.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -28,11 +28,12 @@ struct { int verbose; int quiet; - unsigned debug; + unsigned int debug; int armor; int compress; char *outfile; int dry_run; + int list_only; int textmode; int batch; /* run in batch mode */ int answer_yes; /* answer yes on most questions */ @@ -63,7 +64,9 @@ struct { int compress_sigs; int always_trust; int rfc1991; - unsigned emulate_bugs; /* bug emulation flags EMUBUG_xxxx */ + 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; @@ -83,9 +86,17 @@ struct { int allow_non_selfsigned_uid; int no_literal; ulong set_filesize; + int honor_http_proxy; + int fast_list_mode; + int ignore_time_conflict; + int command_fd; + int auto_key_retrieve; } opt; +#define EMUBUG_3DESS2K 2 +#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 */ @@ -96,6 +107,7 @@ struct { #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_PACKET (opt.debug & DBG_PACKET_VALUE) @@ -104,6 +116,6 @@ struct { #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) #define DBG_TRUST (opt.debug & DBG_TRUST_VALUE) #define DBG_CIPHER (opt.debug & DBG_CIPHER_VALUE) - +#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #endif /*GPG_OPTIONS_H*/ diff --git a/g10/packet.h b/g10/packet.h index 02f701799..f6da15e17 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,5 +1,5 @@ /* packet.h - packet read/write stuff - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -54,14 +54,16 @@ typedef enum { PKT_USER_ID =13, /* user id packet */ PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */ PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */ + PKT_PHOTO_ID =17, /* PGP's photo ID */ + PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */ + PKT_MDC =19, /* manipulaion detection code packet */ PKT_COMMENT =61, /* new comment packet (private) */ - PKT_ENCRYPTED_MDC =62, /* test: encrypted data with MDC */ } pkttype_t; typedef struct packet_struct PACKET; typedef struct { - byte mode; + int mode; byte hash_algo; byte salt[8]; u32 count; @@ -105,7 +107,7 @@ typedef struct { byte version; byte sig_class; /* sig classification, append for MD calculation*/ byte pubkey_algo; /* algorithm used for public key scheme */ - /* (PUBKEY_ALGO_xxx) */ + /* (GCRY_PK_xxx) */ byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ byte *hashed_data; /* all subpackets with hashed data (v4 only) */ byte *unhashed_data; /* ditto for unhashed data */ @@ -165,6 +167,8 @@ typedef struct { ulong stored_at; /* the stream offset where it was stored * by build-packet */ int len; /* length of the name */ + char *photo; /* if this is not NULL, the packet is a photo ID */ + int photolen; /* and the length of the photo */ char name[1]; } PKT_user_id; @@ -178,11 +182,15 @@ typedef struct { typedef struct { u32 len; /* length of encrypted data */ byte new_ctb; /* uses a new CTB */ - byte mdc_method; /* test: > 0: this is is an encrypted_mdc packet */ + 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; } PKT_ring_trust; @@ -212,6 +220,7 @@ struct packet_struct { 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; @@ -246,6 +255,7 @@ typedef enum { 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_PRIV_ADD_SIG =101,/* signatur is also valid for this uid */ SIGSUBPKT_FLAG_CRITICAL=128 @@ -339,7 +349,6 @@ int handle_compressed( void *ctx, PKT_compressed *cd, /*-- encr-data.c --*/ int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek ); -int encrypt_data( PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 886ba4a25..867f93d1d 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1,5 +1,5 @@ /* parse-packet.c - read packets - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,10 +24,10 @@ #include <string.h> #include <assert.h> +#include <gcrypt.h> #include "packet.h" #include "iobuf.h" #include "util.h" -#include <gcrypt.h> #include "filter.h" #include "options.h" #include "main.h" @@ -59,6 +59,8 @@ static int parse_key( IOBUF inp, int pkttype, unsigned long pktlen, byte *hdr, int hdrlen, PACKET *packet ); static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ); +static int parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, + 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, @@ -69,6 +71,8 @@ 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 unsigned short read_16(IOBUF inp) @@ -415,6 +419,10 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, case PKT_USER_ID: rc = parse_user_id(inp, pkttype, pktlen, pkt ); break; + case PKT_PHOTO_ID: + pkt->pkttype = pkttype = PKT_USER_ID; /* must fix it */ + rc = parse_photo_id(inp, pkttype, pktlen, pkt); + break; case PKT_OLD_COMMENT: case PKT_COMMENT: rc = parse_comment(inp, pkttype, pktlen, pkt); @@ -433,6 +441,9 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, 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; default: skip_packet(inp, pkttype, pktlen); break; @@ -803,6 +814,13 @@ dump_sig_subpkt( int hashed, int type, int critical, 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_PRIV_ADD_SIG: p = "signs additional user ID"; break; @@ -840,6 +858,10 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type ) if( n < 8 ) /* minimum length needed */ break; return 0; + case SIGSUBPKT_REVOC_REASON: + if( !n ) + break; + return 0; case SIGSUBPKT_PREF_SYM: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: @@ -877,7 +899,7 @@ can_handle_critical( const byte *buffer, size_t n, int type ) case SIGSUBPKT_PREF_COMPR: return 1; - case SIGSUBPKT_POLICY: /* Is enough to show the policy? */ + case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */ default: return 0; } @@ -896,8 +918,12 @@ enum_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, int seq = 0; int reqseq = start? *start: 0; - if( !buffer || reqseq == -1 ) - return NULL; + if( !buffer || reqseq == -1 ) { + /* return some value different from NULL to indicate that + * there is no crtitical bit we do not understand. The caller + * will never use the value. Yes I know, it is an ugly hack */ + return reqtype == SIGSUBPKT_TEST_CRITICAL? (const byte*)&buffer : NULL; + } buflen = (*buffer << 8) | buffer[1]; buffer += 2; while( buflen ) { @@ -1131,8 +1157,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, 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] = gcry_mpi_set_opaque(NULL, - read_rest(inp, pktlen), pktlen*8 ); + sig->data[0] = mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen ); pktlen = 0; } else { @@ -1317,6 +1342,24 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, sk->protect.algo = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.mode = iobuf_get_noeof(inp); pktlen--; sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--; + /* 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 = GPGERR_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: @@ -1332,10 +1375,13 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, 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 S2K %d\n", - sk->protect.s2k.mode ); + printf( "\tunknown %sS2K %d\n", + sk->protect.s2k.mode < 1000? "":"GNU ", + sk->protect.s2k.mode ); rc = GPGERR_INVALID_PACKET; goto leave; } @@ -1388,6 +1434,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, default: sk->protect.ivlen = 8; } + if( sk->protect.s2k.mode == 1001 ) + sk->protect.ivlen = 0; + if( pktlen < sk->protect.ivlen ) { rc = GPGERR_INVALID_PACKET; goto leave; @@ -1408,10 +1457,15 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, * 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( is_v4 && sk->is_protected ) { + if( sk->protect.s2k.mode == 1001 ) { + /* better set some dummy stuff here */ + sk->skey[npkey] = mpi_set_opaque(NULL, gcry_xstrdup("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 (which is the one indexed by npkey) */ + * skey element */ sk->skey[npkey] = gcry_mpi_set_opaque(NULL, read_rest(inp, pktlen), pktlen*8 ); pktlen = 0; @@ -1475,6 +1529,8 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen); packet->pkt.user_id->len = pktlen; + packet->pkt.user_id->photo = NULL; + packet->pkt.user_id->photolen = 0; p = packet->pkt.user_id->name; for( ; pktlen; pktlen--, p++ ) *p = iobuf_get_noeof(inp); @@ -1496,6 +1552,31 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) } +/**************** + * PGP generates a packet of type 17. We assume this is a photo ID and + * simply store it here as a comment packet. + */ +static int +parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) +{ + byte *p; + + packet->pkt.user_id = gcry_xmalloc(sizeof *packet->pkt.user_id + 30); + sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen ); + packet->pkt.user_id->len = strlen(packet->pkt.user_id->name); + + packet->pkt.user_id->photo = gcry_xmalloc(sizeof *packet->pkt.user_id + pktlen); + packet->pkt.user_id->photolen = pktlen; + p = packet->pkt.user_id->photo; + for( ; pktlen; pktlen--, p++ ) + *p = iobuf_get_noeof(inp); + + if( list_mode ) { + printf(":photo_id packet: %s\n", packet->pkt.user_id->name ); + } + return 0; +} + static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) @@ -1624,9 +1705,8 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, ed->new_ctb = new_ctb; ed->mdc_method = 0; if( pkttype == PKT_ENCRYPTED_MDC ) { - /* test: this is the new encrypted_mdc packet */ /* fixme: add some pktlen sanity checks */ - int version, method; + int version; version = iobuf_get_noeof(inp); pktlen--; if( version != 1 ) { @@ -1634,12 +1714,7 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, version); goto leave; } - method = iobuf_get_noeof(inp); pktlen--; - if( method != GCRY_MD_SHA1 ) { - log_error("encrypted_mdc does not use SHA1 method\n" ); - goto leave; - } - ed->mdc_method = method; + ed->mdc_method = GCRY_MD_SHA1; } if( pktlen && pktlen < 10 ) { /* actually this is blocksize+2 */ log_error("packet(%d) too short\n", pkttype); @@ -1662,3 +1737,26 @@ parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, return 0; } + +static int +parse_mdc( IOBUF inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int new_ctb ) +{ + PKT_mdc *mdc; + byte *p; + + mdc = pkt->pkt.mdc= gcry_xmalloc(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"); + goto leave; + } + p = mdc->hash; + for( ; pktlen; pktlen--, p++ ) + *p = iobuf_get_noeof(inp); + + leave: + return 0; +} + diff --git a/g10/passphrase.c b/g10/passphrase.c index 53b2a82a3..24addd072 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -1,5 +1,5 @@ /* passphrase.c - Get a passphrase - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,8 +24,9 @@ #include <string.h> #include <unistd.h> #include <assert.h> -#include "util.h" + #include <gcrypt.h> +#include "util.h" #include "options.h" #include "ttyio.h" #include "keydb.h" @@ -163,9 +164,9 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, tty_printf("\"\n"); if( !get_pubkey( pk, keyid ) ) { + const char *s = gcry_pk_algo_name( pk->pubkey_algo ); tty_printf( _("%u-bit %s key, ID %08lX, created %s"), - nbits_from_pk( pk ), - gcry_pk_algo_name( pk->pubkey_algo ), (ulong)keyid[1], + 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] ) diff --git a/g10/pkclist.c b/g10/pkclist.c index abd75f9cd..8e61ffdd0 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1,5 +1,5 @@ /* pkclist.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,11 +24,10 @@ #include <string.h> #include <errno.h> #include <assert.h> -#include <gcrypt.h> +#include <gcrypt.h> #include "options.h" #include "packet.h" -#include "main.h" #include "errors.h" #include "keydb.h" #include "util.h" @@ -36,6 +35,7 @@ #include "ttyio.h" #include "status.h" #include "i18n.h" +#include "main.h" #define CONTROL_D ('D' - 'A' + 1) @@ -97,6 +97,112 @@ fpr_info( PKT_public_key *pk ) } +/**************** + * 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_data, SIGSUBPKT_REVOC_REASON, + &n, &seq )) ) { + if( !n ) + continue; /* invalid - just skip it */ + + if( *p == 0 ) + text = _("No reason specified"); + else if( *p == 0x01 ) + text = _("Key is superseeded"); + 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 ); + } +} + + +static void +show_revocation_reason( PKT_public_key *pk ) +{ + /* Hmmm, this is not so easy becuase we have to duplicate the code + * used in the trustbd to calculate the keyflags. We need to find + * a clean way to check revocation certificates on keys and signatures. + * And there should be no duplicate code. Because we enter this function + * only when the trustdb toldus, taht we have a revoked key, we could + * simplylook for a revocation cert and display this one, when there is + * only one. Let's try to do this until we have a better solution. + */ + 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( ( 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 ); + } + } + + release_kbnode( keyblock ); +} + static void show_paths( ulong lid, int only_first ) @@ -338,38 +444,53 @@ _("Could not find a valid trust path to the key. Let's see whether we\n" /**************** * Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL - * Returns: true if we trust. + * Returns: true if we trust. Might change the trustlevel */ static int -do_we_trust( PKT_public_key *pk, int trustlevel ) +do_we_trust( PKT_public_key *pk, int *trustlevel ) { int rc; int did_add = 0; + int trustmask = 0; retry: - if( (trustlevel & TRUST_FLAG_REVOKED) ) { + if( (*trustlevel & TRUST_FLAG_REVOKED) ) { log_info(_("key %08lX: key has been revoked!\n"), (ulong)keyid_from_pk( pk, NULL) ); + show_revocation_reason( pk ); if( opt.batch ) return 0; if( !cpr_get_answer_is_yes("revoked_key.override", _("Use this key anyway? ")) ) return 0; + trustmask |= TRUST_FLAG_REVOKED; } - else if( (trustlevel & TRUST_FLAG_SUB_REVOKED) ) { + else 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 ); 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"); + /* The problem with this, is that EXPIRE can't be checked as + * this needs to insert a ne key into the trustdb first and + * we don't want that */ + return 1; } - switch( (trustlevel & TRUST_MASK) ) { + switch( (*trustlevel & TRUST_MASK) ) { case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ rc = insert_trust_record_by_pk( pk ); if( rc ) { @@ -377,11 +498,12 @@ do_we_trust( PKT_public_key *pk, int trustlevel ) gpg_errstr(rc) ); return 0; /* no */ } - rc = check_trust( pk, &trustlevel, NULL, NULL, NULL ); + rc = check_trust( pk, trustlevel, NULL, NULL, NULL ); + *trustlevel &= ~trustmask; if( rc ) log_fatal("trust check after insert failed: %s\n", gpg_errstr(rc) ); - if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED ) { + if( *trustlevel == TRUST_UNKNOWN || *trustlevel == TRUST_EXPIRED ) { log_debug("do_we_trust: oops at %d\n", __LINE__ ); return 0; } @@ -399,7 +521,8 @@ do_we_trust( PKT_public_key *pk, int trustlevel ) else { int quit; - rc = add_ownertrust( pk, &quit, &trustlevel ); + rc = add_ownertrust( pk, &quit, trustlevel ); + *trustlevel &= ~trustmask; if( !rc && !did_add && !quit ) { did_add = 1; goto retry; @@ -445,7 +568,7 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel ) { int rc; - rc = do_we_trust( pk, trustlevel ); + rc = do_we_trust( pk, &trustlevel ); if( (trustlevel & TRUST_FLAG_REVOKED) && !rc ) return 0; @@ -528,10 +651,12 @@ check_signatures_trust( PKT_signature *sig ) 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 ); } 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 ); } @@ -770,7 +895,8 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) else { int trustlevel; - rc = check_trust( pk, &trustlevel, NULL, NULL, NULL ); + rc = check_trust( pk, &trustlevel, pk->namehash, + NULL, NULL ); if( rc ) { log_error("error checking pk of `%s': %s\n", answer, gpg_errstr(rc) ); @@ -844,7 +970,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use )) ) { int trustlevel; - rc = check_trust( pk, &trustlevel, NULL, NULL, NULL ); + rc = check_trust( pk, &trustlevel, pk->namehash, NULL, NULL ); if( rc ) { free_public_key( pk ); pk = NULL; log_error(_("%s: error checking key: %s\n"), diff --git a/g10/plaintext.c b/g10/plaintext.c index f0c01ca8e..e3c7a865c 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -1,5 +1,5 @@ /* plaintext.c - process an plaintext packet - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -107,8 +107,10 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, } if( mfx->md ) gcry_md_putc(mfx->md, c ); - if( c == '\r' ) - continue; /* fixme: this hack might be too simple */ + #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", @@ -152,8 +154,10 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, while( (c = iobuf_get(pt->buf)) != -1 ) { if( mfx->md ) gcry_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", @@ -169,10 +173,10 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int eof; for( eof=0; !eof; ) { /* Why do we check for len < 32768: - * If we won´ we would practically read 2 EOFS but + * 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. - * Always assume EOF if iobuf_read returns less bytes + * So, always assume EOF if iobuf_read returns less bytes * then requested */ int len = iobuf_read( pt->buf, buffer, 32768 ); if( len == -1 ) @@ -217,6 +221,8 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, if( !state ) { if( c == '\r' ) state = 1; + else if( c == '\n' ) + state = 2; else gcry_md_putc(mfx->md, c ); } diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 587847aeb..2019d0301 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -1,5 +1,5 @@ /* pubkey-enc.c - public key encoded packet handling - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -23,14 +23,15 @@ #include <stdlib.h> #include <string.h> #include <assert.h> -#include "util.h" + #include <gcrypt.h> +#include "util.h" #include "packet.h" -#include "main.h" #include "keydb.h" #include "trustdb.h" #include "status.h" #include "options.h" +#include "main.h" #include "i18n.h" static int get_it( PKT_pubkey_enc *k, @@ -103,7 +104,6 @@ pk_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) } - /**************** * Get the session key from a pubkey enc paket and return * it in DEK, which should have been allocated in secure memory. @@ -169,7 +169,7 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) int rc; MPI plain_dek = NULL; byte *frame = NULL; - unsigned n; + unsigned int n; size_t nframe; u16 csum, csum2; @@ -199,7 +199,7 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) * DEK is the encryption key (session key) with length k * CSUM */ - if( (opt.debug & DBG_CIPHER_VALUE) ) + if( DBG_CIPHER ) log_hexdump("DEK frame:", frame, nframe ); n=0; if( n + 7 > nframe ) @@ -219,10 +219,14 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) dek->keylen = nframe - (n+1) - 2; dek->algo = frame[n++]; - if( dek->algo == GCRY_CIPHER_IDEA ) + if( dek->algo == GCRY_CIPHER_IDEA ) write_status(STATUS_RSA_OR_IDEA); rc = openpgp_cipher_test_algo( dek->algo ); if( rc ) { + if( !opt.quiet && rc == GPGERR_CIPHER_ALGO ) { + log_info(_("cipher algorithm %d is unknown or disabled\n"), + dek->algo); + } dek->algo = 0; goto leave; } @@ -241,9 +245,9 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) rc = GPGERR_WRONG_SECKEY; goto leave; } - if( (opt.debug & DBG_CIPHER_VALUE) ) + if( DBG_CIPHER ) log_hexdump("DEK is:", dek->key, dek->keylen ); - /* check that the algo is in the preferences */ + /* check that the algo is in the preferences and whether it has expired */ { PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); if( (rc = get_pubkey( pk, keyid )) ) @@ -262,10 +266,25 @@ get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) "NOTE: cipher algorithm %d not found in preferences\n"), dek->algo ); } + + + if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) { + log_info(_("NOTE: secret key %08lX expired at %s\n"), + (ulong)keyid[1], asctimestamp( pk->expiredate) ); + } + + /* FIXME: check wheter the key has been revoked and display + * the revocation reason. Actually the user should know this himself, + * but the sender might not know already and therefor the user + * should get a notice that an revoked key has been used to decode + * the message. The user can than watch out for snakes send by + * one of those Eves outside his paradise :-) + */ free_public_key( pk ); rc = 0; } + leave: mpi_release(plain_dek); gcry_free(frame); diff --git a/g10/revoke.c b/g10/revoke.c index b1a50e786..4abd5edd7 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -1,5 +1,5 @@ /* revoke.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,6 +24,7 @@ #include <string.h> #include <errno.h> #include <assert.h> +#include <ctype.h> #include "options.h" #include "packet.h" @@ -37,6 +38,38 @@ #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->desc ) { + ud = native_to_utf8( reason->desc ); + buflen += strlen(ud); + } + buffer = gcry_xmalloc( buflen ); + *buffer = reason->code; + if( ud ) { + memcpy(buffer+1, ud, strlen(ud) ); + gcry_free( ud ); + } + + build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen ); + gcry_free( buffer ); + return 0; +} + + + /**************** * Generate a revocation certificate for UNAME */ @@ -55,6 +88,7 @@ gen_revoke( const char *uname ) KBNODE keyblock = NULL; KBNODE node; KBPOS kbpos; + struct revocation_reason_info *reason = NULL; if( opt.batch ) { log_error(_("sorry, can't do this in batch mode\n")); @@ -62,19 +96,6 @@ gen_revoke( const char *uname ) } - /* FIXME: ask for the reason of revocation - 0x00 - No reason specified (key revocations or cert revocations) - Does not make sense! - - 0x01 - Key is superceded (key revocations) - 0x02 - Key material has been compromised (key revocations) - 0x03 - Key is no longer used (key revocations) - 0x20 - User id information is no longer valid (cert revocations) - - Following the revocation code is a string of octets which gives - information about the reason for revocation in human-readable form - */ - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); init_packet( &pkt ); @@ -136,6 +157,13 @@ gen_revoke( const char *uname ) goto leave; } + /* get the reason for the revocation */ + reason = ask_revocation_reason( 1, 0, 1 ); + if( !reason ) { /* user decided to cancel */ + rc = 0; + goto leave; + } + switch( is_secret_key_protected( sk ) ) { case -1: log_error(_("unknown protection algorithm\n")); @@ -163,7 +191,9 @@ gen_revoke( const char *uname ) iobuf_push_filter( out, armor_filter, &afx ); /* create it */ - rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, NULL, NULL); + rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, + revocation_reason_build_cb, + reason ); if( rc ) { log_error(_("make_keysig_packet failed: %s\n"), gpg_errstr(rc)); goto leave; @@ -198,193 +228,127 @@ gen_revoke( const char *uname ) iobuf_cancel(out); else iobuf_close(out); + release_revocation_reason_info( reason ); return rc; } -#if 0 /* The code is not complete but anyway, now we use */ - /* the edit menu to revoke signature */ -/**************** - * Return true if there is already a revocation signature for KEYID - * in KEYBLOCK at point node. - */ -static int -already_revoked( const KBNODE keyblock, const KBNODE node, u32 *keyid ) ) { -{ - const KBNODE n = find_prev_kbnode( keyblock, node, PKT_USER_ID ); - - for( ; n; n = n->next ) { - PKT_signature *sig; - if( n->pkt->pkttype == PKT_SIGNATURE - && (sig = node->pkt->pkt.signature)->sig_class == 0x30 - && sig->keyid[0] == keyid[0] - && sig->keyid[1] == keyid[1] ) - return 1; - } - else if( n->pkt->pkttype == PKT_USER_ID - break; - else if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY - break; - } - return 0; -} -/**************** - * Ask whether the signature should be revoked. If the user commits this, - * flag bit 0 is set. - */ -static void -ask_revoke_sig( KBNODE keyblock, KBNODE node, PKT_signature *sig ) ) { -{ - 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, 0 ); - tty_printf(_("\"\nsigned with your key %08lX at %s\n"), - sig->keyid[1], datestr_from_sig(sig) ); - - if( cpr_get_answer_is_yes("ask_revoke_sig.one", - _("Create a revocation certificate for this signature? (y/N)")) ) { - node->flag |= 1; - } -} - -/**************** - * Generate a signature revocation certificate for UNAME - */ -int -gen_sig_revoke( const char *uname ) +struct revocation_reason_info * +ask_revocation_reason( int key_rev, int cert_rev, int hint ) { - int rc = 0; - armor_filter_context_t afx; - compress_filter_context_t zfx; - PACKET pkt; - IOBUF out = NULL; - KBNODE keyblock = NULL; - KBNODE node; - KBPOS kbpos; - int uidchg; - - if( opt.batch ) { - log_error(_("sorry, can't do this in batch mode\n")); - return GPGERR_GENERAL; - } - - - memset( &afx, 0, sizeof afx); - memset( &zfx, 0, sizeof zfx); - init_packet( &pkt ); - - - /* get the keyblock */ - rc = find_keyblock_byname( &kbpos, uname ); - if( rc ) { - log_error(_("public key for user `%s' not found\n"), uname ); - goto leave; - } - - /* read the keyblock */ - rc = read_keyblock( &kbpos, &keyblock ); - if( rc ) { - log_error(_("error reading the certificate: %s\n"), gpg_errstr(rc) ); - goto leave; - } - - /* get the keyid from the keyblock */ - node = find_kbnode( keyblock, PKT_PUBLIC_KEY ); - if( !node ) { - log_error(_("Oops; public key lost!\n")); - rc = GPGERR_GENERAL; - goto leave; - } - - if( (rc = open_outfile( NULL, 0, &out )) ) - goto leave; - - if( opt.armor ) { - afx.what = 1; - iobuf_push_filter( out, armor_filter, &afx ); - } + int code; + char *description = NULL; + struct revocation_reason_info *reason; + const char *text_1 = _("Key has been compromised"); + const char *text_2 = _("Key is superseded"); + const char *text_3 = _("Key is no longer used"); + const char *text_4 = _("User ID is non longer valid"); + const char *code_text = NULL; + + do { + gcry_free(description); + description = NULL; + + tty_printf(_("Please select the reason for the revocation:\n")); + 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( " 0 = %s\n", _("Cancel") ); + if( hint ) + tty_printf(_("(Probably you want to select %d here)\n"), hint ); + + for(code = 0; !code;) { + int n; + char *answer = cpr_get("ask_revocation_reason.code", + _("Your decision? ")); + trim_spaces( answer ); + cpr_kill_prompt(); + if( *answer == 'q' || *answer == 'Q' ) + n = 0; + else if( !isdigit( *answer ) ) + n = -1; + else if( hint && !*answer ) + n = hint; + else + n = atoi(answer); + gcry_free(answer); + if( !n ) + return NULL; /* cancel */ + 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 non longer valid */ + code_text = text_4; + } + else + tty_printf(_("Invalid selection.\n")); + } - /* Now walk over all signatures which we did with one of - * our secret keys. Hmmm: Should we check for duplicate signatures */ - clear_kbnode_flags( flags ); - for( node = keyblock; node; node = node->next ) { - PKT_signature *sig; - if( node->pkt->pkttype == PKT_SIGNATURE - && ((sig = node->pkt->pkt.signature)->sig_class&~3) == 0x10 - && seckey_available( sig->keyid ) - && !already_revoked( keyblock, node, sig->keyid ) ) { ) { - ask_revoke_sig( keyblock, node, sig ) + 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 ) { + gcry_free(answer); + break; + } + + { + char *p = make_printable_string( answer, strlen(answer), 0 ); + gcry_free(answer); + answer = p; + } + + if( !description ) + description = gcry_xstrdup(answer); + else { + char *p = gcry_xmalloc( strlen(description) + strlen(answer) + 2 ); + strcpy(stpcpy(stpcpy( p, description),"\n"),answer); + gcry_free(description); + description = p; + } + gcry_free(answer); } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY - break; - } + tty_printf(_("Reason for revocation: %s\n"), code_text ); + if( !description ) + tty_printf(_("(No description given)\n") ); + else + tty_printf("%s\n", description ); - for( node = keyblock; node; node = node->next ) { { - if( (node->flag & 1) ) - break; - } - if( !node ) { - log_info(_("nothing to revoke\n")); - iobuf_cancel(out); - out = NULL; - goto leave; - } + } while( !cpr_get_answer_is_yes("ask_revocation_reason.okay", + _("Is this okay? ")) ); - init_packet( &pkt ); - pkt.pkttype = PKT_PUBLIC_KEY; - pkt.pkt.public_key = keyblock->pkt->pkt.public_key; - rc = build_packet( out, &pkt ); - if( rc ) { - log_error(_("build_packet failed: %s\n"), gpg_errstr(rc) ); - goto leave; - } - uidchg = 1; - for( node = keyblock; node; node = node->next ) { - if( node->pkt->pkttype == PKT_USER_ID ) - uidchg = 1; - if( !(node->flag & 1) ) - continue; - - if( uidchg ) { - /* create a user ID packet */ - ....... - uidchg = 0; - } + reason = gcry_xmalloc( sizeof *reason ); + reason->code = code; + reason->desc = description; + return reason; +} - /* create it */ - rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x30, 0, NULL, NULL); - if( rc ) { - log_error(_("make_keysig_packet failed: %s\n"), gpg_errstr(rc)); - goto leave; - } - init_packet( &pkt ); - pkt.pkttype = PKT_SIGNATURE; - pkt.pkt.signature = sig; - - rc = build_packet( out, &pkt ); - if( rc ) { - log_error(_("build_packet failed: %s\n"), gpg_errstr(rc) ); - goto leave; - } +void +release_revocation_reason_info( struct revocation_reason_info *reason ) +{ + if( reason ) { + gcry_free( reason->desc ); + gcry_free( reason ); } - - leave: - release_kbnode( keyblock ); - if( !out ) - ; - else if( rc ) - iobuf_cancel(out); - else - iobuf_close(out); - return rc; } -#endif /* unused code */ diff --git a/g10/ringedit.c b/g10/ringedit.c index 2fa79fd74..3a29654d2 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -1,5 +1,5 @@ /* ringedit.c - Function for key ring editing - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -51,9 +51,10 @@ #ifdef HAVE_LIBGDBM #include <gdbm.h> #endif + +#include <gcrypt.h> #include "util.h" #include "packet.h" -#include <gcrypt.h> #include "iobuf.h" #include "keydb.h" #include "host2net.h" @@ -63,10 +64,6 @@ #include "kbx.h" -#ifdef MKDIR_TAKES_ONE_ARG -# undef mkdir -# define mkdir(a,b) mkdir(a) -#endif struct resource_table_struct { @@ -191,7 +188,6 @@ enum_keyblock_resources( int *sequence, int secret ) } - /**************** * Register a resource (which currently may only be a keyring file). * The first keyring which is added by this function is @@ -312,24 +308,13 @@ add_keyblock_resource( const char *url, int force, int secret ) *last_slash_in_filename = 0; if( access(filename, F_OK) ) { - if( strlen(filename) >= 7 - && !strcmp(filename+strlen(filename)-7, "/.gnupg") ) { - if( mkdir(filename, S_IRUSR|S_IWUSR|S_IXUSR) ) - { - log_error( _("%s: can't create directory: %s\n"), - filename, strerror(errno)); - rc = GPGERR_OPEN_FILE; - goto leave; - } - else if( !opt.quiet ) - log_info( _("%s: directory created\n"), filename ); - copy_options_file( filename ); - } - else - { - rc = GPGERR_OPEN_FILE; - goto leave; - } + /* on the first time we try to create the default homedir and + * in this case the process will be terminated, so that on the + * next invocation it can read the options file in on startup + */ + try_make_homedir( filename ); + rc = GPGERR_OPEN_FILE; + goto leave; } *last_slash_in_filename = '/'; @@ -363,7 +348,6 @@ add_keyblock_resource( const char *url, int force, int secret ) #endif break; - #ifdef HAVE_LIBGDBM case rt_GDBM: resource_table[i].dbf = gdbm_open( filename, 0, @@ -457,6 +441,35 @@ get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos ) } +/**************** + * Return the filename of the firstkeyblock resource which is intended + * for write access. This will either be the default resource or in + * case this is not writable one of the others. If no writable is found, + * the default filename in the homedirectory will be returned. + * Caller must free, will never return NULL. + */ +char * +get_writable_keyblock_file( int secret ) +{ + int i = secret? default_secret_resource : default_public_resource; + + if( resource_table[i].used && !resource_table[i].secret == !secret ) { + if( !access( resource_table[i].fname, R_OK|W_OK ) ) { + return gcry_xstrdup( resource_table[i].fname ); + } + } + for(i=0; i < MAX_RESOURCES; i++ ) { + if( resource_table[i].used && !resource_table[i].secret == !secret ) { + if( !access( resource_table[i].fname, R_OK|W_OK ) ) { + return gcry_xstrdup( resource_table[i].fname ); + } + } + } + /* Assume the home dir is always writable */ + return make_filename(opt.homedir, secret? "secring.gpg" + : "pubring.gpg", NULL ); +} + /**************** * Search a keyblock which starts with the given packet and puts all diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index bef75507e..ab09b8f4d 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -1,5 +1,5 @@ /* seckey-cert.c - secret key certificate packet handling - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -33,6 +33,7 @@ #include "i18n.h" #include "status.h" + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. @@ -82,9 +83,11 @@ pk_check_secret_key( int algo, MPI *skey ) return rc; } + static int do_check( PKT_secret_key *sk ) { + byte *buffer; u16 csum=0; int i, res; unsigned nbytes; @@ -95,6 +98,10 @@ do_check( PKT_secret_key *sk ) GCRY_CIPHER_HD cipher_hd=NULL; PKT_secret_key *save_sk; + if( sk->protect.s2k.mode == 1001 ) { + log_info(_("secret key parts are not available\n")); + return GPGERR_GENERAL; + } if( sk->protect.algo == GCRY_CIPHER_NONE ) BUG(); if( openpgp_cipher_test_algo( sk->protect.algo ) ) { @@ -112,6 +119,7 @@ do_check( PKT_secret_key *sk ) } dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo, &sk->protect.s2k, 0 ); + /* Hmmm: Do we use sync mode here even for Twofish? */ if( !(cipher_hd = gcry_cipher_open( sk->protect.algo, GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE @@ -198,7 +206,8 @@ do_check( PKT_secret_key *sk ) free_secret_key( save_sk ); return GPGERR_BAD_PASS; } - /* the checksum may fail, so we also check the key itself */ + /* the checksum may be correct in some cases, + * so we also check the key itself */ res = pk_check_secret_key( sk->pubkey_algo, sk->skey ); if( res ) { copy_secret_key( sk, save_sk ); @@ -300,8 +309,6 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) ) { BUG(); } - - rc = gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen ); if( rc == GCRYERR_WEAK_KEY ) { log_info(_("WARNING: Weak key detected" @@ -316,18 +323,19 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) if( blocksize != 8 && blocksize != 16 ) log_fatal("unsupported blocksize %d\n", blocksize ); sk->protect.ivlen = blocksize; + assert( sk->protect.ivlen <= DIM(sk->protect.iv) ); } - - assert( sk->protect.ivlen <= DIM(sk->protect.iv) ); gcry_randomize(sk->protect.iv, sk->protect.ivlen, - GCRY_STRONG_RANDOM); + GCRY_STRONG_RANDOM); gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen ); + #warning FIXME: replace set/get buffer if( sk->version >= 4 ) { - #define NMPIS (GNUPG_MAX_NSKEY - GNUPG_MAX_NPKEY) - byte *bufarr[NMPIS]; - unsigned narr[NMPIS]; - unsigned nbits[NMPIS]; + /* FIXME: There is a bug in this function for all algorithms + * where the secret MPIs are more than 1 */ + byte *bufarr[GNUPG_MAX_NSKEY]; + unsigned narr[GNUPG_MAX_NSKEY]; + unsigned nbits[GNUPG_MAX_NSKEY]; int ndata=0; byte *p, *data; @@ -342,13 +350,13 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) nbits[j] = gcry_mpi_get_nbits( sk->skey[i] ); ndata += narr[j] + 2; } - for( ; j < NMPIS; j++ ) + for( ; j < GNUPG_MAX_NSKEY; j++ ) bufarr[j] = NULL; ndata += 2; /* for checksum */ data = gcry_xmalloc_secure( ndata ); p = data; - for(j=0; j < NMPIS && bufarr[j]; j++ ) { + for(j=0; j < GNUPG_MAX_NSKEY && bufarr[j]; j++ ) { p[0] = nbits[j] >> 8 ; p[1] = nbits[j]; p += 2; @@ -356,7 +364,6 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) p += narr[j]; gcry_free(bufarr[j]); } - #undef NMPIS csum = checksum( data, ndata-2); sk->csum = csum; *p++ = csum >> 8; diff --git a/g10/seskey.c b/g10/seskey.c index 996118e0f..aa2a1511c 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -1,5 +1,5 @@ /* seskey.c - make sesssion keys etc. - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -152,7 +152,7 @@ encode_session_key( DEK *dek, unsigned nbits ) static MPI do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits, - const byte *asn, size_t asnlen ) + const byte *asn, size_t asnlen, int v3compathack ) { int nframe = (nbits+7) / 8; byte *frame; @@ -165,7 +165,7 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits, /* We encode the MD in this way: * - * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) + * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) * * PAD consists of FF bytes. */ @@ -173,7 +173,7 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits, : gcry_xmalloc( nframe ); n = 0; frame[n++] = 0; - frame[n++] = algo; + frame[n++] = v3compathack? algo : 1; /* block type */ i = nframe - len - asnlen -3 ; assert( i > 1 ); memset( frame+n, 0xff, i ); n += i; @@ -188,8 +188,15 @@ do_encode_md( GCRY_MD_HD md, int algo, size_t len, unsigned nbits, } +/**************** + * Encode a message digest into an MPI. + * v3compathack is used to work around a bug in old GnuPG versions + * which did put the algo identifier inseatd of the block type 1 into + * the encoded value. setting this vare force the old behaviour. + */ MPI -encode_md_value( int pubkey_algo, GCRY_MD_HD md, int hash_algo, unsigned nbits ) +encode_md_value( int pubkey_algo, GCRY_MD_HD md, int hash_algo, + unsigned nbits, int v3compathack ) { int algo = hash_algo? hash_algo : gcry_md_get_algo(md); MPI frame; @@ -211,9 +218,10 @@ encode_md_value( int pubkey_algo, GCRY_MD_HD md, int hash_algo, unsigned nbits ) if( gcry_md_algo_info( algo, GCRYCTL_GET_ASNOID, asn, &asnlen ) ) BUG(); frame = do_encode_md( md, algo, gcry_md_get_algo_dlen( algo ), - nbits, asn, asnlen ); + nbits, asn, asnlen, v3compathack ); gcry_free( asn ); } return frame; } + diff --git a/g10/sig-check.c b/g10/sig-check.c index bd68d44d7..f12cfa6d3 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -1,5 +1,5 @@ /* sig-check.c - Check a signature - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -31,6 +31,7 @@ #include "main.h" #include "status.h" #include "i18n.h" +#include "options.h" struct cmp_help_context_s { PKT_signature *sig; @@ -39,9 +40,10 @@ struct cmp_help_context_s { static int do_signature_check( PKT_signature *sig, GCRY_MD_HD digest, - u32 *r_expire ); + u32 *r_expiredate, int *r_expired ); static int do_check( PKT_public_key *pk, PKT_signature *sig, - GCRY_MD_HD digest ); + GCRY_MD_HD digest, int *r_expired ); + /**************** @@ -131,11 +133,13 @@ int signature_check( PKT_signature *sig, GCRY_MD_HD digest ) { u32 dummy; - return do_signature_check( sig, digest, &dummy ); + int dum2; + return do_signature_check( sig, digest, &dummy, &dum2 ); } static int -do_signature_check( PKT_signature *sig, GCRY_MD_HD digest, u32 *r_expire ) +do_signature_check( PKT_signature *sig, GCRY_MD_HD digest, + u32 *r_expiredate, int *r_expired ) { PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); int rc=0; @@ -143,12 +147,12 @@ do_signature_check( PKT_signature *sig, GCRY_MD_HD digest, u32 *r_expire ) if( is_RSA(sig->pubkey_algo) ) write_status(STATUS_RSA_OR_IDEA); - *r_expire = 0; + *r_expiredate = 0; if( get_pubkey( pk, sig->keyid ) ) rc = GPGERR_NO_PUBKEY; else { - *r_expire = pk->expiredate; - rc = do_check( pk, sig, digest ); + *r_expiredate = pk->expiredate; + rc = do_check( pk, sig, digest, r_expired ); } free_public_key( pk ); @@ -199,97 +203,6 @@ do_signature_check( PKT_signature *sig, GCRY_MD_HD digest, u32 *r_expire ) } -#if 0 /* not anymore used */ -/**************** - * Check the MDC which is contained in SIG. - * The GCRY_MD_HD should be currently open, so that this function - * is able to append some data, before finalizing the digest. - */ -int -mdc_kludge_check( PKT_signature *sig, GCRY_MD_HD digest ) -{ - int rc=0; - - if( (rc=check_digest_algo(sig->digest_algo)) ) - return rc; - - /* make sure the digest algo is enabled (in case of a detached mdc??) */ - md_enable( digest, sig->digest_algo ); - - /* complete the digest */ - if( sig->version >= 4 ) - gcry_md_putc( digest, sig->version ); - gcry_md_putc( digest, sig->sig_class ); - if( sig->version < 4 ) { - u32 a = sig->timestamp; - gcry_md_putc( digest, (a >> 24) & 0xff ); - gcry_md_putc( digest, (a >> 16) & 0xff ); - gcry_md_putc( digest, (a >> 8) & 0xff ); - gcry_md_putc( digest, a & 0xff ); - } - else { - byte buf[6]; - size_t n; - gcry_md_putc( digest, sig->pubkey_algo ); - gcry_md_putc( digest, sig->digest_algo ); - if( sig->hashed_data ) { - n = (sig->hashed_data[0] << 8) | sig->hashed_data[1]; - gcry_md_write( digest, sig->hashed_data, n+2 ); - n += 6; - } - else - 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; - gcry_md_write( digest, buf, 6 ); - } - md_final( digest ); - - rc = GPGERR_BAD_SIGN; - { const byte *s1 = md_read( digest, sig->digest_algo ); - int s1len = md_digest_length( sig->digest_algo ); - - log_hexdump( "MDC calculated", s1, s1len ); - - if( !sig->data[0] ) - log_debug("sig_data[0] is NULL\n"); - else { - unsigned s2len; - char *s2; - - if( gcry_mpi_print( GCRYMPI_FMT_USG, &s2, &s2len, sig->data[0] )) - BUG(); - - log_hexdump( "MDC stored ", s2, s2len ); - - if( s2len != s1len ) - log_debug("MDC check: len differ: %d/%d\n", s1len, s2len); - else if( memcmp( s1, s2, s1len ) ) - log_debug("MDC check: hashs differ\n"); - else - rc = 0; - gcry_free(s2); - } - } - - if( !rc && sig->flags.unknown_critical ) { - log_info(_("assuming bad MDC due to an unknown critical bit\n")); - rc = GPGERR_BAD_SIGN; - } - sig->flags.checked = 1; - sig->flags.valid = !rc; - - /* FIXME: check that we are actually in an encrypted packet */ - - return rc; -} -#endif - /**************** * This function gets called by pubkey_verify() if the algorithm needs it. */ @@ -366,16 +279,18 @@ cmp_help( void *opaque, MPI result ) static int -do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest ) +do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest, + int *r_expired ) { MPI result = NULL; int rc=0; struct cmp_help_context_s ctx; u32 cur_time; + *r_expired = 0; if( pk->version == 4 && pk->pubkey_algo == GCRY_PK_ELG_E ) { log_info(_("this is a PGP generated " - "ElGamal key which is NOT secure for signatures!\n")); + "ElGamal key which is NOT secure for signatures!\n")); return GPGERR_PUBKEY_ALGO; } @@ -385,7 +300,8 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest ) ? _("public key is %lu second newer than the signature\n") : _("public key is %lu seconds newer than the signature\n"), d ); - return GPGERR_TIME_CONFLICT; /* pubkey newer than signature */ + if( !opt.ignore_time_conflict ) + return GPGERR_TIME_CONFLICT; /* pubkey newer than signature */ } cur_time = make_timestamp(); @@ -395,13 +311,15 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest ) "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); - return GPGERR_TIME_CONFLICT; + if( !opt.ignore_time_conflict ) + return GPGERR_TIME_CONFLICT; } if( pk->expiredate && pk->expiredate < cur_time ) { log_info(_("NOTE: signature key expired %s\n"), asctimestamp( pk->expiredate ) ); write_status(STATUS_SIGEXPIRED); + *r_expired = 1; } @@ -448,13 +366,24 @@ do_check( PKT_public_key *pk, PKT_signature *sig, GCRY_MD_HD digest ) gcry_md_final( digest ); result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo, - gcry_mpi_get_nbits(pk->pkey[0])); - + gcry_mpi_get_nbits(pk->pkey[0]), 0); ctx.sig = sig; ctx.md = digest; rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey, cmp_help, &ctx ); mpi_release( result ); + if( (opt.emulate_bugs & EMUBUG_MDENCODE) + && rc == GPGERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) { + /* In this case we try again because old GnuPG versions didn't encode + * the hash right. There is no problem with DSA however */ + result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo, + gcry_mpi_get_nbits(pk->pkey[0]), (sig->version < 5) ); + ctx.sig = sig; + ctx.md = digest; + rc = pk_verify( pk->pubkey_algo, result, sig->data, pk->pkey, + cmp_help, &ctx ); + } + if( !rc && sig->flags.unknown_critical ) { log_info(_("assuming bad signature due to an unknown critical bit\n")); rc = GPGERR_BAD_SIGN; @@ -472,16 +401,30 @@ hash_uid_node( KBNODE unode, GCRY_MD_HD md, PKT_signature *sig ) PKT_user_id *uid = unode->pkt->pkt.user_id; assert( unode->pkt->pkttype == PKT_USER_ID ); - 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; - gcry_md_write( md, buf, 5 ); + if( uid->photo ) { + if( sig->version >=4 ) { + byte buf[5]; + buf[0] = 0xd1; /* packet of type 17 */ + buf[1] = uid->photolen >> 24; /* always use 4 length bytes */ + buf[2] = uid->photolen >> 16; + buf[3] = uid->photolen >> 8; + buf[4] = uid->photolen; + gcry_md_write( md, buf, 5 ); + } + gcry_md_write( md, uid->photo, uid->photolen ); + } + 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; + gcry_md_write( md, buf, 5 ); + } + gcry_md_write( md, uid->name, uid->len ); } - gcry_md_write( md, uid->name, uid->len ); } /**************** @@ -493,11 +436,13 @@ int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ) { u32 dummy; - return check_key_signature2(root, node, is_selfsig, &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_expire) +check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, + u32 *r_expiredate, int *r_expired ) { GCRY_MD_HD md; PKT_public_key *pk; @@ -507,7 +452,8 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, u32 *r_expire) if( is_selfsig ) *is_selfsig = 0; - *r_expire = 0; + *r_expiredate = 0; + *r_expired = 0; assert( node->pkt->pkttype == PKT_SIGNATURE ); assert( root->pkt->pkttype == PKT_PUBLIC_KEY ); @@ -528,7 +474,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, u32 *r_expire) if( !(md = gcry_md_open( algo, 0 )) ) BUG(); hash_public_key( md, pk ); - rc = do_check( pk, sig, md ); + rc = do_check( pk, sig, md, r_expired ); gcry_md_close(md); } else if( sig->sig_class == 0x28 ) { /* subkey revocation */ @@ -539,7 +485,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, u32 *r_expire) BUG(); hash_public_key( md, pk ); hash_public_key( md, snode->pkt->pkt.public_key ); - rc = do_check( pk, sig, md ); + rc = do_check( pk, sig, md, r_expired ); gcry_md_close(md); } else { @@ -562,7 +508,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, u32 *r_expire) BUG(); hash_public_key( md, pk ); hash_public_key( md, snode->pkt->pkt.public_key ); - rc = do_check( pk, sig, md ); + rc = do_check( pk, sig, md, r_expired ); gcry_md_close(md); } else { @@ -584,10 +530,11 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig, u32 *r_expire) if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) { if( is_selfsig ) *is_selfsig = 1; - rc = do_check( pk, sig, md ); + rc = do_check( pk, sig, md, r_expired ); + } + else { + rc = do_signature_check( sig, md, r_expiredate, r_expired ); } - else - rc = do_signature_check( sig, md, r_expire ); gcry_md_close(md); } else { diff --git a/g10/sign.c b/g10/sign.c index bb2d2290c..9d0c203b8 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1,5 +1,5 @@ /* sign.c - sign data - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -36,9 +36,16 @@ #include "filter.h" #include "ttyio.h" #include "trustdb.h" +#include "status.h" #include "i18n.h" +#ifdef HAVE_DOSISH_SYSTEM + #define LF "\r\n" +#else + #define LF "\n" +#endif + /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. @@ -163,7 +170,8 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); - return GPGERR_TIME_CONFLICT; + if( !opt.ignore_time_conflict ) + return GPGERR_TIME_CONFLICT; } @@ -178,7 +186,7 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; frame = encode_md_value( sk->pubkey_algo, md, - digest_algo, gcry_mpi_get_nbits(sk->skey[0])); + digest_algo, gcry_mpi_get_nbits(sk->skey[0]), 0 ); rc = pk_sign( sk->pubkey_algo, sig->data, frame, sk->skey ); mpi_release(frame); if( rc ) @@ -240,6 +248,25 @@ only_old_style( SK_LIST sk_list ) } +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 ); +} + /**************** * Sign the files whose names are in FILENAME. @@ -521,6 +548,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, sig->sig_class = opt.textmode && !outfile? 0x01 : 0x00; md = gcry_md_copy( mfx.md ); + if( !md ) + BUG(); if( sig->version >= 4 ) { build_sig_subpkt_from_sig( sig ); @@ -573,12 +602,16 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; rc = build_packet( out, &pkt ); + if( !rc && is_status_enabled() ) { + print_status_sig_created ( sk, sig, detached ? 'D':'S'); + } free_packet( &pkt ); if( rc ) log_error("build signature packet failed: %s\n", gpg_errstr(rc) ); } if( rc ) goto leave; + } @@ -640,7 +673,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) else if( (rc = open_outfile( fname, 1, &out )) ) goto leave; - iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----\n" ); + 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; @@ -683,13 +716,15 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) } - if( !(textmd = gcry_md_open(0, 0)) ) + textmd = gcry_md_open(0, 0); + if( !textmd ) BUG(); for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) { PKT_secret_key *sk = sk_rover->sk; gcry_md_enable(textmd, hash_for(sk->pubkey_algo)); } - /*md_start_debug( textmd, "sign" );*/ + if ( DBG_HASHING ) + gcry_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 */ @@ -717,6 +752,8 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) sig->sig_class = 0x01; md = gcry_md_copy( textmd ); + if( !md ) + BUG(); if( sig->version >= 4 ) { build_sig_subpkt_from_sig( sig ); gcry_md_putc( md, sig->version ); @@ -768,6 +805,9 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) pkt.pkttype = PKT_SIGNATURE; pkt.pkt.signature = sig; rc = build_packet( out, &pkt ); + if( !rc && is_status_enabled() ) { + print_status_sig_created ( sk, sig, 'C'); + } free_packet( &pkt ); if( rc ) log_error("build signature packet failed: %s\n", gpg_errstr(rc) ); diff --git a/g10/signal.c b/g10/signal.c index fcb012e02..f61b0a8f8 100644 --- a/g10/signal.c +++ b/g10/signal.c @@ -1,5 +1,5 @@ /* signal.c - signal handling - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -27,9 +27,9 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "options.h" #include "errors.h" -#include <gcrypt.h> #include "util.h" #include "main.h" #include "ttyio.h" @@ -59,14 +59,23 @@ got_fatal_signal( int sig ) caught_fatal_sig = 1; gcry_control( GCRYCTL_TERM_SECMEM ); - #ifdef IS_DEVELOPMENT_VERSION + /* better don't transtale these messages */ write(2, "\n", 1 ); s = log_get_name(); if( s ) write(2, s, strlen(s) ); write(2, ": ", 2 ); s = get_signal_name(sig); write(2, s, strlen(s) ); write(2, " caught ... exiting\n", 21 ); + + #ifndef HAVE_DOSISH_SYSTEM + { /* reset action to default action and raise signal again */ + struct sigaction nact; + nact.sa_handler = SIG_DFL; + sigemptyset( &nact.sa_mask ); + nact.sa_flags = 0; + sigaction( sig, &nact, NULL); + } #endif - exit(8); /* Hmmm, for some reasons rais2e does not work */ + raise( sig ); } diff --git a/g10/skclist.c b/g10/skclist.c index a0d69a49e..8fcb22aba 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -1,5 +1,5 @@ /* skclist.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -66,7 +66,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock, } else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo, use)) ) { SK_LIST r; - if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN) + if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN ) && sk->pubkey_algo == GCRY_PK_ELG_E ) { log_info("this is a PGP generated " "ElGamal key which is NOT secure for signatures!\n"); diff --git a/g10/status.c b/g10/status.c index 3eeec4648..c35a8adba 100644 --- a/g10/status.c +++ b/g10/status.c @@ -1,5 +1,5 @@ /* status.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -38,12 +38,13 @@ #include <sys/mman.h> #endif #endif + +#include <gcrypt.h> #include "util.h" #include "status.h" #include "ttyio.h" #include "options.h" #include "main.h" -#include <gcrypt.h> #include "i18n.h" static int fd = -1; @@ -54,10 +55,32 @@ static int fd = -1; 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 ); +} + + void set_status_fd ( int newfd ) { fd = newfd; + if ( fd != -1 ) { + #if 0 + #warning fixme - progress functions + register_primegen_progress ( progress_cb, "primegen" ); + register_pk_dsa_progress ( progress_cb, "pk_dsa" ); + register_pk_elg_progress ( progress_cb, "pk_elg" ); + #endif + } } int @@ -96,6 +119,10 @@ write_status_text ( int no, const char *text) case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL\n"; break; case STATUS_TRUST_FULLY : s = "TRUST_FULLY\n"; break; case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE\n"; break; + case STATUS_GET_BOOL : s = "GET_BOOL\n"; break; + case STATUS_GET_LINE : s = "GET_LINE\n"; break; + case STATUS_GET_HIDDEN : s = "GET_HIDDEN\n"; break; + case STATUS_GOT_IT : s = "GOT_IT\n"; break; case STATUS_SHM_INFO : s = "SHM_INFO\n"; break; case STATUS_SHM_GET : s = "SHM_GET\n"; break; case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL\n"; break; @@ -118,6 +145,16 @@ write_status_text ( int no, const char *text) case STATUS_ERRMDC : s = "ERRMDC\n"; break; case STATUS_IMPORTED : s = "IMPORTED\n"; break; case STATUS_IMPORT_RES : s = "IMPORT_RES\n"; break; + case STATUS_FILE_START : s = "FILE_START\n"; break; + case STATUS_FILE_DONE : s = "FILE_DONE\n"; break; + case STATUS_FILE_ERROR : s = "FILE_ERROR\n"; break; + case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION\n"; break; + case STATUS_END_DECRYPTION : s = "END_DECRYPTION\n"; break; + case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION\n"; break; + case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION\n"; break; + case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM\n"; break; + case STATUS_PROGRESS : s = "PROGRESS\n"; break; + case STATUS_SIG_CREATED : s = "SIG_CREATED\n"; break; default: s = "?\n"; break; } @@ -164,6 +201,10 @@ init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) 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", @@ -174,29 +215,17 @@ init_shm_coprocessing ( ulong requested_shm_size, int 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; - #elif defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) /* (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; - #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 } - - #ifdef IPC_RMID_DEFERRED_RELEASE if( shmctl( shm_id, IPC_RMID, 0) ) log_fatal("shmctl IPC_RMDID of %d failed: %s\n", @@ -213,13 +242,59 @@ init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) 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 @@ -269,10 +344,50 @@ do_shm_get( const char *keyword, int hidden, int bool ) #endif /* USE_SHM_COPROCESSING */ +/**************** + * 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? gcry_xmalloc_secure ( len ) : gcry_malloc ( len ); + if( save ) + memcpy(string, save, i ); + else + i=0; + } + /* Hmmm: why not use our read_line function here */ + if( read( fd, string+i, 1) != 1 || string[i] == '\n' ) + 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; @@ -285,6 +400,8 @@ 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 ); @@ -318,6 +435,8 @@ 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 ); @@ -336,6 +455,8 @@ cpr_get_hidden( const char *keyword, const char *prompt ) void cpr_kill_prompt(void) { + if( opt.command_fd != -1 ) + return; #ifdef USE_SHM_COPROCESSING if( opt.shm_coprocess ) return; @@ -350,6 +471,8 @@ 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 ); @@ -376,6 +499,8 @@ 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 ); diff --git a/g10/status.h b/g10/status.h index 73cc1b1bf..f9cce5b6b 100644 --- a/g10/status.h +++ b/g10/status.h @@ -1,5 +1,5 @@ /* status.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -65,7 +65,22 @@ #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 /*-- status.c --*/ void set_status_fd ( int fd ); diff --git a/g10/tdbdump.c b/g10/tdbdump.c index 9be91241b..6729d4e56 100644 --- a/g10/tdbdump.c +++ b/g10/tdbdump.c @@ -1,5 +1,5 @@ /* tdbdump.c - * Copyright (C) 1999 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -520,5 +520,6 @@ import_ownertrust( const char *fname ) if( !is_stdin ) fclose(fp); do_sync(); + sync_trustdb(); } diff --git a/g10/tdbio.c b/g10/tdbio.c index 926048fbf..669f66ffc 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -1,5 +1,5 @@ /* tdbio.c - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -40,11 +40,6 @@ #include "tdbio.h" -#ifdef MKDIR_TAKES_ONE_ARG -# undef mkdir -# define mkdir(a,b) mkdir(a) -#endif - /**************** * Yes, this is a very simple implementation. We should really * use a page aligned buffer and read complete pages. @@ -439,17 +434,8 @@ tdbio_set_dbname( const char *new_dbname, int create ) assert(p); *p = 0; if( access( fname, F_OK ) ) { - if( strlen(fname) >= 7 - && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) { - 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 ); - } - else - log_fatal( _("%s: directory does not exist!\n"), fname ); + try_make_homedir( fname ); + log_fatal( _("%s: directory does not exist!\n"), fname ); } *p = '/'; @@ -1130,6 +1116,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp ) fputs(", expired", fp ); if( rec->r.dir.dirflags & DIRF_REVOKED ) fputs(", revoked", fp ); + if( rec->r.dir.dirflags & DIRF_NEWKEYS ) + fputs(", newkeys", fp ); } putc('\n', fp); break; diff --git a/g10/tdbio.h b/g10/tdbio.h index 4eabed91c..a2e5404f6 100644 --- a/g10/tdbio.h +++ b/g10/tdbio.h @@ -1,5 +1,5 @@ /* tdbio.h - Trust database I/O functions - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -52,6 +52,7 @@ /* one uid with a selfsignature or an revocation */ #define DIRF_EXPIRED 4 /* the complete key has expired */ #define DIRF_REVOKED 8 /* the complete key has been revoked */ +#define DIRF_NEWKEYS 128 /* new keys are available: we can check the sigs */ #define KEYF_CHECKED 1 /* This key has been checked */ #define KEYF_VALID 2 /* This is a valid (sub)key */ @@ -121,7 +122,7 @@ struct trust_record { } uid; struct { /* preference record */ ulong lid; /* point back to the directory record */ - /* or 0 for a glocal pref record */ + /* or 0 for a global pref record */ ulong next; /* points to next pref record */ byte data[ITEMS_PER_PREF_RECORD]; } pref; diff --git a/g10/textfilter.c b/g10/textfilter.c index 06f85dc64..a360ffccb 100644 --- a/g10/textfilter.c +++ b/g10/textfilter.c @@ -1,5 +1,5 @@ /* textfilter.c - * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -31,7 +31,13 @@ #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 */ @@ -151,6 +157,9 @@ copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md, int truncated = 0; int pending_lf = 0; + if( !opt.pgp2_workarounds ) + pgp2mode = 0; + if( !escape_dash ) escape_from = 0; @@ -183,12 +192,37 @@ copy_clearsig_text( IOBUF out, IOBUF inp, GCRY_MD_HD md, 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_put( out, '\n'); + iobuf_writestr( out, LF ); if( !escape_dash ) gcry_md_putc( md, '\n' ); } diff --git a/g10/trustdb.c b/g10/trustdb.c index 610b3b355..f75ccc52f 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1,5 +1,5 @@ /* trustdb.c - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -110,7 +110,6 @@ static int alloced_tns; static int max_alloced_tns; - static LOCAL_ID_TABLE new_lid_table(void); static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag ); static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag ); @@ -125,13 +124,22 @@ static int do_check( TRUSTREC *drec, unsigned *trustlevel, unsigned *retflgs); static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec ); static int do_update_trust_record( KBNODE keyblock, TRUSTREC *drec, - int recheck, int *modified ); -static int check_trust_record( TRUSTREC *drec ); + int sigs_only, int *modified ); +static int check_trust_record( TRUSTREC *drec, int sigs_only ); +static void mark_fresh_keys(void); /* a table used to keep track of ultimately trusted keys * which are the ones from our secrings and the trusted keys */ static LOCAL_ID_TABLE ultikey_table; + +/* a table to keep track of newly importted keys. This one is + * create by the insert_trust_record function and from time to time + * used to verify key signature which have been done with these new keys */ +static LOCAL_ID_TABLE fresh_imported_keys; +static int fresh_imported_keys_count; +#define FRESH_KEY_CHECK_THRESHOLD 200 + /* list of unused lid items and tables */ static LOCAL_ID_TABLE unused_lid_tables; static struct local_id_item *unused_lid_items; @@ -245,6 +253,27 @@ release_lid_table( LOCAL_ID_TABLE tbl ) } #endif + +/**************** + * Remove all items from a LID table + */ +static void +clear_lid_table( LOCAL_ID_TABLE tbl ) +{ + struct local_id_item *a, *a2; + int i; + + for(i=0; i < 16; i++ ) { + for(a=tbl->items[i]; a; a = a2 ) { + a2 = a->next; + a->next = unused_lid_items; + unused_lid_items = a; + } + tbl->items[i] = NULL; + } +} + + /**************** * Add a new item to the table or return 1 if we already have this item */ @@ -454,7 +483,7 @@ verify_own_keys(void) if( DBG_TRUST ) log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] ); - if( is_secret_key_protected( sk ) < 1 ) + if( !opt.quiet && is_secret_key_protected( sk ) < 1 ) log_info(_("NOTE: secret key %08lX is NOT protected.\n"), (ulong)keyid[1] ); @@ -572,6 +601,18 @@ init_trustdb() +/**************** + * This function should be called in certain cases to sync the internal state + * of the trustdb with the file image. Currently it is needed after + * a sequence of insert_trust_record() calls. + */ +void +sync_trustdb() +{ + if( fresh_imported_keys && fresh_imported_keys_count ) + mark_fresh_keys(); +} + /*********************************************** @@ -652,7 +693,7 @@ print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight ) p = get_user_id( keyid, &n ); putc(' ', fp); putc('\"', fp); - print_utf8_string( fp, p, n > 40? 40:n, 0 ); + print_utf8_string( fp, p, n > 40? 40:n ); putc('\"', fp); gcry_free(p); putc('\n', fp ); @@ -683,8 +724,14 @@ print_uid_from_keyblock( FILE *fp, KBNODE keyblock, ulong urecno ) if( node->pkt->pkttype == PKT_USER_ID ) { PKT_user_id *uidpkt = node->pkt->pkt.user_id; - gcry_md_hash_buffer( GCRY_MD_RMD160, uhash, - uidpkt->name, uidpkt->len ); + if( uidpkt->photo ) { + gcry_md_hash_buffer( GCRY_MD_RMD160, uhash, + uidpkt->photo, uidpkt->photolen ); + } + else { + gcry_md_hash_buffer( GCRY_MD_RMD160, uhash, + uidpkt->name, uidpkt->len ); + } if( !memcmp( uhash, urec.r.uid.namehash, 20 ) ) { print_string( fp, uidpkt->name, uidpkt->len, ':' ); return; @@ -1001,7 +1048,7 @@ check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid, (ulong)mainkid[1], lid ); assert(keynode->pkt->pkttype == PKT_USER_ID ); uid = keynode->pkt->pkt.user_id; - print_utf8_string( log_stream(), uid->name, uid->len ); + print_string( log_stream(), uid->name, uid->len, '\"' ); fputs("\"\n", log_stream()); } @@ -1083,17 +1130,17 @@ check_uidsigs( KBNODE keyblock, KBNODE keynode, u32 *mainkid, ulong lid, static unsigned int check_sig_record( KBNODE keyblock, KBNODE signode, ulong siglid, int sigidx, u32 *keyid, ulong lid, - u32 *r_expire ) + u32 *r_expiretime, int *mod_down, int *mod_up ) { PKT_signature *sig = signode->pkt->pkt.signature; unsigned int sigflag = 0; TRUSTREC tmp; - int revocation=0, rc; + int revocation=0, expired=0, rc; if( DBG_TRUST ) log_debug("check_sig_record: %08lX.%lu %lu[%d]\n", (ulong)keyid[1], lid, siglid, sigidx ); - *r_expire = 0; + *r_expiretime = 0; if( (sig->sig_class&~3) == 0x10 ) /* regular certification */ ; else if( sig->sig_class == 0x30 ) /* cert revocation */ @@ -1104,7 +1151,8 @@ check_sig_record( KBNODE keyblock, KBNODE signode, read_record( siglid, &tmp, 0 ); if( tmp.rectype == RECTYPE_DIR ) { /* the public key is in the trustdb: check sig */ - rc = check_key_signature2( keyblock, signode, NULL, r_expire ); + rc = check_key_signature2( keyblock, signode, NULL, + r_expiretime, &expired ); if( !rc ) { /* valid signature */ if( opt.verbose ) log_info("sig %08lX.%lu/%lu[%d]/%08lX: %s\n", @@ -1113,18 +1161,25 @@ check_sig_record( KBNODE keyblock, KBNODE signode, revocation? _("Valid certificate revocation") : _("Good certificate") ); sigflag |= SIGF_CHECKED | SIGF_VALID; + if( expired ) { + sigflag |= SIGF_EXPIRED; + /* We have to reset the expiretime, so that this signature + * does not get checked over and over due to the reached + * expiretime */ + *r_expiretime = 0; + } if( revocation ) { sigflag |= SIGF_REVOKED; - /**mod_down = 1;*/ + *mod_down = 1; } else - /**mod_up = 1*/; + *mod_up = 1; } else if( rc == GPGERR_NO_PUBKEY ) { /* This may happen if the key is still in the trustdb * but not available in the keystorage */ sigflag |= SIGF_NOPUBKEY; - /**mod_down = 1;*/ + *mod_down = 1; if( revocation ) sigflag |= SIGF_REVOKED; } @@ -1138,7 +1193,7 @@ check_sig_record( KBNODE keyblock, KBNODE signode, sigflag |= SIGF_CHECKED; if( revocation ) { sigflag |= SIGF_REVOKED; - /**mod_down = 1;*/ + *mod_down = 1; } } } @@ -1169,14 +1224,15 @@ check_sig_record( KBNODE keyblock, KBNODE signode, */ static ulong make_sig_records( KBNODE keyblock, KBNODE uidnode, - ulong lid, u32 *mainkid, u32 *min_expire ) + ulong lid, u32 *mainkid, u32 *min_expire, + int *mod_down, int *mod_up ) { TRUSTREC *srecs, **s_end, *s=NULL, *s2; KBNODE node; PKT_signature *sig; ulong sigrecno, siglid; int i, sigidx = 0; - u32 expire; + u32 expiretime; srecs = NULL; s_end = &srecs; for( node=uidnode->next; node; node = node->next ) { @@ -1191,6 +1247,12 @@ make_sig_records( KBNODE keyblock, KBNODE uidnode, siglid = find_or_create_lid( sig ); /* smash dups */ + /* FIXME: Here we have a problem: + * We can't distinguish between a certification and a certification + * revocation without looking at class of the signature - we have + * to see how we can store the sigclass in the sigrecord.. + * Argg- I hope I can get rid of this ugly trustdb ASAP. + */ for( s2 = s; s2 ; s2 = s2->next ) { for(i=0; i < sigidx; i++ ) { if( s2->r.sig.sig[i].lid == siglid ) @@ -1219,7 +1281,8 @@ make_sig_records( KBNODE keyblock, KBNODE uidnode, s->r.sig.sig[sigidx].lid = siglid; s->r.sig.sig[sigidx].flag= check_sig_record( keyblock, node, siglid, sigidx, - mainkid, lid, &expire ); + mainkid, lid, &expiretime, + mod_down, mod_up ); sigidx++; if( sigidx == SIGS_PER_RECORD ) { @@ -1229,8 +1292,8 @@ make_sig_records( KBNODE keyblock, KBNODE uidnode, sigidx = 0; } /* keep track of signers pk expire time */ - if( expire && (!*min_expire || *min_expire > expire ) ) - *min_expire = expire; + if( expiretime && (!*min_expire || *min_expire > expiretime ) ) + *min_expire = expiretime; } if( sigidx ) { s->recnum = tdbio_new_recnum(); @@ -1320,7 +1383,8 @@ make_pref_record( PKT_signature *sig, ulong lid ) static ulong -make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire ) +make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire, + int *mod_down, int *mod_up ) { TRUSTREC *urecs, **uend, *u, *u2; KBNODE node; @@ -1335,7 +1399,14 @@ make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire ) if( node->pkt->pkttype != PKT_USER_ID ) continue; uid = node->pkt->pkt.user_id; - gcry_md_hash_buffer( GCRY_MD_RMD160, uidhash, uid->name, uid->len ); + if( uid->photo ) { + gcry_md_hash_buffer( GCRY_MD_RMD160, uidhash, + uid->photo, uid->photolen ); + } + else { + gcry_md_hash_buffer( GCRY_MD_RMD160, uidhash, + uid->name, uid->len ); + } /* create the uid record */ u = gcry_xcalloc( 1, sizeof *u ); @@ -1352,9 +1423,21 @@ make_uid_records( KBNODE keyblock, ulong lid, u32 *keyid, u32 *min_expire ) && (u->r.uid.uidflags & UIDF_VALID) ) { u->r.uid.prefrec = bestsig? make_pref_record( bestsig, lid ) : 0; } + + /* the next test is really bad because we should modify + * out modification timestamps only if we really have a change. + * But because we are deleting the uid records first it is somewhat + * difficult to track those changes. fixme */ + if( !( u->r.uid.uidflags & UIDF_VALID ) + || ( u->r.uid.uidflags & UIDF_REVOKED ) ) + *mod_down=1; + else + *mod_up=1; + /* create the list of signatures */ u->r.uid.siglist = make_sig_records( keyblock, node, - lid, keyid, min_expire ); + lid, keyid, min_expire, + mod_down, mod_up ); } uidrecno = urecs? urecs->recnum : 0; @@ -1381,6 +1464,8 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) TRUSTREC drec; int rc; + /* NOTE: We don't need recheck anymore, but this might chnage again in + * the future */ if( opt.dry_run ) return 0; if( modified ) @@ -1391,26 +1476,27 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified ) if( rc ) return rc; - rc = do_update_trust_record( keyblock, &drec, recheck, modified ); + rc = do_update_trust_record( keyblock, &drec, 0, modified ); return rc; } /**************** - * Same as update_trust_record, but tghis functions expects the dir record. - * On exit the dirrecord will reflect any changes made. + * Same as update_trust_record, but this functions expects the dir record. + * On exit the dir record will reflect any changes made. + * With sigs_only set only foreign key signatures are checked. */ static int do_update_trust_record( KBNODE keyblock, TRUSTREC *drec, - int recheck, int *modified ) + int sigs_only, int *modified ) { PKT_public_key *primary_pk; TRUSTREC krec, urec, prec, helprec; int i, rc = 0; u32 keyid[2]; /* keyid of primary key */ -/* int mod_up = 0; - int mod_down = 0; */ + int mod_up = 0; + int mod_down = 0; ulong recno, r2; - u32 expire; + u32 expiretime; primary_pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key; if( !primary_pk->local_id ) @@ -1425,7 +1511,7 @@ do_update_trust_record( KBNODE keyblock, TRUSTREC *drec, if( rc ) return rc; - /* delete the old stuff */ + /* delete the old stuff FIXME: implementend sigs_only */ for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) { read_record( recno, &krec, RECTYPE_KEY ); delete_record( recno ); @@ -1448,22 +1534,13 @@ do_update_trust_record( KBNODE keyblock, TRUSTREC *drec, /* insert new stuff */ drec->r.dir.dirflags &= ~DIRF_REVOKED; + drec->r.dir.dirflags &= ~DIRF_NEWKEYS; drec->r.dir.keylist = make_key_records( keyblock, drec->recnum, keyid, &i ); if( i ) /* primary key has been revoked */ - drec->r.dir.dirflags &= DIRF_REVOKED; - expire = 0; + drec->r.dir.dirflags |= DIRF_REVOKED; + expiretime = 0; drec->r.dir.uidlist = make_uid_records( keyblock, drec->recnum, keyid, - &expire ); - #if 0 - if( orig_uidflags != urec.r.uid.uidflags ) { - write_record( &urec ); - if( !( urec.r.uid.uidflags & UIDF_VALID ) - || ( urec.r.uid.uidflags & UIDF_REVOKED ) ) - *mod_down=1; - else - *mod_up=1; /*(maybe a new user id)*/ - #endif - + &expiretime, &mod_down, &mod_up ); if( rc ) rc = tdbio_cancel_transaction(); else { @@ -1471,9 +1548,9 @@ do_update_trust_record( KBNODE keyblock, TRUSTREC *drec, *modified = 1; drec->r.dir.dirflags |= DIRF_CHECKED; drec->r.dir.valcheck = 0; - drec->r.dir.checkat = expire; + drec->r.dir.checkat = expiretime; write_record( drec ); - /*tdbio_write_modify_stamp( mod_up, mod_down );*/ + tdbio_write_modify_stamp( mod_up, mod_down ); rc = tdbio_end_transaction(); } return rc; @@ -1538,16 +1615,28 @@ insert_trust_record( KBNODE keyblock ) } } + /* mark tdb as modified upwards */ tdbio_write_modify_stamp( 1, 0 ); /* and put all the other stuff into the keydb */ - rc = do_update_trust_record( keyblock, &dirrec, 1, NULL ); + rc = do_update_trust_record( keyblock, &dirrec, 0, NULL ); do_sync(); + + /* keep track of new keys */ + if( !fresh_imported_keys ) + fresh_imported_keys = new_lid_table(); + ins_lid_table_item( fresh_imported_keys, pk->local_id, 0 ); + if( ++fresh_imported_keys_count > FRESH_KEY_CHECK_THRESHOLD ) + mark_fresh_keys(); + return rc; } + + + /**************** * Insert a trust record indentified by a PK into the TrustDB */ @@ -1585,7 +1674,7 @@ insert_trust_record_by_pk( PKT_public_key *pk ) * Currently we only do an update_trust_record. */ static int -check_trust_record( TRUSTREC *drec ) +check_trust_record( TRUSTREC *drec, int sigs_only ) { KBNODE keyblock; int modified, rc; @@ -1597,7 +1686,7 @@ check_trust_record( TRUSTREC *drec ) return rc; } - rc = do_update_trust_record( keyblock, drec, 0, &modified ); + rc = do_update_trust_record( keyblock, drec, sigs_only, &modified ); release_kbnode( keyblock ); return rc; @@ -1674,7 +1763,7 @@ update_trustdb() /**************** - * Do all required check in the trustdb. This function walks over all + * Do all required checks in the trustdb. This function walks over all * records in the trustdb and does scheduled processing. */ void @@ -1682,7 +1771,7 @@ check_trustdb( const char *username ) { TRUSTREC rec; ulong recnum; - ulong count=0, upd_count=0, err_count=0, skip_count=0; + ulong count=0, upd_count=0, err_count=0, skip_count=0, sigonly_count=0; ulong current_time = make_timestamp(); if( username ) @@ -1691,15 +1780,25 @@ check_trustdb( const char *username ) init_trustdb(); for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) { + int sigs_only; + if( rec.rectype != RECTYPE_DIR ) continue; /* we only want the dir records */ if( count && !(count % 100) && !opt.quiet ) log_info(_("%lu keys so far processed\n"), count); count++; - if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) { - skip_count++; - continue; /* not scheduled for checking */ + sigs_only = 0; + + if( !(rec.r.dir.dirflags & DIRF_CHECKED) ) + ; + else if( !rec.r.dir.checkat || rec.r.dir.checkat > current_time ) { + if( !(rec.r.dir.dirflags & DIRF_NEWKEYS) ) { + skip_count++; + continue; /* not scheduled for checking */ + } + sigs_only = 1; /* new public keys - check them */ + sigonly_count++; } if( !rec.r.dir.keylist ) { @@ -1708,11 +1807,12 @@ check_trustdb( const char *username ) continue; } - check_trust_record( &rec ); - + check_trust_record( &rec, sigs_only ); } log_info(_("%lu keys processed\n"), count); + if( sigonly_count ) + log_info(_("\t%lu due to new pubkeys\n"), sigonly_count); if( skip_count ) log_info(_("\t%lu keys skipped\n"), skip_count); if( err_count ) @@ -1772,8 +1872,12 @@ build_cert_tree( ulong lid, int depth, int max_depth, TN helproot ) return NULL; } - if( dirrec.r.dir.checkat && dirrec.r.dir.checkat <= make_timestamp() ) - check_trust_record( &dirrec ); + if( dirrec.r.dir.checkat && dirrec.r.dir.checkat <= make_timestamp() ) { + check_trust_record( &dirrec, 0 ); + } + else if( (dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) { + check_trust_record( &dirrec, 1 ); + } keynode->n.k.ownertrust = dirrec.r.dir.ownertrust & TRUST_MASK; @@ -1924,10 +2028,10 @@ propagate_validity( TN root, TN node, int (*add_fnc)(ulong), unsigned *retflgs ) } /* loop over all user ids */ - for( ur=node->list; ur && max_validity < TRUST_FULLY; ur = ur->next ) { + for( ur=node->list; ur && max_validity <= TRUST_FULLY; ur = ur->next ) { assert( ur->is_uid ); /* loop over all signators */ - for(kr=ur->list; kr && max_validity < TRUST_FULLY; kr = kr->next ) { + for(kr=ur->list; kr && max_validity <= TRUST_FULLY; kr = kr->next ) { if( propagate_validity( root, kr, add_fnc, retflgs ) ) return -1; /* quit */ if( kr->n.k.validity == TRUST_ULTIMATE ) { @@ -2001,8 +2105,12 @@ verify_key( int max_depth, TRUSTREC *drec, const char *namehash, if( !tree ) return TRUST_UNDEFINED; pv_result = propagate_validity( tree, tree, add_fnc, retflgs ); - if( namehash ) { + if( namehash && tree->n.k.validity != TRUST_ULTIMATE ) { /* find the matching user id. + * We don't do this here if the key is ultimately trusted; in + * this case there will be no lids for the user IDs and frankly + * it does not make sense to compare by the name if we do + * have the secret key. * fixme: the way we handle this is too inefficient */ TN ur; TRUSTREC rec; @@ -2075,6 +2183,7 @@ do_check( TRUSTREC *dr, unsigned *validity, } else if( !add_fnc && tdbio_db_matches_options() + /* FIXME, TODO: This comparision is WRONG ! */ && dr->r.dir.valcheck > tdbio_read_modify_stamp( (dr->r.dir.validity < TRUST_FULLY) ) && dr->r.dir.validity ) @@ -2240,10 +2349,16 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, log_info(_("key %08lX.%lu: created in future " "(time warp or clock problem)\n"), (ulong)keyid[1], pk->local_id ); - return GPGERR_TIME_CONFLICT; + if( !opt.ignore_time_conflict ) + return GPGERR_TIME_CONFLICT; } - if( rec.r.dir.checkat && rec.r.dir.checkat <= cur_time ) - check_trust_record( &rec ); + + if( !(rec.r.dir.dirflags & DIRF_CHECKED) ) + check_trust_record( &rec, 0 ); + else if( rec.r.dir.checkat && rec.r.dir.checkat <= cur_time ) + check_trust_record( &rec, 0 ); + else if( (rec.r.dir.dirflags & DIRF_NEWKEYS) ) + check_trust_record( &rec, 1 ); if( pk->expiredate && pk->expiredate <= cur_time ) { log_info(_("key %08lX.%lu: expired at %s\n"), @@ -2299,6 +2414,51 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, } +/**************** + * scan the whole trustdb and mark all signature records whose keys + * are freshly imported. + */ +static void +mark_fresh_keys() +{ + TRUSTREC dirrec, rec; + ulong recnum, lid; + int i; + + memset( &dirrec, 0, sizeof dirrec ); + + for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) { + if( rec.rectype != RECTYPE_SIG ) + continue; + /* if we have already have the dir record, we can check it now */ + if( dirrec.recnum == rec.r.sig.lid + && (dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) + continue; /* flag is already set */ + + for(i=0; i < SIGS_PER_RECORD; i++ ) { + if( !(lid=rec.r.sig.sig[i].lid) ) + continue; /* skip deleted sigs */ + if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) + continue; /* skip checked signatures */ + if( qry_lid_table_flag( fresh_imported_keys, lid, NULL ) ) + continue; /* not in the list of new keys */ + read_record( rec.r.sig.lid, &dirrec, RECTYPE_DIR ); + if( !(dirrec.r.dir.dirflags & DIRF_NEWKEYS) ) { + dirrec.r.dir.dirflags |= DIRF_NEWKEYS; + write_record( &dirrec ); + } + break; + } + } + + do_sync(); + + clear_lid_table( fresh_imported_keys ); + fresh_imported_keys_count = 0; +} + + + int query_trust_info( PKT_public_key *pk, const byte *namehash ) { @@ -2532,7 +2692,7 @@ enum_cert_paths_print( void **context, FILE *fp, /* * Return an allocated buffer with the preference values for * the key with LID and the userid which is identified by the - * HAMEHASH or the firstone if namehash is NULL. ret_n receives + * HAMEHASH or the first one if namehash is NULL. ret_n receives * the length of the allocated buffer. Structure of the buffer is * a repeated sequences of 2 bytes; where the first byte describes the * type of the preference and the second one the value. The constants diff --git a/g10/trustdb.h b/g10/trustdb.h index 86351c1eb..1279edb0f 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -1,5 +1,5 @@ /* trustdb.h - Trust database - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -49,6 +49,7 @@ void check_trustdb( const char *username ); void update_trustdb( void ); int setup_trustdb( int level, const char *dbname ); void init_trustdb( void ); +void sync_trustdb( void ); int check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte* nh, int (*add_fnc)(ulong), unsigned *retflgs ); int query_trust_info( PKT_public_key *pk, const byte *nh ); diff --git a/g10/verify.c b/g10/verify.c index 5fdf99338..f3f9a36eb 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -1,5 +1,5 @@ /* verify.c - verify signed data - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,14 +25,15 @@ #include <errno.h> #include <assert.h> +#include <gcrypt.h> #include "options.h" #include "packet.h" #include "errors.h" #include "iobuf.h" #include "keydb.h" -#include <gcrypt.h> #include "util.h" #include "main.h" +#include "status.h" #include "filter.h" #include "ttyio.h" #include "i18n.h" @@ -58,6 +59,7 @@ verify_signatures( int nfiles, char **files ) int i, rc; STRLIST sl; + memset( &afx, 0, sizeof afx); sigfile = nfiles? *files : NULL; /* open the signature file */ @@ -67,6 +69,51 @@ verify_signatures( int nfiles, char **files ) return GPGERR_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; +} + + +static void +print_file_status( int status, const char *name, int what ) +{ + char *p = gcry_xmalloc(strlen(name)+10); + sprintf(p, "%d %s", what, name ); + write_status_text( status, p ); + gcry_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 GPGERR_OPEN_FILE; + } + if( !opt.no_armor ) { if( use_armor_filter( fp ) ) { memset( &afx, 0, sizeof afx); @@ -74,14 +121,44 @@ verify_signatures( int nfiles, char **files ) } } - 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); + 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 GPGERR_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; +} |