diff options
Diffstat (limited to 'g10/import.c')
-rw-r--r-- | g10/import.c | 250 |
1 files changed, 187 insertions, 63 deletions
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)) + /* 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, " 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; +#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 + } + else + { + /* Standard case for the old (non-ECC) algorithms. */ + for (i=j=0; i < nskey; i++) { - put_membuf_str (&mbuf, " _ %m"); - format_args[j++] = pk->pkey + 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; } |