diff --git a/ChangeLog b/ChangeLog index d3e7eb1a7..d79108648 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2011-02-01 Werner Koch + + * configure.ac (HAVE_GCRY_PK_GET_CURVE): Define if availabale. + 2011-01-20 Werner Koch * configure.ac (AC_CONFIG_FILES): Remove keyserver/. diff --git a/agent/ChangeLog b/agent/ChangeLog index 6338c56c5..d4a0de3a8 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,5 +1,12 @@ +2011-02-02 Werner Koch + + * cvt-openpgp.c (convert_secret_key): Remove algo mapping. + 2011-01-31 Werner Koch + * cvt-openpgp.c (convert_to_openpgp): Adjust to reverted Libgcrypt + ABI. + * protect.c (protect_info): Adjust ECDSA and ECDH parameter names. Add "ecc". * findkey.c (key_parms_from_sexp): Ditto. @@ -522,7 +529,7 @@ * genkey.c (agent_protect_and_store): Return RC and not 0. * protect.c (do_encryption): Fix ignored error code from malloc. Reported by Fabian Keil. - + 2009-06-17 Werner Koch * call-pinentry.c (agent_get_confirmation): Add arg WITH_CANCEL. @@ -546,7 +553,7 @@ * trustlist.c: Include estream.h. (agent_marktrusted): Replace stdio stream by estream functions. - * protect-tool.c (store_private_key): Use bin2hex. + * protect-tool.c (store_private_key): Use bin2hex. 2009-06-02 Werner Koch @@ -560,7 +567,7 @@ 2009-05-15 Werner Koch Fix bug #1053. - + * agent.h (lookup_ttl_t): New. * findkey.c (unprotect): Add arg LOOKUP_TTL. (agent_key_from_file): Ditto. @@ -638,7 +645,7 @@ (agent_istrusted): Add arg R_DISABLED. Change all callers. (agent_marktrusted): Do not ask if flagged as disabled. Reverse the order of the questions. Store the disabled flag. - + * gpg-agent.c (main): Save signal mask and open fds. Restore mask and close all fds prior to the exec. Fixes bug#1013. @@ -749,11 +756,11 @@ * command.c (cmd_geteventcounter): Mark unused arg. (cmd_listtrusted, cmd_pksign, cmd_pkdecrypt, cmd_genkey): Ditto. (cmd_updatestartuptty, post_cmd_notify): Ditto. - * command-ssh.c (add_control_entry) - (ssh_handler_request_identities, ssh_handler_remove_identity) - (ssh_handler_remove_all_identities, ssh_handler_lock) + * command-ssh.c (add_control_entry) + (ssh_handler_request_identities, ssh_handler_remove_identity) + (ssh_handler_remove_all_identities, ssh_handler_lock) (ssh_handler_unlock): Ditto. - * call-pinentry.c (pinentry_active_p, popup_message_thread) + * call-pinentry.c (pinentry_active_p, popup_message_thread) (agent_popup_message_stop): Ditto. * findkey.c (agent_public_key_from_file): Ditto. * genkey.c (check_passphrase_pattern): Ditto. @@ -872,7 +879,7 @@ * agent.h (struct server_control_s): Add XAUTHORITY and PINENTRY_USER_DATA. * gpg-agent.c: New option --xauthority. - (main, agent_init_default_ctrl) + (main, agent_init_default_ctrl) (agent_deinit_default_ctrl): Implemented * command.c (cmd_updatestartuptty): Ditto. * command-ssh.c (start_command_handler_ssh): Ditto. @@ -1032,7 +1039,7 @@ 2007-06-21 Werner Koch - * agent.h (ctrl_t): Remove. It is now declared in ../common/util.h. + * agent.h (ctrl_t): Remove. It is now declared in ../common/util.h. * gpg-agent.c (check_for_running_agent): New arg SILENT. Changed all callers. @@ -1065,7 +1072,7 @@ * preset-passphrase.c (main): Setup default socket name for simple-pwquery. (map_spwq_error): Remove. - (MAP_SPWQ_ERROR_IMPL): New. + (MAP_SPWQ_ERROR_IMPL): New. * call-pinentry.c (start_pinentry): Use gnupg_module_name. * call-scd.c (start_scd): Ditto. @@ -1127,7 +1134,7 @@ (main): Call the setup_libgcrypt_logging helper. * protect-tool.c (my_gcry_logger): Removed. (main): Call the setup_libgcrypt_logging helper. - + 2007-04-03 Werner Koch * trustlist.c (read_trustfiles): Take a missing trustlist as an @@ -1135,7 +1142,7 @@ 2007-03-20 Werner Koch - * protect-tool.c: New option --p12-charset. + * protect-tool.c: New option --p12-charset. * minip12.c (p12_build): Implement it. 2007-03-19 Werner Koch @@ -1170,7 +1177,7 @@ 2007-01-31 Werner Koch - * command-ssh.c (start_command_handler_ssh): + * command-ssh.c (start_command_handler_ssh): * Makefile.am (t_common_ldadd): Add LIBICONV. @@ -1298,7 +1305,7 @@ (agent_pksign_do): Use it here for the TLS algo. * agent.h (GCRY_MD_USER_TLS_MD5SHA1): New. * divert-scd.c (pksign): Add case for tls-md5sha1. - + * divert-scd.c (encode_md_for_card): Check that the algo is valid. 2006-10-04 Werner Koch @@ -1368,7 +1375,7 @@ Replaced all Assuan error codes by libgpg-error codes. Removed all map_to_assuan_status and map_assuan_err. - + * gpg-agent.c (main): Call assuan_set_assuan_err_source to have Assuan switch to gpg-error codes. * command.c (set_error): Adjusted. @@ -1412,7 +1419,7 @@ * minip12.c (oid_pkcs_12_keyBag): New. (parse_bag_encrypted_data): New arg R_RESULT. Support keybags and - return the key object. + return the key object. (p12_parse): Take new arg into account. Free RESULT on error. 2006-06-26 Werner Koch @@ -1480,7 +1487,7 @@ * call-scd.c (inq_needpin): Reworked to support the new KEYPADINFO. * query.c (start_pinentry): Keep track of the owner. - (popup_message_thread, agent_popup_message_start) + (popup_message_thread, agent_popup_message_start) (agent_popup_message_stop, agent_reset_query): New. * command.c (start_command_handler): Make sure a popup window gets closed. @@ -1531,7 +1538,7 @@ 2005-06-21 Werner Koch - * minip12.c (create_final): Cast size_t to ulong for printf. + * minip12.c (create_final): Cast size_t to ulong for printf. (build_key_bag, build_cert_bag, build_cert_sequence): Ditto. 2005-06-16 Werner Koch @@ -1546,7 +1553,7 @@ * protect.c (do_encryption): Ditto. (do_encryption): Made arg PROTBEGIN unsigned. Initialize RESULT and RESULTLEN even on error. - (merge_lists): Need to cast unsigned char * for strcpy. Initialize + (merge_lists): Need to cast unsigned char * for strcpy. Initialize RESULTand RESULTLEN even on error. (agent_unprotect): Likewise for strtoul. (make_shadow_info): Made P and INFO plain char. @@ -1606,7 +1613,7 @@ * command.c (cmd_updatestartuptty): New. * gpg-agent.c: New option --write-env-file. - + * gpg-agent.c (handle_connections): Make sure that the signals we are handling are not blocked.Block signals while creating new threads. @@ -1876,8 +1883,8 @@ (make_cstring): Ditto. (data_sign): Don't use a variable for the passphrase prompt, make it translatable. - (ssh_request_process): - + (ssh_request_process): + * findkey.c (modify_description): Renamed arguments for clarity, polished documentation. Make comment a C-string. Fixed case of @@ -2003,7 +2010,7 @@ 2004-12-21 Werner Koch * gpg-agent.c (main): Use default_homedir(). - * protect-tool.c (main): Ditto. + * protect-tool.c (main): Ditto. 2004-12-20 Werner Koch @@ -2029,7 +2036,7 @@ * query.c (initialize_module_query): New. * call-scd.c (initialize_module_call_scd): New. * gpg-agent.c (main): Call them. - + 2004-12-18 Werner Koch * gpg-agent.c (main): Remove special Pth initialize. @@ -2081,10 +2088,10 @@ to Moritz for pointing this out. 2004-09-25 Moritz Schulte - + * agent.h: Declare: agent_pksign_do. (struct server_control_s): New member: raw_value. - + * pksign.c (do_encode_md): New argument: raw_value; support generation of raw (non-pkcs1) data objects; adjust callers. (agent_pksign_do): New function, based on code ripped @@ -2092,7 +2099,7 @@ (agent_pksign): Use agent_pksign_do. * command.c (start_command_handler): Set ctrl.digest.raw_value. - + 2004-09-09 Werner Koch * gpg-agent.c (check_for_running_agent): New. @@ -2133,14 +2140,14 @@ * gpg-agent.c (handle_signal): Reload the trustlist on SIGHUP. (start_connection_thread): Hack to simulate a ticker. - * trustlist.c (agent_trustlist_housekeeping) + * trustlist.c (agent_trustlist_housekeeping) (agent_reload_trustlist): New. Protected all global functions here with a simple counter which is sufficient for Pth. 2004-05-03 Werner Koch * gpg-agent.c: Remove help texts for options lile --lc-ctype. - (main): New option --allow-mark-trusted. + (main): New option --allow-mark-trusted. * trustlist.c (agent_marktrusted): Use it here. 2004-04-30 Werner Koch @@ -2213,7 +2220,7 @@ string. Changed all callers. * minip12.c: Revamped the build part. - (p12_build): New args CERT and CERTLEN. + (p12_build): New args CERT and CERTLEN. 2004-02-18 Werner Koch @@ -2307,7 +2314,7 @@ * findkey.c (agent_key_from_file): Now return an error code so that we have more detailed error messages in the upper layers. - This fixes the handling of pinentry's cancel button. + This fixes the handling of pinentry's cancel button. * pksign.c (agent_pksign): Changed accordingly. * pkdecrypt.c (agent_pkdecrypt): Ditto. * command.c (cmd_passwd): Ditto. @@ -2334,12 +2341,12 @@ * pksign.c (do_encode_md): Allocate enough space. Cast md byte to unsigned char to prevent sign extension. - + 2003-08-14 Timo Schulz * pksign.c (do_encode_md): Due to the fact pkcs#1 padding is now in Libgcrypt, use the new interface. - + 2003-07-31 Werner Koch * Makefile.am (gpg_agent_LDADD): Added INTLLIBS. @@ -2389,7 +2396,7 @@ * gpg-agent.c (handle_connections): Adjusted for Pth 2.0 Adjusted for changes in the libgcrypt API. Some more fixes for the - libgpg-error stuff. + libgpg-error stuff. 2003-06-04 Werner Koch @@ -2468,11 +2475,11 @@ (agent_askpin,agent_get_passphrase,agent_get_confirmation): Add CTRL arg and pass it ot start_pinentry. * command.c (cmd_get_passphrase): Pass CTRL argument. - * trustlist.c (agent_marktrusted): Add CTRL argument + * trustlist.c (agent_marktrusted): Add CTRL argument * command.c (cmd_marktrusted): Pass CTRL argument - * divert-scd.c (ask_for_card): Add CTRL arg. + * divert-scd.c (ask_for_card): Add CTRL arg. (divert_pksign,divert_pkdecrypt): Ditto. Changed caller. - (getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both + (getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both users. * findkey.c (unprotect): Add CTRL arg. (agent_key_from_file): Ditto. @@ -2707,7 +2714,7 @@ convert it to hex here. * findkey.c (agent_write_private_key): New. * genkey.c (store_key): And use it here. - + * pkdecrypt.c (agent_pkdecrypt): Changed the way the diversion is done. * divert-scd.c (divert_pkdecrypt): Changed interface and implemented it. @@ -2737,7 +2744,7 @@ * protect.c (snext,sskip,smatch): Moved to * sexp-parse.h: New file. * divert-scd.c: New. - + 2002-02-27 Werner Koch * protect.c (agent_shadow_key): New. @@ -2765,7 +2772,7 @@ * gpg-agent.c: New option --default-cache-ttl. * cache.c (agent_put_cache): Use it. - + * cache.c: Add a few debug outputs. * protect.c (agent_private_key_type): New. @@ -2773,10 +2780,10 @@ * findkey.c (agent_key_from_file): Use it to decide whether we have to unprotect a key. (unprotect): Cache the passphrase. - + * findkey.c (agent_key_from_file,agent_key_available): The key files do now require a ".key" suffix to make a script's life - easier. + easier. * genkey.c (store_key): Ditto. 2002-01-31 Werner Koch @@ -2784,11 +2791,11 @@ * genkey.c (store_key): Protect the key. (agent_genkey): Ask for the passphrase. * findkey.c (unprotect): Actually unprotect the key. - * query.c (agent_askpin): Add an optional start_err_text. + * query.c (agent_askpin): Add an optional start_err_text. 2002-01-30 Werner Koch - * protect.c: New. + * protect.c: New. (hash_passphrase): Based on the GnuPG 1.0.6 version. * protect-tool.c: New @@ -2842,10 +2849,10 @@ * command.c (rc_to_assuan_status): Removed and changed all callers to use map_to_assuan_status. - + 2001-12-19 Werner Koch - * keyformat.txt: New. + * keyformat.txt: New. 2001-12-19 Marcus Brinkmann diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index 02c2bc841..690459330 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -37,7 +37,7 @@ /* Helper to pass data via the callback to do_unprotect. */ -struct try_do_unprotect_arg_s +struct try_do_unprotect_arg_s { int is_v4; int is_protected; @@ -87,10 +87,12 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip) "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); break; - case GCRY_PK_ECDSA: - case GCRY_PK_ECDH: + case GCRY_PK_ECDSA: + case GCRY_PK_ECDH: err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(c%m)(q%m)))", pkey[0], pkey[1]); + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))", + pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], + pkey[5]); break; default: @@ -108,8 +110,7 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip) /* Convert a secret key given as algorithm id and an array of key parameters into our s-expression based format. Note that - PUBKEY_ALGO is a standard id and not an OpenPGP id. - */ + PUBKEY_ALGO has an gcrypt algorithm number. */ static gpg_error_t convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey) { @@ -118,9 +119,6 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey) *r_key = NULL; - /* FIXME: This is not consistent with the above comment. */ - pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo); - switch (pubkey_algo) { case GCRY_PK_DSA: @@ -147,15 +145,15 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey) break; case GCRY_PK_ECDSA: - err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecdsa(c%m)(q%m)(d%m)))", - skey[0], skey[1], skey[2]); - break; - case GCRY_PK_ECDH: + /* Although our code would work with "ecc" we explicitly use + "ecdh" or "ecdsa" to implicitly set the key capabilities. */ err = gcry_sexp_build (&s_skey, NULL, - "(private-key(ecdh(c%m)(q%m)(p%m)(d%m)))", - skey[0], skey[1], skey[2], skey[3]); + "(private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)" + "(d%m)))", + pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh", + skey[0], skey[1], skey[2], skey[3], skey[4], + skey[5], skey[6]); break; default: @@ -184,7 +182,7 @@ hash_passphrase_and_set_key (const char *passphrase, keylen = gcry_cipher_get_algo_keylen (protect_algo); if (!keylen) return gpg_error (GPG_ERR_INTERNAL); - + key = xtrymalloc_secure (keylen); if (!key) return gpg_error_from_syserror (); @@ -204,7 +202,7 @@ static u16 checksum (const unsigned char *p, unsigned int n) { u16 a; - + for (a=0; n; n-- ) a += *p++; return a; @@ -272,7 +270,7 @@ do_unprotect (const char *passphrase, return gpg_error (GPG_ERR_MISSING_VALUE); if (nskey+1 >= skeysize) return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); - + /* Check whether SKEY is at all protected. If it is not protected merely verify the checksum. */ if (!is_protected) @@ -284,7 +282,7 @@ do_unprotect (const char *passphrase, { if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE)) return gpg_error (GPG_ERR_BAD_SECKEY); - + err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]); if (!err) { @@ -301,7 +299,7 @@ do_unprotect (const char *passphrase, if (err) return err; } - + if (actual_csum != desired_csum) return gpg_error (GPG_ERR_CHECKSUM); return 0; @@ -324,7 +322,7 @@ do_unprotect (const char *passphrase, s2k_algo, gcry_md_algo_name (s2k_algo)); return gpg_error (GPG_ERR_DIGEST_ALGO); } - + err = gcry_cipher_open (&cipher_hd, protect_algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE @@ -343,10 +341,10 @@ do_unprotect (const char *passphrase, { gcry_cipher_close (cipher_hd); return err; - } + } gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen); - + actual_csum = 0; if (pkt_version >= 4) { @@ -379,15 +377,15 @@ do_unprotect (const char *passphrase, { /* This is the new SHA1 checksum method to detect tampering with the key as used by the Klima/Rosa attack. */ - desired_csum = 0; + desired_csum = 0; actual_csum = 1; /* Default to bad checksum. */ - if (ndata < 20) + if (ndata < 20) log_error ("not enough bytes for SHA-1 checksum\n"); - else + else { gcry_md_hd_t h; - + if (gcry_md_open (&h, GCRY_MD_SHA1, 1)) BUG(); /* Algo not available. */ gcry_md_write (h, data, ndata - 20); @@ -397,13 +395,13 @@ do_unprotect (const char *passphrase, gcry_md_close (h); } } - else + else { /* Old 16 bit checksum method. */ if (ndata < 2) { log_error ("not enough bytes for checksum\n"); - desired_csum = 0; + desired_csum = 0; actual_csum = 1; /* Mark checksum bad. */ } else @@ -417,7 +415,7 @@ do_unprotect (const char *passphrase, } } } - + /* Better check it here. Otherwise the gcry_mpi_scan would fail because the length may have an arbitrary value. */ if (desired_csum == actual_csum) @@ -468,7 +466,7 @@ do_unprotect (const char *passphrase, gcry_cipher_close (cipher_hd); return gpg_error (GPG_ERR_BAD_SECKEY); } - + buffer = xtrymalloc_secure (ndata); if (!buffer) { @@ -476,7 +474,7 @@ do_unprotect (const char *passphrase, gcry_cipher_close (cipher_hd); return err; } - + gcry_cipher_sync (cipher_hd); buffer[0] = p[0]; buffer[1] = p[1]; @@ -557,7 +555,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi) pointed to by GRIP. On error NULL is stored at all return arguments. */ gpg_error_t -convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, +convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, unsigned char *grip, const char *prompt, const char *cache_nonce, unsigned char **r_key, char **r_passphrase) @@ -625,7 +623,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, if (!protect_algo && !!strcmp (string, "IDEA")) protect_algo = GCRY_CIPHER_IDEA; xfree (string); - + value = gcry_sexp_nth_data (list, 3, &valuelen); if (!value || !valuelen || valuelen > sizeof iv) goto bad_seckey; @@ -848,7 +846,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; - + outofmem: err = gpg_error (GPG_ERR_ENOMEM); goto leave; @@ -874,13 +872,13 @@ key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array) } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); - if (!array[idx]) + if (!array[idx]) { err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */ goto leave; } } - + leave: if (err) { @@ -1028,7 +1026,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, gcry_sexp_release (list); return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */ } - + algo = gcry_pk_map_name (name); xfree (name); @@ -1038,8 +1036,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break; case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break; case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break; - case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 2; elems = "cqd"; break; - case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 3; elems = "cqpd"; break; + case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break; + case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break; default: algoname = ""; npkey = 0; elems = NULL; break; } assert (!elems || strlen (elems) < DIM (array) ); @@ -1070,9 +1068,9 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, void *format_args[10+2]; size_t n; gcry_sexp_t tmpkey, tmpsexp = NULL; - + snprintf (countbuf, sizeof countbuf, "%lu", s2k_count); - + init_membuf (&mbuf, 50); put_membuf_str (&mbuf, "(skey"); for (i=j=0; i < npkey; i++) @@ -1105,7 +1103,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, " %S\n" " (protection sha1 aes %b 1:3 sha1 %b %s))\n", algoname, - tmpkey, + tmpkey, (int)sizeof protect_iv, protect_iv, (int)sizeof salt, salt, countbuf); diff --git a/common/util.h b/common/util.h index cf38ad4f8..fc3dd02df 100644 --- a/common/util.h +++ b/common/util.h @@ -42,6 +42,12 @@ #ifndef GPG_ERR_FULLY_CANCELED #define GPG_ERR_FULLY_CANCELED 198 #endif +#ifndef GPG_ERR_INV_CURVE +#define GPG_ERR_INV_CURVE 187 +#endif +#ifndef GPG_ERR_UNKNOWN_CURVE +#define GPG_ERR_UNKNOWN_CURVE 188 +#endif /* Hash function used with libksba. */ @@ -75,10 +81,10 @@ /* GCC attributes. */ -#if __GNUC__ >= 4 +#if __GNUC__ >= 4 # define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a))) #else -# define GNUPG_GCC_A_SENTINEL(a) +# define GNUPG_GCC_A_SENTINEL(a) #endif @@ -132,14 +138,14 @@ int answer_is_yes_no_quit (const char *s); int answer_is_okay_cancel (const char *s, int def_answer); /*-- xreadline.c --*/ -ssize_t read_line (FILE *fp, +ssize_t read_line (FILE *fp, char **addr_of_buffer, size_t *length_of_buffer, size_t *max_length); /*-- b64enc.c and b64dec.c --*/ -struct b64state -{ +struct b64state +{ unsigned int flags; int idx; int quad_count; @@ -184,9 +190,9 @@ unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen, size_t *r_len); gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, - unsigned char const **r_n, + unsigned char const **r_n, size_t *r_nlen, - unsigned char const **r_e, + unsigned char const **r_e, size_t *r_elen); gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, @@ -231,7 +237,7 @@ const char *dirmngr_socket_name (void); gpgconf. */ #define GNUPG_MODULE_NAME_AGENT 1 #define GNUPG_MODULE_NAME_PINENTRY 2 -#define GNUPG_MODULE_NAME_SCDAEMON 3 +#define GNUPG_MODULE_NAME_SCDAEMON 3 #define GNUPG_MODULE_NAME_DIRMNGR 4 #define GNUPG_MODULE_NAME_PROTECT_TOOL 5 #define GNUPG_MODULE_NAME_CHECK_PATTERN 6 @@ -286,7 +292,7 @@ int gnupg_compare_version (const char *a, const char *b); #ifndef HAVE_TTYNAME /* Systems without ttyname (W32) will merely return NULL. */ static inline char * -ttyname (int fd) +ttyname (int fd) { (void)fd; return NULL; diff --git a/configure.ac b/configure.ac index e24117b28..1081b2d3c 100644 --- a/configure.ac +++ b/configure.ac @@ -742,6 +742,7 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION", AM_PATH_LIBGCRYPT("$NEED_LIBGCRYPT_API:$NEED_LIBGCRYPT_VERSION", have_libgcrypt=yes,have_libgcrypt=no) +# fixme: We can remove the next two checks if we require libgcrypt 1.5. AC_CACHE_CHECK([whether Libgcrypt support ECDH], gnupg_cv_gcry_pk_ecdh, [ _gnupg_gcry_save_cflags=$CFLAGS CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" @@ -756,6 +757,21 @@ if test "$gnupg_cv_gcry_pk_ecdh" = yes; then [Define if gcrypt.h has the enum value for ECDH.]) fi +AC_CACHE_CHECK([whether Libgcrypt has gcry_pk_get_curve], + gnupg_cv_gcry_pk_get_curve, + [ _gnupg_gcry_save_cflags=$CFLAGS + CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" + AC_TRY_COMPILE( + [#include ], + [ return gcry_pk_get_curve (NULL, 0, NULL); ], + gnupg_cv_gcry_pk_get_curve=yes, + gnupg_cv_gcry_pk_get_curve=no) + CFLAGS=$_gnupg_gcry_save_cflags]) +if test "$gnupg_cv_gcry_pk_get_curve" = yes; then + AC_DEFINE([HAVE_GCRY_PK_GET_CURVE], 1, + [Define if gcrypt.h has gcry_pk_get_curve.]) +fi + # # libassuan is used for IPC diff --git a/g10/ChangeLog b/g10/ChangeLog index 2a284e765..bb55ff85f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,18 @@ +2011-02-02 Werner Koch + + * import.c (transfer_secret_keys): Make sure keyids are available. + + * keyid.c (hash_public_key): Adjust for the ECC case. + +2011-02-01 Werner Koch + + * import.c (transfer_secret_keys): Implement ECC case. + + * gpg.c (main): Call setup_libgcrypt_logging. + + * keygen.c (gpg_curve_to_oid): New. + (ecckey_from_sexp): Factor curve name mapping out to new function. + 2011-01-31 Werner Koch * misc.c (make_flagged_int, openpgp_oid_from_str) diff --git a/g10/ecdh.c b/g10/ecdh.c index 09ab3ed16..f97667ae3 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -36,7 +36,7 @@ static const struct unsigned int qbits; int openpgp_hash_id; /* KEK digest algorithm. */ int openpgp_cipher_id; /* KEK cipher algorithm. */ -} kek_params_table[] = +} kek_params_table[] = /* Note: Must be sorted by ascending values for QBITS. */ { { 256, DIGEST_ALGO_SHA256, CIPHER_ALGO_AES }, @@ -60,8 +60,8 @@ pk_ecdh_default_params (unsigned int qbits) if (!kek_params) return NULL; kek_params[0] = 3; /* Number of bytes to follow. */ - kek_params[1] = 1; /* Version for KDF+AESWRAP. */ - + kek_params[1] = 1; /* Version for KDF+AESWRAP. */ + /* Search for matching KEK parameter. Defaults to the strongest possible choices. Performance is not an issue here, only interoperability. */ @@ -78,7 +78,7 @@ pk_ecdh_default_params (unsigned int qbits) assert (i < DIM (kek_params_table)); if (DBG_CIPHER) log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) ); - + return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8); } @@ -88,16 +88,16 @@ pk_ecdh_default_params (unsigned int qbits) key_derivation+key_wrapping. If IS_ENCRYPT is true the function encrypts; if false, it decrypts. On success the result is stored at R_RESULT; on failure NULL is stored at R_RESULT and an error - code returned. + code returned. FIXME: explain PKEY and PK_FP. */ - + /* TODO: memory leaks (x_secret). */ gpg_error_t -pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, +pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t data, gcry_mpi_t *pkey, gcry_mpi_t *r_result) @@ -106,8 +106,8 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, byte *secret_x; int secret_x_size; unsigned int nbits; - const unsigned char *kdf_params; - size_t kdf_params_size; + const unsigned char *kek_params; + size_t kek_params_size; int kdf_hash_algo; int kdf_encr_algo; unsigned char message[256]; @@ -139,11 +139,11 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, return err; } - secret_x_size = (nbits+7)/8; + secret_x_size = (nbits+7)/8; assert (nbytes > secret_x_size); memmove (secret_x, secret_x+1, secret_x_size); memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); - + if (DBG_CIPHER) log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size ); } @@ -158,24 +158,24 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, */ if (!gcry_mpi_get_flag (pkey[2], GCRYMPI_FLAG_OPAQUE)) return GPG_ERR_BUG; - kdf_params = gcry_mpi_get_opaque (pkey[2], &nbits); - kdf_params_size = (nbits+7)/8; - + kek_params = gcry_mpi_get_opaque (pkey[2], &nbits); + kek_params_size = (nbits+7)/8; + if (DBG_CIPHER) - log_printhex ("ecdh KDF params:", kdf_params, kdf_params_size); - + log_printhex ("ecdh KDF params:", kek_params, kek_params_size); + /* Expect 4 bytes 03 01 hash_alg symm_alg. */ - if (kdf_params_size != 4 || kdf_params[0] != 3 || kdf_params[1] != 1) + if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1) return GPG_ERR_BAD_PUBKEY; - - kdf_hash_algo = kdf_params[2]; - kdf_encr_algo = kdf_params[3]; - + + kdf_hash_algo = kek_params[2]; + kdf_encr_algo = kek_params[3]; + if (DBG_CIPHER) log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n", openpgp_md_algo_name (kdf_hash_algo), openpgp_cipher_algo_name (kdf_encr_algo)); - + if (kdf_hash_algo != GCRY_MD_SHA256 && kdf_hash_algo != GCRY_MD_SHA384 && kdf_hash_algo != GCRY_MD_SHA512) @@ -199,7 +199,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, /* fixed-length field 4 */ iobuf_write (obuf, "Anonymous Sender ", 20); /* fixed-length field 5, recipient fp */ - iobuf_write (obuf, pk_fp, 20); + iobuf_write (obuf, pk_fp, 20); message_size = iobuf_temp_to_buffer (obuf, message, sizeof message); iobuf_close (obuf); @@ -207,11 +207,10 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, return err; if(DBG_CIPHER) - log_printhex ("ecdh KDF message params are:", - kdf_params, kdf_params_size ); + log_printhex ("ecdh KDF message params are:", message, message_size); } - /* Derive a KEK (key wrapping key) using kdf_params and secret_x. */ + /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */ { gcry_md_hd_t h; int old_size; @@ -222,7 +221,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, kdf_hash_algo, gpg_strerror (err)); gcry_md_write(h, "\x00\x00\x00\x01", 4); /* counter = 1 */ gcry_md_write(h, secret_x, secret_x_size); /* x of the point X */ - gcry_md_write(h, kdf_params, kdf_params_size);/* KDF parameters */ + gcry_md_write(h, message, message_size);/* KDF parameters */ gcry_md_final (h); @@ -242,7 +241,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, if (DBG_CIPHER) log_printhex ("ecdh KEK is:", secret_x, secret_x_size ); } - + /* And, finally, aeswrap with key secret_x. */ { gcry_cipher_hd_t hd; @@ -284,7 +283,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, if (is_encrypt) { byte *in = data_buf+1+data_buf_size+8; - + /* Write data MPI into the end of data_buf. data_buf is size aeswrap data. */ err = gcry_mpi_print (GCRYMPI_FMT_USG, in, @@ -296,7 +295,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, xfree (data_buf); return err; } - + if (DBG_CIPHER) log_printhex ("ecdh encrypting :", in, data_buf_size ); @@ -325,14 +324,14 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, gpg_strerror (err)); return err; } - + *r_result = result; } else { byte *in; const void *p; - + p = gcry_mpi_get_opaque (data, &nbits); nbytes = (nbits+7)/8; if (!p || nbytes > data_buf_size || !nbytes) @@ -349,10 +348,10 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } in = data_buf+data_buf_size; data_buf_size = data_buf[0]; - + if (DBG_CIPHER) log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size); - + err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size); gcry_cipher_close (hd); @@ -363,12 +362,12 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, xfree (data_buf); return err; } - + data_buf_size -= 8; - + if (DBG_CIPHER) log_printhex ("ecdh decrypted to :", in, data_buf_size); - + /* Padding is removed later. */ /* if (in[data_buf_size-1] > 8 ) */ /* { */ @@ -376,7 +375,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, /* in[data_buf_size-1] ); */ /* return GPG_ERR_BAD_KEY; */ /* } */ - + err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, in, data_buf_size, NULL); xfree (data_buf); if (err) @@ -385,11 +384,11 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, gpg_strerror (err)); return err; } - + *r_result = result; } } - + return err; } @@ -453,5 +452,3 @@ pk_ecdh_decrypt (gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], sk_fp, data/*encr data as an MPI*/, skey, result); } - - diff --git a/g10/export.c b/g10/export.c index 1eb0baa8b..91a6c87f1 100644 --- a/g10/export.c +++ b/g10/export.c @@ -107,7 +107,7 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, kbnode_t *keyblock_out, unsigned int options ) { int any, rc; - + rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any); if (!rc && !any) rc = -1; @@ -197,9 +197,9 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options ) int any, rc; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; - + memset( &zfx, 0, sizeof zfx); - + rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out ); if (rc) return rc; @@ -251,7 +251,7 @@ subkey_in_list_p (subkey_list_t list, KBNODE node) u32 kid[2]; keyid_from_pk (node->pkt->pkt.public_key, kid); - + for (; list; list = list->next) if (list->kid[0] == kid[0] && list->kid[1] == kid[1]) return 1; @@ -293,17 +293,17 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) case KEYDB_SEARCH_MODE_LONG_KID: keyid_from_pk (node->pkt->pkt.public_key, kid); break; - + case KEYDB_SEARCH_MODE_FPR16: case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen); break; - + default: break; } - + switch(desc->mode) { case KEYDB_SEARCH_MODE_SHORT_KID: @@ -346,7 +346,7 @@ canon_pubkey_algo (int algo) case GCRY_PK_RSA: case GCRY_PK_RSA_E: case GCRY_PK_RSA_S: return GCRY_PK_RSA; - case GCRY_PK_ELG: + case GCRY_PK_ELG: case GCRY_PK_ELG_E: return GCRY_PK_ELG; default: return algo; } @@ -354,7 +354,7 @@ canon_pubkey_algo (int algo) /* Use the key transfer format given in S_PGP to create the secinfo - structure in PK and chnage the parameter array in PK to include the + structure in PK and change the parameter array in PK to include the secret parameters. */ static gpg_error_t transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) @@ -415,7 +415,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) goto bad_seckey; protect_algo = gcry_cipher_map_name (string); xfree (string); - + value = gcry_sexp_nth_data (list, 3, &valuelen); if (!value || !valuelen || valuelen > sizeof iv) goto bad_seckey; @@ -460,6 +460,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey) || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY) goto bad_seckey; + pubkey_algo = map_pk_gcry_to_openpgp (pubkey_algo); gcry_sexp_release (list); list = gcry_sexp_find_token (top_list, "skey", 0); @@ -557,6 +558,77 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) goto leave; } + /* We need to change the received parameters for ECC algorithms. + The transfer format has all parameters but OpenPGP defines that + only the OID of the curve is to be used. */ + if (pubkey_algo == PUBKEY_ALGO_ECDSA || pubkey_algo == PUBKEY_ALGO_ECDH) + { + gcry_sexp_t s_pubkey; + const char *curvename, *curveoidstr; + gcry_mpi_t mpi; + + /* We build an S-expression with the public key parameters and + ask Libgcrypt to return the matching curve name. */ + if (npkey != 6 || !skey[0] || !skey[1] || !skey[2] + || !skey[3] || !skey[4] || !skey[5] + || !skey[6] || skey[7]) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + err = gcry_sexp_build (&s_pubkey, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))", + skey[0], skey[1], skey[2], skey[3], skey[4]); + if (err) + goto leave; +#ifdef HAVE_GCRY_PK_GET_CURVE + curvename = gcry_pk_get_curve (s_pubkey, 0, NULL); +#else + curvename = "?"; +#endif + gcry_sexp_release (s_pubkey); + curveoidstr = gpg_curve_to_oid (curvename, NULL); + if (!curveoidstr) + { + log_error ("no OID known for curve `%s'\n", curvename); + err = gpg_error (GPG_ERR_UNKNOWN_NAME); + goto leave; + } + err = openpgp_oid_from_str (curveoidstr, &mpi); + if (err) + goto leave; + + /* Now replace the curve parameters by the OID and shift the + rest of the parameters. */ + gcry_mpi_release (skey[0]); + skey[0] = mpi; + for (idx=1; idx <= 4; idx++) + gcry_mpi_release (skey[idx]); + skey[1] = skey[5]; + skey[2] = skey[6]; + for (idx=3; idx <= 6; idx++) + skey[idx] = NULL; + + /* Fixup the NPKEY and NSKEY to match OpenPGP reality. */ + npkey = 2; + nskey = 3; + + /* for (idx=0; skey[idx]; idx++) */ + /* { */ + /* log_info ("YYY skey[%d]:", idx); */ + /* if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */ + /* { */ + /* void *p; */ + /* unsigned int nbits; */ + /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ + /* log_printhex (NULL, p, (nbits+7)/8); */ + /* } */ + /* else */ + /* gcry_mpi_dump (skey[idx]); */ + /* log_printf ("\n"); */ + /* } */ + } + /* Do some sanity checks. */ if (s2k_count <= 1024) { @@ -576,11 +648,17 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) err = openpgp_md_test_algo (s2k_algo); if (err) goto leave; - - /* Check that the public key parameters match. */ + + /* Check that the public key parameters match. Since Libgcrypt 1.5 + and the gcry_pk_get_curve function, gcry_mpi_cmp handles opaque + MPI correctly and thus we don't need to to do the extra + opaqueness checks. */ for (idx=0; idx < npkey; idx++) - if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE) + if (0 +#ifndef HAVE_GCRY_PK_GET_CURVE + gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE) || gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE) +#endif || gcry_mpi_cmp (pk->pkey[idx], skey[idx])) { err = gpg_error (GPG_ERR_BAD_PUBKEY); @@ -607,7 +685,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) err = gpg_error_from_syserror (); goto leave; } - + ski->is_protected = 1; ski->sha1chk = 1; ski->algo = protect_algo; @@ -636,7 +714,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) bad_seckey: err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; - + outofmem: err = gpg_error (GPG_ERR_ENOMEM); goto leave; @@ -671,7 +749,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, init_packet (&pkt); kdbhd = keydb_new (); - if (!users) + if (!users) { ndesc = 1; desc = xcalloc (ndesc, sizeof *desc); @@ -679,10 +757,10 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } else { - for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) + for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) ; desc = xmalloc ( ndesc * sizeof *desc); - + for (ndesc=0, sl=users; sl; sl = sl->next) { if (!(err=classify_user_id (sl->d, desc+ndesc))) @@ -708,7 +786,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, goto leave; } #endif - + /* For secret key export we need to setup a decryption context. */ if (secret) { @@ -721,7 +799,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } - + /* Prepare a cipher context. */ err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); @@ -737,20 +815,20 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kek = NULL; } - while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) + while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) { int skip_until_subkey = 0; u32 keyid[2]; PKT_public_key *pk; - if (!users) + if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* Read the keyblock. */ release_kbnode (keyblock); keyblock = NULL; err = keydb_get_keyblock (kdbhd, &keyblock); - if (err) + if (err) { log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); goto leave; @@ -802,7 +880,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); /* And write it. */ - for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) { if (skip_until_subkey) { @@ -835,7 +913,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, subkey and include that subkey into the output too. Need to add this subkey to a list so that it won't get processed a second time. - + So the first step here is to check that list and skip in any case if the key is in that list. @@ -843,7 +921,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, function of GnuPG < 2.1 is not able to merge secret keys and thus it is useless to output them as two separate keys and have import merge them. */ - if (subkey_in_list_p (subkey_list, node)) + if (subkey_in_list_p (subkey_list, node)) skip_until_subkey = 1; /* Already processed this one. */ else { @@ -854,7 +932,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, && exact_subkey_match_p (desc+j, node)) break; if (!(j < ndesc)) - skip_until_subkey = 1; /* No other one matching. */ + skip_until_subkey = 1; /* No other one matching. */ } } @@ -885,7 +963,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, && node->pkt->pkt.signature->revkey) { int i; - + for (i=0;ipkt->pkt.signature->numrevkeys;i++) if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40)) break; @@ -904,7 +982,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, or a signature on an attrib */ while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) kbctx = kbctx->next; - + continue; } @@ -913,7 +991,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, { u32 subkidbuf[2], *subkid; char *hexgrip, *serialno; - + pk = node->pkt->pkt.public_key; if (node->pkt->pkttype == PKT_PUBLIC_KEY) subkid = NULL; @@ -930,7 +1008,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, skip_until_subkey = 1; continue; } - + err = hexkeygrip_from_pk (pk, &hexgrip); if (err) { @@ -970,7 +1048,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, /* Create a key stub. */ struct seckey_info *ski; const char *s; - + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); if (!ski) { @@ -989,7 +1067,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, ski->ivlen++, s += 2) ski->iv[ski->ivlen] = xtoi_2 (s); } - + if ((options&EXPORT_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else @@ -1032,7 +1110,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); if (!realkeylen) goto unwraperror; /* Invalid csexp. */ - + err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); xfree (key); key = NULL; @@ -1252,7 +1330,7 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) /* For some packet types we write them in a S-expression format. This is still EXPERIMENTAL and subject to change. */ -static int +static int build_sexp (iobuf_t out, PACKET *pkt, int *indent) { int rc; diff --git a/g10/gpg.c b/g10/gpg.c index 47e8b361f..6daa144be 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1959,6 +1959,9 @@ main (int argc, char **argv) NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); } + /* Use our own logging handler for Libcgrypt. */ + setup_libgcrypt_logging (); + /* Put random number into secure memory */ gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); diff --git a/g10/import.c b/g10/import.c index 88abafd6a..99398c762 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1,6 +1,6 @@ /* import.c - import a key into our key storage. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2010 Free Software Foundation, Inc. + * 2007, 2010, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -200,7 +200,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames, rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options); iobuf_close(inp2); /* Must invalidate that ugly cache to actually close it. */ - iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, + iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); if( rc ) log_error("import from `%s' failed: %s\n", fname, @@ -294,7 +294,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats, if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) rc = import_one (ctrl, fname, keyblock, stats, fpr, fpr_len, options, 0); - else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) + else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) rc = import_secret_one (ctrl, fname, keyblock, stats, options); else if( keyblock->pkt->pkttype == PKT_SIGNATURE && keyblock->pkt->pkt.signature->sig_class == 0x20 ) @@ -647,7 +647,7 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock) kbnode_t node; PKT_public_key *pk; int problem=0; - + merge_keys_and_selfsig(keyblock); pk=keyblock->pkt->pkt.public_key; @@ -672,9 +672,9 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock) { if (openpgp_cipher_test_algo (prefs->value)) { - const char *algo = + const char *algo = (openpgp_cipher_test_algo (prefs->value) - ? num + ? num : openpgp_cipher_algo_name (prefs->value)); if(!problem) check_prefs_warning(pk); @@ -689,7 +689,7 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock) { const char *algo = (gcry_md_test_algo (prefs->value) - ? num + ? num : gcry_md_algo_name (prefs->value)); if(!problem) check_prefs_warning(pk); @@ -801,7 +801,7 @@ import_one (ctrl_t ctrl, log_error( _("key %s: no user ID\n"), keystr_from_pk(pk)); return 0; } - + if (opt.interactive) { if(is_status_enabled()) print_import_check (pk, uidnode->pkt->pkt.user_id); @@ -938,7 +938,7 @@ import_one (ctrl_t ctrl, size_t an; fingerprint_from_pk (pk_orig, afp, &an); - while (an < MAX_FINGERPRINT_LEN) + while (an < MAX_FINGERPRINT_LEN) afp[an++] = 0; rc = keydb_search_fpr (hd, afp); } @@ -962,7 +962,7 @@ import_one (ctrl_t ctrl, n_sigs_cleaned = fix_bad_direct_key_sigs (keyblock_orig, keyid); if (n_sigs_cleaned) commit_kbnode (&keyblock_orig); - + /* and try to merge the block */ clear_kbnode_flags( keyblock_orig ); clear_kbnode_flags( keyblock ); @@ -1032,13 +1032,13 @@ import_one (ctrl_t ctrl, stats->n_sigs_cleaned +=n_sigs_cleaned; stats->n_uids_cleaned +=n_uids_cleaned; - if (is_status_enabled ()) + if (is_status_enabled ()) print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0))); } else { same_key = 1; - if (is_status_enabled ()) + if (is_status_enabled ()) print_import_ok (pk, 0); if( !opt.quiet ) @@ -1107,6 +1107,37 @@ import_one (ctrl_t ctrl, } +/* Extract one MPI value from the S-expression PKEY which is expected + to hold a "public-key". Returns NULL on error. */ +static gcry_mpi_t +one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen) +{ + gcry_sexp_t list, l2; + gcry_mpi_t a; + + list = gcry_sexp_find_token (pkey, "public-key", 0); + if (!list) + return NULL; + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + if (!list) + return NULL; + + l2 = gcry_sexp_find_token (list, name, namelen); + if (!l2) + { + gcry_sexp_release (list); + return NULL; + } + a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + gcry_sexp_release (list); + + return a; +} + + /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The function prints diagnostics and returns an error code. */ static gpg_error_t @@ -1133,6 +1164,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) unsigned char *wrappedkey = NULL; size_t wrappedkeylen; char *cache_nonce = NULL; + gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL}; /* Get the current KEK. */ err = agent_keywrap_key (ctrl, 0, &kek, &keklen); @@ -1148,7 +1180,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) - goto leave; xfree (kek); + goto leave; + xfree (kek); kek = NULL; main_pk = NULL; @@ -1161,6 +1194,20 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) if (!main_pk) main_pk = pk; + /* Make sure the keyids are available. */ + keyid_from_pk (pk, NULL); + if (node->pkt->pkttype == PKT_SECRET_KEY) + { + pk->main_keyid[0] = pk->keyid[0]; + pk->main_keyid[1] = pk->keyid[1]; + } + else + { + pk->main_keyid[0] = main_pk->keyid[0]; + pk->main_keyid[1] = main_pk->keyid[1]; + } + + ski = pk->seckey_info; if (!ski) BUG (); @@ -1191,34 +1238,109 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) init_membuf (&mbuf, 50); put_membuf_str (&mbuf, "(skey"); - for (i=j=0; i < nskey; i++) + if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA + || pk->pubkey_algo == PUBKEY_ALGO_ECDH) { - if (!pk->pkey[i]) - ; /* Protected keys only have NPKEY+1 elements. */ - else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) - { - put_membuf_str (&mbuf, " e %b"); - format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i], &n); - format_args_buf_int[i] = (n+7)/8; - format_args[j++] = format_args_buf_int + i; - format_args[j++] = format_args_buf_ptr + i; - } + /* We need special treatment for ECC algorithms. OpenPGP + stores only the curve name but the agent expects a full + key. This is so that we can keep all curve name + validation code out of gpg-agent. */ +#if PUBKEY_MAX_NSKEY < 7 +#error PUBKEY_MAX_NSKEY too low for ECC +#endif + char *curve = openpgp_oid_to_str (pk->pkey[0]); + if (!curve) + err = gpg_error_from_syserror (); else { - put_membuf_str (&mbuf, " _ %m"); - format_args[j++] = pk->pkey + i; +#ifdef HAVE_GCRY_PK_GET_CURVE /* Also ensures availability of get_param. */ + gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECDSA, curve); +#else + gcry_sexp_t cparam = NULL; +#endif + xfree (curve); + if (!cparam) + err = gpg_error (GPG_ERR_UNKNOWN_CURVE); + else + { + const char *s; + + /* Append the curve parameters P, A, B, G and N. */ + for (i=j=0; !err && *(s = "pabgn"+i); i++) + { + ecc_params[i] = one_mpi_from_pkey (cparam, s, 1); + if (!ecc_params[i]) + err = gpg_error (GPG_ERR_INV_CURVE); + else + { + put_membuf_str (&mbuf, " _ %m"); + format_args[j++] = ecc_params+i; + } + } + gcry_sexp_release (cparam); + if (!err) + { + /* Append the public key element Q. */ + put_membuf_str (&mbuf, " _ %m"); + format_args[j++] = pk->pkey + 1; + + /* Append the secret key element D. Note that + for ECDH we need to skip PKEY[2] because this + holds the KEK which is not needed. */ + i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2; + if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) + { + put_membuf_str (&mbuf, " e %b"); + format_args_buf_ptr[i] + = gcry_mpi_get_opaque (pk->pkey[i],&n); + format_args_buf_int[i] = (n+7)/8; + format_args[j++] = format_args_buf_int + i; + format_args[j++] = format_args_buf_ptr + i; + } + else + { + put_membuf_str (&mbuf, " _ %m"); + format_args[j++] = pk->pkey + i; + } + } + } + } + } + else + { + /* Standard case for the old (non-ECC) algorithms. */ + for (i=j=0; i < nskey; i++) + { + if (!pk->pkey[i]) + ; /* Protected keys only have NPKEY+1 elements. */ + else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) + { + put_membuf_str (&mbuf, " e %b"); + format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n); + format_args_buf_int[i] = (n+7)/8; + format_args[j++] = format_args_buf_int + i; + format_args[j++] = format_args_buf_ptr + i; + } + else + { + put_membuf_str (&mbuf, " _ %m"); + format_args[j++] = pk->pkey + i; + } } } put_membuf_str (&mbuf, ")\n"); put_membuf (&mbuf, "", 1); - { - char *format = get_membuf (&mbuf, NULL); - if (!format) - err = gpg_error_from_syserror (); - else - err = gcry_sexp_build_array (&skey, NULL, format, format_args); - xfree (format); - } + if (err) + xfree (get_membuf (&mbuf, NULL)); + else + { + char *format = get_membuf (&mbuf, NULL); + if (!format) + err = gpg_error_from_syserror (); + else + err = gcry_sexp_build_array (&skey, NULL, format, format_args); + xfree (format); + } if (err) { log_error ("error building skey array: %s\n", gpg_strerror (err)); @@ -1228,7 +1350,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) if (ski->is_protected) { char countbuf[35]; - + /* Note that the IVLEN may be zero if we are working on a dummy key. We can't express that in an S-expression and thus we send dummy data for the IV. */ @@ -1289,9 +1411,9 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) transferkey = NULL; /* Send the wrapped key to the agent. */ - { + { char *desc = gpg_format_keydesc (pk, 1, 1); - err = agent_import_key (ctrl, desc, &cache_nonce, + err = agent_import_key (ctrl, desc, &cache_nonce, wrappedkey, wrappedkeylen); xfree (desc); } @@ -1328,6 +1450,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock) } leave: + for (i=0; i < DIM (ecc_params); i++) + gcry_mpi_release (ecc_params[i]); xfree (cache_nonce); xfree (wrappedkey); xfree (transferkey); @@ -1392,7 +1516,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock) * with the trust calculation. */ static int -import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, +import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, struct stats_s *stats, unsigned int options) { PKT_public_key *pk; @@ -1400,17 +1524,17 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, KBNODE node, uidnode; u32 keyid[2]; int rc = 0; - + /* Get the key and print some info about it */ node = find_kbnode (keyblock, PKT_SECRET_KEY); if (!node) BUG (); - + pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); uidnode = find_next_kbnode (keyblock, PKT_USER_ID); - + if (opt.verbose) { log_info ("sec %4u%c/%s %s ", @@ -1423,7 +1547,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, log_printf ("\n"); } stats->secret_read++; - + if (!uidnode) { log_error( _("key %s: no user ID\n"), keystr_from_pk (pk)); @@ -1456,10 +1580,10 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, log_error (_("importing secret keys not allowed\n")); return 0; } -#endif - +#endif + clear_kbnode_flags (keyblock); - + if (!(options&IMPORT_MERGE_ONLY) || !have_secret_key_with_kid (keyid) ) { /* We don't have this key, insert as a new key. */ @@ -1477,7 +1601,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, /* Fixme: We should check for an invalid keyblock and cancel the secret key import in this case. */ release_kbnode (pub_keyblock); - + /* Read the keyblock again to get the effects of a merge. */ /* Fixme: we should do this based on the fingerprint or even better let import_one return the merged @@ -1493,7 +1617,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, if (!opt.quiet) log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk)); - if (is_status_enabled ()) + if (is_status_enabled ()) print_import_ok (pk, 1|16); check_prefs (ctrl, node); } @@ -1502,11 +1626,11 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, } } else - { + { /* We don't want to merge the secret keys. */ log_error (_("key %s: secret key part already available\n"), keystr_from_pk (pk)); - if (is_status_enabled ()) + if (is_status_enabled ()) print_import_ok (pk, 16); } @@ -1556,9 +1680,9 @@ import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats ) { byte afp[MAX_FINGERPRINT_LEN]; size_t an; - + fingerprint_from_pk (pk, afp, &an); - while (an < MAX_FINGERPRINT_LEN) + while (an < MAX_FINGERPRINT_LEN) afp[an++] = 0; rc = keydb_search_fpr (hd, afp); } @@ -1654,11 +1778,11 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, int rc; u32 bsdate=0, rsdate=0; kbnode_t bsnode = NULL, rsnode = NULL; - + (void)fname; (void)pk; - for (n=keyblock; (n = find_next_kbnode (n, 0)); ) + for (n=keyblock; (n = find_next_kbnode (n, 0)); ) { if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY) { @@ -1672,7 +1796,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, if ( n->pkt->pkttype != PKT_SIGNATURE ) continue; - + sig = n->pkt->pkt.signature; if ( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] ) { @@ -1684,7 +1808,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, import a fully-cached key which speeds things up. */ if (!opt.no_sig_cache) check_key_signature (keyblock, n, NULL); - + if ( IS_UID_SIG(sig) || IS_UID_REV(sig) ) { KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID ); @@ -1694,16 +1818,16 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, keystr(keyid)); return -1; /* The complete keyblock is invalid. */ } - + /* If it hasn't been marked valid yet, keep trying. */ - if (!(unode->flag&1)) + if (!(unode->flag&1)) { rc = check_key_signature (keyblock, n, NULL); if ( rc ) { if ( opt.verbose ) { - char *p = utf8_to_native + char *p = utf8_to_native (unode->pkt->pkt.user_id->name, strlen (unode->pkt->pkt.user_id->name),0); log_info (gpg_err_code(rc) == G10ERR_PUBKEY_ALGO ? @@ -1732,7 +1856,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, n->flag |= 4; } } - else if ( IS_SUBKEY_SIG (sig) ) + else if ( IS_SUBKEY_SIG (sig) ) { /* Note that this works based solely on the timestamps like the rest of gpg. If the standard gets revocation @@ -1761,19 +1885,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, else { /* It's valid, so is it newer? */ - if (sig->timestamp >= bsdate) + if (sig->timestamp >= bsdate) { knode->flag |= 1; /* The subkey is valid. */ if (bsnode) { /* Delete the last binding sig since this one is newer */ - bsnode->flag |= 4; + bsnode->flag |= 4; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " binding\n"),keystr(keyid)); } - + bsnode = n; bsdate = sig->timestamp; } @@ -1818,12 +1942,12 @@ chk_self_sigs (const char *fname, kbnode_t keyblock, { /* Delete the last revocation sig since this one is newer. */ - rsnode->flag |= 4; + rsnode->flag |= 4; if (opt.verbose) log_info (_("key %s: removed multiple subkey" " revocation\n"),keystr(keyid)); } - + rsnode = n; rsdate = sig->timestamp; } diff --git a/g10/keygen.c b/g10/keygen.c index 4d911f0b9..d8535fa61 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1080,6 +1080,40 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, return err; } +/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL + store the bit size of the curve there. Returns NULL for unknown + curve names. */ +const char * +gpg_curve_to_oid (const char *name, unsigned int *r_nbits) +{ + unsigned int nbits = 0; + const char *oidstr; + + if (!name) + oidstr = NULL; + else if (!strcmp (name, "NIST P-256")) + { + oidstr = "1.2.840.10045.3.1.7"; + nbits = 256; + } + else if (!strcmp (name, "NIST P-384")) + { + oidstr = "1.3.132.0.34"; + nbits = 384; + } + else if (!strcmp (name, "NIST P-521")) + { + oidstr = "1.3.132.0.35"; + nbits = 521; + } + else + oidstr = NULL; + + if (r_nbits) + *r_nbits = nbits; + return oidstr; +} + static gpg_error_t ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) @@ -1117,23 +1151,11 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) goto leave; } gcry_sexp_release (l2); - if (!strcmp (curve, "NIST P-256")) - { - oidstr = "1.2.840.10045.3.1.7"; - nbits = 256; - } - else if (!strcmp (curve, "NIST P-384")) - { - oidstr = "1.3.132.0.34"; - nbits = 384; - } - else if (!strcmp (curve, "NIST P-521")) - { - oidstr = "1.3.132.0.35"; - nbits = 521; - } - else + oidstr = gpg_curve_to_oid (curve, &nbits); + if (!oidstr) { + /* That can't happen because we used one of the curves + gpg_curve_to_oid knows about. */ err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } @@ -1445,7 +1467,8 @@ gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root, assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH); - /* For now we may only use one of the 3 NISY curves. */ + /* For now we may only use one of the 3 NIST curves. See also + gpg_curve_to_oid. */ if (nbits <= 256) curve = "NIST P-256"; else if (nbits <= 384) diff --git a/g10/keyid.c b/g10/keyid.c index 6571a51c0..cbcc971c3 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -39,7 +39,7 @@ #ifdef HAVE_UNSIGNED_TIME_T # define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1)) -#else +#else /* Error or 32 bit time_t and value after 2038-01-19. */ # define IS_INVALID_TIME_T(a) ((a) < 0) #endif @@ -81,6 +81,11 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) if(pk->version<4) n+=2; + /* FIXME: We can avoid the extra malloc by calling only the first + mpi_print here which computes the required length and calling the + real mpi_print only at the end. The speed advantage would only be + for ECC (opaque MPIs) or if we could implement an mpi_print + variant with a callback handler to do the hashing. */ if (npkey==0 && pk->pkey[0] && gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE)) { @@ -92,25 +97,32 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) { for (i=0; i < npkey; i++ ) { - enum gcry_mpi_format fmt; - - if ((pk->pubkey_algo == PUBKEY_ALGO_ECDSA - || pk->pubkey_algo == PUBKEY_ALGO_ECDH) - && (i == 0 || i == 2)) - fmt = GCRYMPI_FMT_USG; /* Name of OID or KEK parms. */ + if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) + { + size_t nbits; + const void *p; + + p = gcry_mpi_get_opaque (pk->pkey[i], &nbits); + pp[i] = xmalloc ((nbits+7)/8); + memcpy (pp[i], p, (nbits+7)/8); + nn[i] = (nbits+7)/8; + n += nn[i]; + } else - fmt = GCRYMPI_FMT_PGP; - - if (gcry_mpi_print (fmt, NULL, 0, &nbytes, pk->pkey[i])) - BUG (); - pp[i] = xmalloc (nbytes); - if (gcry_mpi_print (fmt, pp[i], nbytes, &nbytes, pk->pkey[i])) - BUG (); - nn[i] = nbytes; - n += nn[i]; + { + if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, + &nbytes, pk->pkey[i])) + BUG (); + pp[i] = xmalloc (nbytes); + if (gcry_mpi_print (GCRYMPI_FMT_PGP, pp[i], nbytes, + &nbytes, pk->pkey[i])) + BUG (); + nn[i] = nbytes; + n += nn[i]; + } } } - + gcry_md_putc ( md, 0x99 ); /* ctb */ /* What does it mean if n is greater than than 0xFFFF ? */ gcry_md_putc ( md, n >> 8 ); /* 2 byte length header */ @@ -127,7 +139,7 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk) u16 days=0; if(pk->expiredate) days=(u16)((pk->expiredate - pk->timestamp) / 86400L); - + gcry_md_putc ( md, days >> 8 ); gcry_md_putc ( md, days ); } @@ -178,7 +190,7 @@ v3_keyid (gcry_mpi_t a, u32 *ki) BUG (); if (nbytes < 8) /* oops */ ki[0] = ki[1] = 0; - else + else { p = buffer + nbytes - 8; ki[0] = (p[0] << 24) | (p[1] <<16) | (p[2] << 8) | p[3]; @@ -215,7 +227,7 @@ keystrlen(void) const char * keystr (u32 *keyid) -{ +{ static char keyid_str[KEYID_STR_SIZE]; switch (opt.keyid_format) @@ -226,7 +238,7 @@ keystr (u32 *keyid) case KF_LONG: if (keyid[0]) - snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX", + snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1]); else snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]); @@ -238,12 +250,12 @@ keystr (u32 *keyid) case KF_0xLONG: if(keyid[0]) - snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX", + snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX", (ulong)keyid[0],(ulong)keyid[1]); else snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]); break; - + default: BUG(); } @@ -254,7 +266,7 @@ keystr (u32 *keyid) const char * keystr_with_sub (u32 *main_kid, u32 *sub_kid) -{ +{ static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE]; char *p; @@ -408,7 +420,7 @@ keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ) else keyid_from_pk (&pk, keyid); } - else + else { const byte *dp = fprint; keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; @@ -422,7 +434,7 @@ keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid ) u32 keyid_from_sig (PKT_signature *sig, u32 *keyid) { - if( keyid ) + if( keyid ) { keyid[0] = sig->keyid[0]; keyid[1] = sig->keyid[1]; @@ -437,13 +449,13 @@ namehash_from_uid (PKT_user_id *uid) if (!uid->namehash) { uid->namehash = xmalloc (20); - + if (uid->attrib_data) rmd160_hash_buffer (uid->namehash, uid->attrib_data, uid->attrib_len); else rmd160_hash_buffer (uid->namehash, uid->name, uid->len); } - + return uid->namehash; } @@ -465,7 +477,7 @@ mk_datestr (char *buffer, time_t atime) if (IS_INVALID_TIME_T (atime)) strcpy (buffer, "????" "-??" "-??"); /* Mark this as invalid. */ - else + else { tp = gmtime (&atime); sprintf (buffer,"%04d-%02d-%02d", @@ -485,7 +497,7 @@ datestr_from_pk (PKT_public_key *pk) { static char buffer[11+5]; time_t atime = pk->timestamp; - + return mk_datestr (buffer, atime); } @@ -518,7 +530,7 @@ expirestr_from_sig (PKT_signature *sig) { static char buffer[11+5]; time_t atime; - + if (!sig->expiredate) return _("never "); atime=sig->expiredate; @@ -591,7 +603,7 @@ const char * colon_datestr_from_sig (PKT_signature *sig) { static char buf[20]; - + snprintf (buf, sizeof buf, "%lu", (ulong)sig->timestamp); return buf; } @@ -621,21 +633,21 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) const byte *dp; size_t len, nbytes; int i; - + if ( pk->version < 4 ) { if ( is_RSA(pk->pubkey_algo) ) { /* RSA in version 3 packets is special. */ gcry_md_hd_t md; - + if (gcry_md_open (&md, DIGEST_ALGO_MD5, 0)) BUG (); - if ( pubkey_get_npkey (pk->pubkey_algo) > 1 ) + if ( pubkey_get_npkey (pk->pubkey_algo) > 1 ) { for (i=0; i < 2; i++) { - if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, + if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nbytes, pk->pkey[i])) BUG (); /* fixme: Better allocate BUF on the stack */ @@ -662,10 +674,10 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) memset (array,0,16); } } - else + else { gcry_md_hd_t md; - + md = do_fingerprint_md(pk); dp = gcry_md_read( md, 0 ); len = gcry_md_get_algo_dlen (gcry_md_get_algo (md)); @@ -677,7 +689,7 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; gcry_md_close( md); } - + *ret_len = len; return array; } @@ -694,7 +706,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) { gpg_error_t err; gcry_sexp_t s_pkey; - + if (DBG_PACKET) log_debug ("get_keygrip for public key\n"); @@ -742,7 +754,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) err = gpg_error (GPG_ERR_PUBKEY_ALGO); break; } - + if (err) return err; @@ -758,7 +770,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) /* FIXME: Save the keygrip in PK. */ } gcry_sexp_release (s_pkey); - + return 0; } @@ -786,4 +798,3 @@ hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) } return err; } - diff --git a/g10/main.h b/g10/main.h index d70c16901..920d82c97 100644 --- a/g10/main.h +++ b/g10/main.h @@ -236,6 +236,7 @@ void keyedit_passwd (ctrl_t ctrl, const char *username); void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ +const char *gpg_curve_to_oid (const char *name, unsigned int *r_nbits); u32 parse_expire_string(const char *string); u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expiredate(void); diff --git a/g10/passphrase.c b/g10/passphrase.c index f29fca72f..8065810c9 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -74,7 +74,7 @@ encode_s2k_iterations (int iterations) if (err && gpg_err_code (err) != GPG_ERR_ASS_PARAMETER) log_error (_("problem with the agent: %s\n"), gpg_strerror (err)); /* Default to 65536 which we used up to 2.0.13. */ - return 96; + return 96; } else if (mycnt >= 65011712) return 255; /* Largest possible value. */ @@ -87,7 +87,7 @@ encode_s2k_iterations (int iterations) if (iterations >= 65011712) return 255; - + /* Need count to be in the range 16-31 */ for (count=iterations>>6; count>=32; count>>=1) c++; @@ -96,13 +96,13 @@ encode_s2k_iterations (int iterations) if (S2K_DECODE_COUNT(result) < iterations) result++; - + return result; } -/* Hash a passphrase using the supplied s2k. +/* Hash a passphrase using the supplied s2k. Always needs: dek->algo, s2k->mode, s2k->hash_algo. */ static void hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k) @@ -119,20 +119,20 @@ hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k) if (gcry_md_open (&md, s2k->hash_algo, 1)) BUG (); - for (pass=0; used < dek->keylen ; pass++ ) + for (pass=0; used < dek->keylen ; pass++ ) { - if ( pass ) + if ( pass ) { gcry_md_reset (md); for (i=0; i < pass; i++ ) /* Preset the hash context. */ gcry_md_putc (md, 0 ); } - if ( s2k->mode == 1 || s2k->mode == 3 ) + if ( s2k->mode == 1 || s2k->mode == 3 ) { int len2 = pwlen + 8; ulong count = len2; - + if ( s2k->mode == 3 ) { count = S2K_DECODE_COUNT(s2k->count); @@ -146,7 +146,7 @@ hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k) /* A little bit complicated because we need a ulong for count. */ while ( count > len2 ) /* maybe iterated+salted */ - { + { gcry_md_write ( md, s2k->salt, 8 ); gcry_md_write ( md, pw, pwlen ); count -= len2; @@ -231,7 +231,7 @@ read_passphrase_from_fd( int fd ) int i, len; char *pw; - if ( !opt.batch ) + if ( !opt.batch ) { /* Not used but we have to do a dummy read, so that it won't end up at the begin of the message if the quite usual trick to prepend the passphtrase to the message is used. */ @@ -240,12 +240,12 @@ read_passphrase_from_fd( int fd ) while (!(read (fd, buf, 1) != 1 || *buf == '\n' )) ; *buf = 0; - return; + return; } - for (pw = NULL, i = len = 100; ; i++ ) + for (pw = NULL, i = len = 100; ; i++ ) { - if (i >= len-1 ) + if (i >= len-1 ) { char *pw2 = pw; len += 100; @@ -311,35 +311,35 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, if( keyid && get_pubkey( pk, keyid ) ) { if (pk) - free_public_key( pk ); + free_public_key( pk ); pk = NULL; /* oops: no key for some reason */ } - + orig_codeset = i18n_switchto_utf8 (); if (custom_description) atext = native_to_utf8 (custom_description); else if ( !mode && pk && keyid ) - { + { char *uid; size_t uidlen; const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo ); const char *timestr; char *maink; - + if ( !algo_name ) algo_name = "?"; #define KEYIDSTRING _(" (main key ID %s)") maink = xmalloc ( strlen (KEYIDSTRING) + keystrlen() + 20 ); - if( keyid[2] && keyid[3] && keyid[0] != keyid[2] + if( keyid[2] && keyid[3] && keyid[0] != keyid[2] && keyid[1] != keyid[3] ) sprintf( maink, KEYIDSTRING, keystr(&keyid[2]) ); else *maink = 0; - - uid = get_user_id ( keyid, &uidlen ); + + uid = get_user_id ( keyid, &uidlen ); timestr = strtimestamp (pk->timestamp); #undef KEYIDSTRING @@ -350,7 +350,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, "%u-bit %s key, ID %s,\n" \ "created %s%s.\n" ) - atext = xmalloc ( 100 + strlen (PROMPTSTRING) + atext = xmalloc ( 100 + strlen (PROMPTSTRING) + uidlen + 15 + strlen(algo_name) + keystrlen() + strlen (timestr) + strlen (maink) ); sprintf (atext, PROMPTSTRING, @@ -362,16 +362,16 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, #undef PROMPTSTRING - { + { size_t dummy; fingerprint_from_pk( pk, fpr, &dummy ); have_fpr = 1; } - + } else atext = xstrdup ( _("Enter passphrase\n") ); - + if (!mode && cacheid) my_cacheid = cacheid; @@ -387,7 +387,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext, repeat, check, &pw); - + xfree (my_prompt); xfree (atext); atext = NULL; @@ -396,14 +396,14 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, if (!rc) ; - else if (gpg_err_code (rc) == GPG_ERR_CANCELED + else if (gpg_err_code (rc) == GPG_ERR_CANCELED || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) { log_info (_("cancelled by user\n") ); if (canceled) *canceled = 1; } - else + else { log_error (_("problem with the agent: %s\n"), gpg_strerror (rc)); /* Due to limitations in the API of the upper layers they @@ -412,7 +412,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, definitely not happen and let it continue without requiring a passphrase. Given that now all the upper layers handle a cancel correctly, we simply set the cancel flag now for all - errors from the agent. */ + errors from the agent. */ if (canceled) *canceled = 1; @@ -440,7 +440,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) int rc; (void)algo; - + if (!cacheid) { PKT_public_key *pk; @@ -450,7 +450,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) byte fpr[MAX_FINGERPRINT_LEN]; char hexfprbuf[2*20+1]; size_t dummy; - + pk = xcalloc (1, sizeof *pk); if ( !keyid || get_pubkey( pk, keyid ) ) { @@ -478,7 +478,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) NULL, sets it to true. MODE 0: Allow cached passphrase - 1: Ignore cached passphrase + 1: Ignore cached passphrase 2: Ditto, but create a new key 3: Allow cached passphrase; use the S2K salt as the cache ID 4: Ditto, but create a new key @@ -486,7 +486,7 @@ passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) DEK * passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, - const char *tryagain_text, + const char *tryagain_text, const char *custdesc, const char *custprompt, int *canceled) { @@ -499,11 +499,11 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, if (!canceled) canceled = &dummy_canceled; *canceled = 0; - + if ( !s2k ) { assert (mode != 3 && mode != 4); - /* This is used for the old rfc1991 mode + /* This is used for the old rfc1991 mode * Note: This must match the code in encode.c with opt.rfc1991 set */ s2k = &help_s2k; s2k->mode = 0; @@ -529,16 +529,16 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, /* If we do not have a passphrase available in NEXT_PW and status information are request, we print them now. */ - if ( !next_pw && is_status_enabled() ) + if ( !next_pw && is_status_enabled() ) { char buf[50]; - + if ( keyid ) { u32 used_kid[2]; char *us; - - if ( keyid[2] && keyid[3] ) + + if ( keyid[2] && keyid[3] ) { used_kid[0] = keyid[2]; used_kid[1] = keyid[3]; @@ -548,16 +548,16 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, used_kid[0] = keyid[0]; used_kid[1] = keyid[1]; } - + us = get_long_user_id_string ( keyid ); write_status_text ( STATUS_USERID_HINT, us ); xfree(us); - + snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0", (ulong)keyid[0], (ulong)keyid[1], (ulong)used_kid[0], (ulong)used_kid[1], pubkey_algo ); - + write_status_text ( STATUS_NEED_PASSPHRASE, buf ); } else @@ -576,7 +576,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, { PKT_public_key *pk = xmalloc_clear( sizeof *pk ); char *p; - + p = get_user_id_native(keyid); tty_printf ("\n"); tty_printf (_("You need a passphrase to unlock the secret key for\n" @@ -586,7 +586,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, if ( !get_pubkey( pk, keyid ) ) { const char *s = openpgp_pk_algo_name ( pk->pubkey_algo ); - + tty_printf (_("%u-bit %s key, ID %s, created %s"), nbits_from_pk( pk ), s?s:"?", keystr(keyid), strtimestamp(pk->timestamp) ); @@ -610,19 +610,19 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, free_public_key( pk ); } - if ( next_pw ) + if ( next_pw ) { /* Simply return the passphrase we already have in NEXT_PW. */ pw = next_pw; next_pw = NULL; } - else if ( have_static_passphrase () ) + else if ( have_static_passphrase () ) { /* Return the passphrase we have stored in FD_PASSWD. */ pw = xmalloc_secure ( strlen(fd_passwd)+1 ); strcpy ( pw, fd_passwd ); } - else + else { if ((mode == 3 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3)) { @@ -643,7 +643,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, return NULL; } } - + if ( !pw || !*pw ) write_status( STATUS_MISSING_PASSPHRASE ); @@ -689,15 +689,15 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped) char *maink; char *desc; const char *prompt; - + algo_name = openpgp_pk_algo_name (pk->pubkey_algo); timestr = strtimestamp (pk->timestamp); - uid = get_user_id (pk->keyid, &uidlen); + uid = get_user_id (pk->keyid, &uidlen); orig_codeset = i18n_switchto_utf8 (); if (pk->main_keyid[0] && pk->main_keyid[1] - && pk->keyid[0] != pk->main_keyid[0] + && pk->keyid[0] != pk->main_keyid[0] && pk->keyid[1] != pk->main_keyid[1]) maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid)); else @@ -724,7 +724,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped) "created %s%s.\n"), prompt, (int)uidlen, uid, - nbits_from_pk (pk), algo_name, + nbits_from_pk (pk), algo_name, keystr (pk->keyid), timestr, maink?maink:"" ); xfree (maink); @@ -735,7 +735,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped) if (escaped) { char *tmp = percent_plus_escape (desc); - xfree (desc); + xfree (desc); desc = tmp; } diff --git a/include/ChangeLog b/include/ChangeLog index 8dd88ffbb..81ba48bab 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2011-02-01 Werner Koch + + * cipher.h (PUBKEY_MAX_NPKEY, PUBKEY_MAX_NSKEY): Bump up to + accommodate gcrypt ECC keys. + 2011-01-21 Werner Koch * cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros diff --git a/include/cipher.h b/include/cipher.h index 311020857..4667e8043 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -100,8 +100,8 @@ typedef struct /* Constants to allocate static MPI arrays. */ -#define PUBKEY_MAX_NPKEY 4 -#define PUBKEY_MAX_NSKEY 6 +#define PUBKEY_MAX_NPKEY 5 +#define PUBKEY_MAX_NSKEY 7 #define PUBKEY_MAX_NSIG 2 #define PUBKEY_MAX_NENC 2 diff --git a/tests/openpgp/samplekeys/README b/tests/openpgp/samplekeys/README index d38616990..fd05aa3a4 100644 --- a/tests/openpgp/samplekeys/README +++ b/tests/openpgp/samplekeys/README @@ -1,4 +1,5 @@ no-creation-time.gpg A key with a zero creation time. - +ecc-sample-1-pub.asc The first ECC sample key. +ecc-sample-1-sec.asc The first ECC sample key (secret). diff --git a/tests/openpgp/samplekeys/ecc-sample-1-pub.asc b/tests/openpgp/samplekeys/ecc-sample-1-pub.asc new file mode 100644 index 000000000..478fc3aac --- /dev/null +++ b/tests/openpgp/samplekeys/ecc-sample-1-pub.asc @@ -0,0 +1,22 @@ +The key has been generated by the first GnuPG ECC version at +http://code.google.com/p/gnupg-ecc. + +The sample key has ECDSA top key 0xBAA59D9C and a single ECDH +encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128 +with KDF. + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.1.0-ecc (GNU/Linux) + +mFIETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs +xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLmtCRlY19kc2FfZGhf +MjU2IDxvcGVucGdwQGJyYWluaHViLm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgH +AwIGFQgCCQoLBBYCAwECHgECF4AACgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9d +JtLJ5As98Alit2oFwzhxG7mSVmQA/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehx +XDfpHj+/uFYETJPQrRIIKoZIzj0DAQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1X +XsRJEwrzftreZYrn7jXSDoiXkRyfVkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB4hh +BBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYBAOSUmaQ8rkgihnepbnpK7tNz +3QEocsLEtsTCDUBGNYGyAQDclifYqsUChXlWKaw3md+yHJPcWZXzHt37c4q/MhIm +oQ== +=hMzp +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/openpgp/samplekeys/ecc-sample-1-sec.asc b/tests/openpgp/samplekeys/ecc-sample-1-sec.asc new file mode 100644 index 000000000..5ff5555f2 --- /dev/null +++ b/tests/openpgp/samplekeys/ecc-sample-1-sec.asc @@ -0,0 +1,25 @@ +The key has been generated by the first GnuPG ECC version at +http://code.google.com/p/gnupg-ecc. + +The sample key has ECDSA top key 0xBAA59D9C and a single ECDH +encryption subkey 0x4089AB73. ECDH subkey uses SHA-256 and AES-128 +with KDF. The password for the key is "ecc". + +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v2.1.0-ecc (GNU/Linux) + +lJ0ETJPQrRMIKoZIzj0DAQcCAwQLx6e669XwjHTHe3HuROe7C1oYMXuZbaU5PjOs +xSkyxtL2D00e/jWgufuNN4ftS+6XygEtB7j1g1vnCTVF1TLm/gMDAmHomSLb9NbE +oyWUoqgKTbZzbFR/SWmiCcuiQEhREcTyvyU1hAglj7FsBJoQ6/pbeAEQZ3bVzlNM +8F0nF8KPLPuEADF1+4CntCRlY19kc2FfZGhfMjU2IDxvcGVucGdwQGJyYWluaHVi +Lm9yZz6IegQTEwgAIgUCTJPQrQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA +CgkQC6Ut8LqlnZzmXQEAiKgiSzPSpUOJcX9dJtLJ5As98Alit2oFwzhxG7mSVmQA +/RP67yOeoUtdsK6bwmRA95cwf9lBIusNjehxXDfpHj+/nKEETJPQrRIIKoZIzj0D +AQcCAwR/cMCoGEzcrqXbILqP7Rfke977dE1XXsRJEwrzftreZYrn7jXSDoiXkRyf +VkvjPZqUvB5cknsaoH/3UNLRHClxAwEIB/4DAwJh6Jki2/TWxKO7gHKWIcOcxYZp +CRWjlUghbKb6Q83p8GLPjKRN0USl/U1tObWdksqMXhUO0ePLWUnrbwoWYfYXg9Er +ADTgCYhhBBgTCAAJBQJMk9CtAhsMAAoJEAulLfC6pZ2c1yYA/3eJRirPQZmBno+Z +P/HOBSFWmFt4cUBGUx3oqiUd5loOAP480pb+vXx9ipljJWCJDSl/boRSuqB4hePP +qt9Rd5gNdQ== +=O8Dg +-----END PGP PRIVATE KEY BLOCK-----