diff --git a/g10/ChangeLog b/g10/ChangeLog index 8e2d65552..d82afa181 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,38 @@ +2010-04-20 Werner Koch + + * keylist.c (list_keyblock_colon): Print the keygrip. + + * sign.c (do_sign): Call the agent to create the signature. + (mpi_from_sexp): New. + * keyid.c (keygrip_from_pk, hexkeygrip_from_pk): New. + * call-agent.c (agent_pksign): New. + * pkglue.c (pk_sign): Remove. + + * keygen.c (generate_keypair): Do not ask for a passphrase. + +2010-04-15 Werner Koch + + * keygen.c (gen_dsa, gen_elg, gen_rsa): Remove args SEC_ROOT, DEK, + S2K and RET_SK. Change to use the gpg-agent based key generation. + Factor common code out to ... + (common_gen): New. + (do_create): Remove args SEC_ROOT, DEK, S2K and RET_SK. + (do_generate_keypair, write_selfsigs, write_direct_sig) + (write_keybinding, make_backsig): Adjust for above changes. + (generate_subkeypair): Remove arg SEC_KEYBLOCK. + (genhelp_protect, genhelp_factors): Remove. + (get_parameter_dek, get_parameter_s2k): Remove. + + * call-agent.c (start_agent): Add dummy arg CTRL. + (agent_havekey, keyinfo_status_cb, agent_get_keyinfo) + (agent_genkey): New. + + * seckey-cert.c (check_secret_key): Remove + (is_secret_key_protected): Take a public key as arg. + (protect_secret_key): Remove. + + * seskey.c (encode_md_value): Remove SK arg. + 2010-04-14 Werner Koch * cpr.c (myread) [W32CE]: Do not use raise. diff --git a/g10/call-agent.c b/g10/call-agent.c index 260cd48a9..9379fcb52 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1,6 +1,6 @@ /* call-agent.c - Divert GPG operations to the agent. - * Copyright (C) 2001, 2002, 2003, 2006, 2007, - * 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009, + * 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -69,14 +69,15 @@ struct writekey_parm_s size_t keydatalen; }; -struct genkey_parm_s +struct genkey_parm_s { + ctrl_t ctrl; assuan_context_t ctx; - const char *sexp; - size_t sexplen; + const char *keyparms; }; + static gpg_error_t learn_status_cb (void *opaque, const char *line); @@ -107,10 +108,12 @@ status_sc_op_failure (int rc) /* Try to connect to the agent via socket or fork it off and work by pipes. Handle the server's initial greeting */ static int -start_agent (int for_card) +start_agent (ctrl_t ctrl, int for_card) { int rc; + (void)ctrl; /* Not yet used. */ + /* Fixme: We need a context for each thread or serialize the access to the agent. */ if (agent_ctx) @@ -486,7 +489,7 @@ agent_learn (struct agent_card_info_s *info) { int rc; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -531,7 +534,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) return gpg_error (GPG_ERR_TOO_LARGE); stpcpy (stpcpy (line, "SCD GETATTR "), name); - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -581,7 +584,7 @@ agent_scd_setattr (const char *name, } *p = 0; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (!rc) { rc = assuan_transact (agent_ctx, line, NULL, NULL, @@ -623,7 +626,7 @@ agent_scd_writecert (const char *certidstr, char line[ASSUAN_LINELENGTH]; struct writecert_parm_s parms; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -673,7 +676,7 @@ agent_scd_writekey (int keyno, const char *serialno, (void)serialno; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -762,7 +765,7 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, (void)serialno; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -909,7 +912,7 @@ agent_scd_pksign (const char *serialno, int hashalgo, *r_buf = NULL; *r_buflen = 0; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED) rc = 0; /* We check later. */ @@ -972,7 +975,7 @@ agent_scd_pkdecrypt (const char *serialno, size_t len; *r_buf = NULL; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED) rc = 0; /* We check later. */ @@ -1029,7 +1032,7 @@ agent_scd_readcert (const char *certidstr, size_t len; *r_buf = NULL; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -1077,7 +1080,7 @@ agent_scd_change_pin (int chvno, const char *serialno) reset = "--reset"; chvno %= 100; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -1099,7 +1102,7 @@ agent_scd_checkpin (const char *serialno) int rc; char line[ASSUAN_LINELENGTH]; - rc = start_agent (1); + rc = start_agent (NULL, 1); if (rc) return rc; @@ -1146,7 +1149,7 @@ agent_get_passphrase (const char *cache_id, *r_passphrase = NULL; - rc = start_agent (0); + rc = start_agent (NULL, 0); if (rc) return rc; @@ -1217,7 +1220,7 @@ agent_clear_passphrase (const char *cache_id) if (!cache_id || !*cache_id) return 0; - rc = start_agent (0); + rc = start_agent (NULL, 0); if (rc) return rc; @@ -1237,7 +1240,7 @@ gpg_agent_get_confirmation (const char *desc) char *tmp; char line[ASSUAN_LINELENGTH]; - rc = start_agent (0); + rc = start_agent (NULL, 0); if (rc) return rc; @@ -1264,7 +1267,7 @@ agent_get_s2k_count (unsigned long *r_count) *r_count = 0; - err = start_agent (0); + err = start_agent (NULL, 0); if (err) return err; @@ -1289,3 +1292,291 @@ agent_get_s2k_count (unsigned long *r_count) return err; } + + +/* Ask the agent whether a secret key with the given keygrip is + known. */ +gpg_error_t +agent_havekey (ctrl_t ctrl, const char *hexkeygrip) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + + err = start_agent (ctrl, 0); + if (err) + return err; + + if (!hexkeygrip || strlen (hexkeygrip) != 40) + return gpg_error (GPG_ERR_INV_VALUE); + + snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip); + line[DIM(line)-1] = 0; + + err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + return err; +} + + + +static gpg_error_t +keyinfo_status_cb (void *opaque, const char *line) +{ + char **serialno = opaque; + const char *s, *s2; + + if (!strncmp (line, "KEYINFO ", 8) && !*serialno) + { + s = strchr (line+8, ' '); + if (s && s[1] == 'T' && s[2] == ' ' && s[3]) + { + s += 3; + s2 = strchr (s, ' '); + if ( s2 > s ) + { + *serialno = xtrymalloc ((s2 - s)+1); + if (*serialno) + { + memcpy (*serialno, s, s2 - s); + (*serialno)[s2 - s] = 0; + } + } + } + } + return 0; +} + + +/* Return the serial number for a secret key. If the returned serial + number is NULL, the key is not stored on a smartcard. Caller needs + to free R_SERIALNO. */ +gpg_error_t +agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + char *serialno = NULL; + + *r_serialno = NULL; + + err = start_agent (ctrl, 0); + if (err) + return err; + + if (!hexkeygrip || strlen (hexkeygrip) != 40) + return gpg_error (GPG_ERR_INV_VALUE); + + snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip); + line[DIM(line)-1] = 0; + + err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, + keyinfo_status_cb, &serialno); + if (!err && serialno) + { + /* Sanity check for bad characters. */ + if (strpbrk (serialno, ":\n\r")) + err = GPG_ERR_INV_VALUE; + } + if (err) + xfree (serialno); + else + *r_serialno = serialno; + return err; +} + + + +/* Handle a KEYPARMS inquiry. Note, we only send the data, + assuan_transact takes care of flushing and writing the end */ +static gpg_error_t +inq_genkey_parms (void *opaque, const char *line) +{ + struct genkey_parm_s *parm = opaque; + gpg_error_t err; + + if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8])) + { + err = assuan_send_data (parm->ctx, + parm->keyparms, strlen (parm->keyparms)); + } + else + err = default_inq_cb (parm->ctrl, line); + + return err; +} + + +/* Call the agent to generate a new key. KEYPARMS is the usual + S-expression giving the parameters of the key. gpg-agent passes it + gcry_pk_genkey. */ +gpg_error_t +agent_genkey (ctrl_t ctrl, const char *keyparms, gcry_sexp_t *r_pubkey) +{ + gpg_error_t err; + struct genkey_parm_s gk_parm; + membuf_t data; + size_t len; + unsigned char *buf; + + *r_pubkey = NULL; + err = start_agent (ctrl, 0); + if (err) + return err; + + err = assuan_transact (agent_ctx, "RESET", + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + + init_membuf (&data, 1024); + gk_parm.ctrl = ctrl; + gk_parm.ctx = agent_ctx; + gk_parm.keyparms = keyparms; + err = assuan_transact (agent_ctx, "GENKEY", + membuf_data_cb, &data, + inq_genkey_parms, &gk_parm, NULL, NULL); + if (err) + { + xfree (get_membuf (&data, &len)); + return err; + } + + buf = get_membuf (&data, &len); + if (!buf) + err = gpg_error_from_syserror (); + else + { + err = gcry_sexp_sscan (r_pubkey, NULL, buf, len); + xfree (buf); + } + return err; +} + + + + +/* FIXME: Call the agent to read the public key part for a given keygrip. If + FROMCARD is true, the key is directly read from the current + smartcard. In this case HEXKEYGRIP should be the keyID + (e.g. OPENPGP.3). */ +/* int */ +/* agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, */ +/* ksba_sexp_t *r_pubkey) */ +/* { */ +/* int rc; */ +/* membuf_t data; */ +/* size_t len; */ +/* unsigned char *buf; */ +/* char line[ASSUAN_LINELENGTH]; */ + +/* *r_pubkey = NULL; */ +/* rc = start_agent (ctrl); */ +/* if (rc) */ +/* return rc; */ + +/* rc = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL); */ +/* if (rc) */ +/* return rc; */ + +/* snprintf (line, DIM(line)-1, "%sREADKEY %s", */ +/* fromcard? "SCD ":"", hexkeygrip); */ +/* line[DIM(line)-1] = 0; */ + +/* init_membuf (&data, 1024); */ +/* rc = assuan_transact (agent_ctx, line, */ +/* membuf_data_cb, &data, */ +/* default_inq_cb, ctrl, NULL, NULL); */ +/* if (rc) */ +/* { */ +/* xfree (get_membuf (&data, &len)); */ +/* return rc; */ +/* } */ +/* buf = get_membuf (&data, &len); */ +/* if (!buf) */ +/* return gpg_error (GPG_ERR_ENOMEM); */ +/* if (!gcry_sexp_canon_len (buf, len, NULL, NULL)) */ +/* { */ +/* xfree (buf); */ +/* return gpg_error (GPG_ERR_INV_SEXP); */ +/* } */ +/* *r_pubkey = buf; */ +/* return 0; */ +/* } */ + + + +/* Call the agent to do a sign operation using the key identified by + the hex string KEYGRIP. DESC is a description of the key to be + displayed if the agent needs to ask for the PIN. DIGEST and + DIGESTLEN is the hash value to sign and DIGESTALGO the algorithm id + used to compute the digest. */ +gpg_error_t +agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, + unsigned char *digest, size_t digestlen, int digestalgo, + gcry_sexp_t *r_sigval) +{ + gpg_error_t err; + int i; + char *p, line[ASSUAN_LINELENGTH]; + membuf_t data; + + *r_sigval = NULL; + err = start_agent (ctrl, 0); + if (err) + return err; + + if (digestlen*2 + 50 > DIM(line)) + return gpg_error (GPG_ERR_GENERAL); + + err = assuan_transact (agent_ctx, "RESET", + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + + snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip); + line[DIM(line)-1] = 0; + err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + + if (desc) + { + snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc); + line[DIM(line)-1] = 0; + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + } + + snprintf (line, sizeof line, "SETHASH %d ", digestalgo); + p = line + strlen (line); + for (i=0; i < digestlen ; i++, p += 2 ) + sprintf (p, "%02X", digest[i]); + err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + + init_membuf (&data, 1024); + err = assuan_transact (agent_ctx, "PKSIGN", + membuf_data_cb, &data, default_inq_cb, ctrl, + NULL, NULL); + if (err) + xfree (get_membuf (&data, NULL)); + else + { + unsigned char *buf; + size_t len; + + buf = get_membuf (&data, &len); + if (!buf) + err = gpg_error_from_syserror (); + else + { + err = gcry_sexp_sscan (r_sigval, NULL, buf, len); + xfree (buf); + } + } + return err; +} + + diff --git a/g10/call-agent.h b/g10/call-agent.h index 9088e4a5b..d42131f47 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -140,6 +140,24 @@ gpg_error_t gpg_agent_get_confirmation (const char *desc); /* Return the S2K iteration count as computed by gpg-agent. */ gpg_error_t agent_get_s2k_count (unsigned long *r_count); +/* Check whether a secret key with HEXKEYGRIP is available. */ +gpg_error_t agent_havekey (ctrl_t ctrl, const char *hexkeygrip); + +/* Return infos about the secret key with HEXKEYGRIP. */ +gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, + char **r_serialno); + +/* Generate a new key. */ +gpg_error_t agent_genkey (ctrl_t ctrl, const char *keyparms, + gcry_sexp_t *r_pubkey); + +/* Create a sigtnature. */ +gpg_error_t agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, + unsigned char *digest, size_t digestlen, + int digestalgo, + gcry_sexp_t *r_sigval); + + #endif /*GNUPG_G10_CALL_AGENT_H*/ diff --git a/g10/card-util.c b/g10/card-util.c index 0723a1c51..dd255a0d9 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1495,8 +1495,8 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock) the serialnumber and thus it won't harm. */ } - okay = generate_card_subkeypair (pub_keyblock, sec_keyblock, - keyno, info.serialno); + /* xxx = generate_card_subkeypair (pub_keyblock, sec_keyblock, */ + /* keyno, info.serialno); */ leave: agent_release_card_info (&info); @@ -1612,17 +1612,18 @@ card_store_subkey (KBNODE node, int use) } /* We better copy the key before we unprotect it. */ copied_sk = sk = copy_secret_key (NULL, sk); - rc = check_secret_key (sk, 0); + rc = 0/*check_secret_key (sk, 0)*/; if (rc) goto leave; } - rc = save_unprotected_key_to_card (sk, keyno); - if (rc) - { - log_error (_("error writing key to card: %s\n"), gpg_strerror (rc)); - goto leave; - } +#warning code save_unprotected_key_to_card + /* rc = save_unprotected_key_to_card (sk, keyno); */ + /* if (rc) */ + /* { */ + /* log_error (_("error writing key to card: %s\n"), gpg_strerror (rc)); */ + /* goto leave; */ + /* } */ /* Get back to the maybe protected original secret key. */ if (copied_sk) diff --git a/g10/export.c b/g10/export.c index 3a4c665c9..34ab90729 100644 --- a/g10/export.c +++ b/g10/export.c @@ -550,7 +550,7 @@ do_export_stream( IOBUF out, strlist_t users, int secret, ; /* Card key stub. */ else { - rc = check_secret_key( sk, 0 ); + /* rc = check_secret_key( sk, 0 ); */ } break; } diff --git a/g10/getkey.c b/g10/getkey.c index b5db65da0..78d5a1eb5 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -526,7 +526,7 @@ get_seckey (PKT_secret_key * sk, u32 * keyid) { /* Check the secret key (this may prompt for a passprase to * unlock the secret key. */ - rc = check_secret_key (sk, 0); + /* rc = check_secret_key (sk, 0); */ } return rc; @@ -1111,8 +1111,8 @@ get_seckey_byname2 (GETKEY_CTX * retctx, free_strlist (namelist); - if (!rc && unprotect) - rc = check_secret_key (sk, 0); + /* if (!rc && unprotect) */ + /* rc = check_secret_key (sk, 0); */ return rc; } diff --git a/g10/gpg.h b/g10/gpg.h index 013b135b2..1d645ea25 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -108,7 +108,7 @@ struct server_control_s #define G10ERR_RENAME_FILE GPG_ERR_RENAME_FILE #define G10ERR_RESOURCE_LIMIT GPG_ERR_RESOURCE_LIMIT #define G10ERR_SIG_CLASS GPG_ERR_SIG_CLASS -#define G10ERR_TIME_CONFLICT GPG_ERR_TIME_CONFLICT +#define G10ERR_TIME_CONFLICT GPG_ERR_TIME_CONFLICT #define G10ERR_TRUSTDB GPG_ERR_TRUSTDB #define G10ERR_UNEXPECTED GPG_ERR_UNEXPECTED #define G10ERR_UNKNOWN_PACKET GPG_ERR_UNKNOWN_PACKET diff --git a/g10/gpgv.c b/g10/gpgv.c index d6e49e368..ed3752f72 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -399,9 +399,9 @@ display_online_help (const char *keyword) * We don't use secret keys, but getkey.c links to this */ int -check_secret_key (PKT_secret_key *sk, int n) +check_secret_key (PKT_public_key *pk, int n) { - (void)sk; + (void)pk; (void)n; return G10ERR_GENERAL; } diff --git a/g10/keydb.h b/g10/keydb.h index cb0e04087..508226e94 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -286,6 +286,9 @@ byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len ); byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len ); char *serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen, PKT_secret_key *sk); +gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array); +gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip); + /*-- kbnode.c --*/ KBNODE new_kbnode( PACKET *pkt ); diff --git a/g10/keyedit.c b/g10/keyedit.c index a5a3be068..3ea926f06 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1164,9 +1164,9 @@ change_passphrase (KBNODE keyblock, int *r_err) keyid_from_sk (sk, keyid); passphrase_clear_cache (keyid, NULL, 0); - rc = check_secret_key( sk, 0 ); - if( !rc ) - passphrase = get_last_passphrase(); + /* rc = check_secret_key( sk, 0 ); */ + /* if( !rc ) */ + /* passphrase = get_last_passphrase(); */ } break; } @@ -1179,9 +1179,9 @@ change_passphrase (KBNODE keyblock, int *r_err) && (subsk->protect.s2k.mode == 1001 || subsk->protect.s2k.mode == 1002))) { set_next_passphrase( passphrase ); - rc = check_secret_key( subsk, 0 ); - if( !rc && !passphrase ) - passphrase = get_last_passphrase(); + /* rc = check_secret_key( subsk, 0 ); */ + /* if( !rc && !passphrase ) */ + /* passphrase = get_last_passphrase(); */ } } } @@ -1227,7 +1227,9 @@ change_passphrase (KBNODE keyblock, int *r_err) if( !no_primary_secrets ) { sk->protect.algo = dek->algo; sk->protect.s2k = *s2k; - rc = protect_secret_key( sk, dek ); +#warning fixme + rc = 0; + /* rc = protect_secret_key( sk, dek ); */ } for(node=keyblock; !rc && node; node = node->next ) { if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { @@ -1237,7 +1239,9 @@ change_passphrase (KBNODE keyblock, int *r_err) || subsk->protect.s2k.mode == 1002))) { subsk->protect.algo = dek->algo; subsk->protect.s2k = *s2k; - rc = protect_secret_key( subsk, dek ); +#warning fixme + rc = 0; + /* rc = protect_secret_key( subsk, dek ); */ } } } @@ -1892,12 +1896,13 @@ keyedit_menu( const char *username, strlist_t locusr, break; case cmdADDKEY: - if( generate_subkeypair( keyblock, sec_keyblock ) ) { + if (!generate_subkeypair (keyblock)) + { redisplay = 1; sec_modified = modified = 1; merge_keys_and_selfsig( sec_keyblock ); merge_keys_and_selfsig( keyblock ); - } + } break; #ifdef ENABLE_CARD_SUPPORT @@ -2018,8 +2023,8 @@ keyedit_menu( const char *username, strlist_t locusr, if (sk->protect.s2k.mode == 1002) tty_printf (_("Secret parts of key" " are stored on-card.\n")); - else - check_secret_key (sk, 0); + /* else */ + /* check_secret_key (sk, 0); */ } } else /* Store it. */ diff --git a/g10/keygen.c b/g10/keygen.c index 836b559f6..89f5e032d 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -132,15 +132,12 @@ static int mdc_available,ks_modify; static void do_generate_keypair( struct para_data_s *para, struct output_control_s *outctrl, int card ); -static int write_keyblock( IOBUF out, KBNODE node ); -static int gen_card_key (int algo, int keyno, int is_primary, - KBNODE pub_root, KBNODE sec_root, - PKT_secret_key **ret_sk, - u32 *timestamp, - u32 expireval, struct para_data_s *para); +static int write_keyblock (iobuf_t out, kbnode_t node); +static int gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root, + u32 *timestamp, u32 expireval, + struct para_data_s *para); static int gen_card_key_with_backup (int algo, int keyno, int is_primary, - KBNODE pub_root, KBNODE sec_root, - u32 timestamp, + kbnode_t pub_root, u32 timestamp, u32 expireval, struct para_data_s *para, const char *backup_dir); @@ -227,43 +224,46 @@ do_add_key_flags (PKT_signature *sig, unsigned int use) int -keygen_add_key_expire( PKT_signature *sig, void *opaque ) +keygen_add_key_expire (PKT_signature *sig, void *opaque) { - PKT_public_key *pk = opaque; - byte buf[8]; - u32 u; - - if( pk->expiredate ) { - if(pk->expiredate > pk->timestamp) - u= pk->expiredate - pk->timestamp; - else - u= 1; - - buf[0] = (u >> 24) & 0xff; - buf[1] = (u >> 16) & 0xff; - buf[2] = (u >> 8) & 0xff; - buf[3] = u & 0xff; - build_sig_subpkt( sig, SIGSUBPKT_KEY_EXPIRE, buf, 4 ); + PKT_public_key *pk = opaque; + byte buf[8]; + u32 u; + + if (pk->expiredate) + { + if (pk->expiredate > pk->timestamp) + u = pk->expiredate - pk->timestamp; + else + u = 1; + + buf[0] = (u >> 24) & 0xff; + buf[1] = (u >> 16) & 0xff; + buf[2] = (u >> 8) & 0xff; + buf[3] = u & 0xff; + build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); + } + else + { + /* Make sure we don't leave a key expiration subpacket lying + around */ + delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); } - else - { - /* Make sure we don't leave a key expiration subpacket lying - around */ - delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); - } - return 0; + return 0; } + static int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque) { - struct opaque_data_usage_and_pk *oduap = opaque; - - do_add_key_flags (sig, oduap->usage); - return keygen_add_key_expire (sig, oduap->pk); + struct opaque_data_usage_and_pk *oduap = opaque; + + do_add_key_flags (sig, oduap->usage); + return keygen_add_key_expire (sig, oduap->pk); } + static int set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) { @@ -697,19 +697,18 @@ keygen_upd_std_prefs (PKT_signature *sig, void *opaque) /**************** * Add preference to the self signature packet. * This is only called for packets with version > 3. - */ int -keygen_add_std_prefs( PKT_signature *sig, void *opaque ) +keygen_add_std_prefs (PKT_signature *sig, void *opaque) { - PKT_public_key *pk = opaque; - - do_add_key_flags (sig, pk->pubkey_usage); - keygen_add_key_expire( sig, opaque ); - keygen_upd_std_prefs (sig, opaque); - keygen_add_keyserver_url(sig,NULL); - - return 0; + PKT_public_key *pk = opaque; + + do_add_key_flags (sig, pk->pubkey_usage); + keygen_add_key_expire (sig, opaque ); + keygen_upd_std_prefs (sig, opaque); + keygen_add_keyserver_url (sig,NULL); + + return 0; } int @@ -778,23 +777,23 @@ keygen_add_notations(PKT_signature *sig,void *opaque) } int -keygen_add_revkey(PKT_signature *sig, void *opaque) +keygen_add_revkey (PKT_signature *sig, void *opaque) { - struct revocation_key *revkey=opaque; + struct revocation_key *revkey = opaque; byte buf[2+MAX_FINGERPRINT_LEN]; - buf[0]=revkey->class; - buf[1]=revkey->algid; - memcpy(&buf[2],revkey->fpr,MAX_FINGERPRINT_LEN); + buf[0] = revkey->class; + buf[1] = revkey->algid; + memcpy (&buf[2], revkey->fpr, MAX_FINGERPRINT_LEN); - build_sig_subpkt(sig,SIGSUBPKT_REV_KEY,buf,2+MAX_FINGERPRINT_LEN); + build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+MAX_FINGERPRINT_LEN); - /* All sigs with revocation keys set are nonrevocable */ - sig->flags.revocable=0; + /* All sigs with revocation keys set are nonrevocable. */ + sig->flags.revocable = 0; buf[0] = 0; - build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 ); + build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); - parse_revkeys(sig); + parse_revkeys (sig); return 0; } @@ -803,115 +802,118 @@ keygen_add_revkey(PKT_signature *sig, void *opaque) /* Create a back-signature. If TIMESTAMP is not NULL, use it for the signature creation time. */ -int -make_backsig (PKT_signature *sig,PKT_public_key *pk, - PKT_public_key *sub_pk,PKT_secret_key *sub_sk, +gpg_error_t +make_backsig (PKT_signature *sig, PKT_public_key *pk, + PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp) { + gpg_error_t err; PKT_signature *backsig; - int rc; - cache_public_key(sub_pk); + cache_public_key (sub_pk); - rc = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_sk, 0x19, - 0, 0, timestamp, 0, NULL, NULL); - if(rc) - log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc)); + err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19, + 0, 0, timestamp, 0, NULL, NULL); + if (err) + log_error ("make_keysig_packet failed for backsig: %s\n", g10_errstr(err)); else { /* Get it into a binary packed form. */ - IOBUF backsig_out=iobuf_temp(); + IOBUF backsig_out = iobuf_temp(); PACKET backsig_pkt; - init_packet(&backsig_pkt); - backsig_pkt.pkttype=PKT_SIGNATURE; - backsig_pkt.pkt.signature=backsig; - rc=build_packet(backsig_out,&backsig_pkt); - free_packet(&backsig_pkt); - if(rc) - log_error("build_packet failed for backsig: %s\n",g10_errstr(rc)); + init_packet (&backsig_pkt); + backsig_pkt.pkttype = PKT_SIGNATURE; + backsig_pkt.pkt.signature = backsig; + err = build_packet (backsig_out, &backsig_pkt); + free_packet (&backsig_pkt); + if (err) + log_error ("build_packet failed for backsig: %s\n", g10_errstr(err)); else { - size_t pktlen=0; - byte *buf=iobuf_get_temp_buffer(backsig_out); + size_t pktlen = 0; + byte *buf = iobuf_get_temp_buffer (backsig_out); - /* Remove the packet header */ + /* Remove the packet header. */ if(buf[0]&0x40) { - if(buf[1]<192) + if (buf[1] < 192) { - pktlen=buf[1]; - buf+=2; + pktlen = buf[1]; + buf += 2; + } + else if(buf[1] < 224) + { + pktlen = (buf[1]-192)*256; + pktlen += buf[2]+192; + buf += 3; } - else if(buf[1]<224) + else if (buf[1] == 255) { - pktlen=(buf[1]-192)*256; - pktlen+=buf[2]+192; - buf+=3; - } - else if(buf[1]==255) - { - pktlen =buf[2] << 24; - pktlen|=buf[3] << 16; - pktlen|=buf[4] << 8; - pktlen|=buf[5]; - buf+=6; + pktlen = buf[2] << 24; + pktlen |= buf[3] << 16; + pktlen |= buf[4] << 8; + pktlen |= buf[5]; + buf += 6; } else - BUG(); + BUG (); } else { - int mark=1; + int mark = 1; - switch(buf[0]&3) + switch (buf[0]&3) { case 3: - BUG(); + BUG (); break; case 2: - pktlen =buf[mark++] << 24; - pktlen|=buf[mark++] << 16; + pktlen = buf[mark++] << 24; + pktlen |= buf[mark++] << 16; case 1: - pktlen|=buf[mark++] << 8; + pktlen |= buf[mark++] << 8; case 0: - pktlen|=buf[mark++]; + pktlen |= buf[mark++]; } - buf+=mark; + buf += mark; } /* Now make the binary blob into a subpacket. */ - build_sig_subpkt(sig,SIGSUBPKT_SIGNATURE,buf,pktlen); + build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen); - iobuf_close(backsig_out); + iobuf_close (backsig_out); } } - - return rc; + + return err; } -static int -write_direct_sig (KBNODE root, KBNODE pub_root, PKT_secret_key *sk, - struct revocation_key *revkey, u32 timestamp) +/* Write a direct key signature to the first key in ROOT using the key + PSK. REVKEY is describes the direct key signature and TIMESTAMP is + the timestamp to set on the signature. */ +static gpg_error_t +write_direct_sig (KBNODE root, PKT_public_key *psk, + struct revocation_key *revkey, u32 timestamp) { + gpg_error_t err; PACKET *pkt; PKT_signature *sig; - int rc=0; KBNODE node; PKT_public_key *pk; - if( opt.verbose ) - log_info(_("writing direct signature\n")); + if (opt.verbose) + log_info (_("writing direct signature\n")); /* Get the pk packet from the pub_tree. */ - node = find_kbnode( pub_root, PKT_PUBLIC_KEY ); - if( !node ) - BUG(); + node = find_kbnode (root, PKT_PUBLIC_KEY); + if (!node) + BUG (); pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the @@ -919,48 +921,54 @@ write_direct_sig (KBNODE root, KBNODE pub_root, PKT_secret_key *sk, cache_public_key (pk); /* Make the signature. */ - rc = make_keysig_packet (&sig,pk,NULL,NULL,sk,0x1F, - 0, 0, timestamp, 0, - keygen_add_revkey, revkey); - if( rc ) + err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F, + 0, 0, timestamp, 0, + keygen_add_revkey, revkey); + if (err) { - log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); - return rc; + log_error ("make_keysig_packet failed: %s\n", g10_errstr (err) ); + return err; } - pkt = xmalloc_clear( sizeof *pkt ); + pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; - add_kbnode( root, new_kbnode( pkt ) ); - return rc; + add_kbnode (root, new_kbnode (pkt)); + return err; } -static int -write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk, - unsigned int use, u32 timestamp ) + +/* Write a self-signature to the first user id in ROOT using the key + PSK. USE and TIMESTAMP give the extra data we need for the + signature. */ +static gpg_error_t +write_selfsigs (KBNODE root, PKT_public_key *psk, + unsigned int use, u32 timestamp) { + gpg_error_t err; PACKET *pkt; PKT_signature *sig; PKT_user_id *uid; - int rc=0; KBNODE node; PKT_public_key *pk; - if( opt.verbose ) - log_info(_("writing self signature\n")); + if (opt.verbose) + log_info (_("writing self signature\n")); /* Get the uid packet from the list. */ - node = find_kbnode( pub_root, PKT_USER_ID ); - if( !node ) + node = find_kbnode (root, PKT_USER_ID); + if (!node) BUG(); /* No user id packet in tree. */ uid = node->pkt->pkt.user_id; /* Get the pk packet from the pub_tree. */ - node = find_kbnode( pub_root, PKT_PUBLIC_KEY ); - if( !node ) + node = find_kbnode (root, PKT_PUBLIC_KEY); + if (!node) BUG(); pk = node->pkt->pkt.public_key; + + /* The usage has not yet been set - do it now. */ pk->pubkey_usage = use; /* We have to cache the key, so that the verification of the @@ -968,48 +976,45 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk, cache_public_key (pk); /* Make the signature. */ - rc = make_keysig_packet (&sig, pk, uid, NULL, sk, 0x13, - 0, 0, timestamp, 0, - keygen_add_std_prefs, pk); - if( rc ) + err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13, + 0, 0, timestamp, 0, + keygen_add_std_prefs, pk); + if (err) { - log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); - return rc; + log_error ("make_keysig_packet failed: %s\n", g10_errstr (err)); + return err; } - pkt = xmalloc_clear( sizeof *pkt ); + pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; - add_kbnode( sec_root, new_kbnode( pkt ) ); + add_kbnode (root, new_kbnode (pkt)); - pkt = xmalloc_clear( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = copy_signature(NULL,sig); - add_kbnode( pub_root, new_kbnode( pkt ) ); - return rc; + return err; } /* Write the key binding signature. If TIMESTAMP is not NULL use the - signature creation times. */ + signature creation time. PRI_PSK is the key use for signing. + SUB_PSK is a key used to create a back-signature; that one is only + used if USE has the PUBKEY_USAGE_SIG capability. */ static int -write_keybinding (KBNODE root, KBNODE pub_root, - PKT_secret_key *pri_sk, PKT_secret_key *sub_sk, +write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, unsigned int use, u32 timestamp) { + gpg_error_t err; PACKET *pkt; PKT_signature *sig; - int rc=0; KBNODE node; PKT_public_key *pri_pk, *sub_pk; struct opaque_data_usage_and_pk oduap; - if ( opt.verbose ) + if (opt.verbose) log_info(_("writing key binding signature\n")); - /* Get the pk packet from the pub_tree. */ - node = find_kbnode ( pub_root, PKT_PUBLIC_KEY ); - if ( !node ) + /* Get the primary pk packet from the tree. */ + node = find_kbnode (root, PKT_PUBLIC_KEY); + if (!node) BUG(); pri_pk = node->pkt->pkt.public_key; @@ -1019,9 +1024,9 @@ write_keybinding (KBNODE root, KBNODE pub_root, /* Find the last subkey. */ sub_pk = NULL; - for (node=pub_root; node; node = node->next ) + for (node = root; node; node = node->next ) { - if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; } if (!sub_pk) @@ -1030,28 +1035,28 @@ write_keybinding (KBNODE root, KBNODE pub_root, /* Make the signature. */ oduap.usage = use; oduap.pk = sub_pk; - rc = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18, - 0, 0, timestamp, 0, - keygen_add_key_flags_and_expire, &oduap ); - if (rc) + err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, + 0, 0, timestamp, 0, + keygen_add_key_flags_and_expire, &oduap); + if (err) { - log_error ("make_keysig_packet failed: %s\n", g10_errstr(rc) ); - return rc; + log_error ("make_keysig_packet failed: %s\n", g10_errstr (err)); + return err; } /* Make a backsig. */ - if (use&PUBKEY_USAGE_SIG) + if (use & PUBKEY_USAGE_SIG) { - rc = make_backsig (sig, pri_pk, sub_pk, sub_sk, timestamp); - if (rc) - return rc; + err = make_backsig (sig, pri_pk, sub_pk, sub_psk, timestamp); + if (err) + return err; } pkt = xmalloc_clear ( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt) ); - return rc; + return err; } @@ -1106,71 +1111,76 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, } + +/* Common code for the key generation fucntion gen_xxx. */ static int -genhelp_protect (DEK *dek, STRING2KEY *s2k, PKT_secret_key *sk) +common_gen (const char *keyparms, int algo, const char *algoelem, + kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey) { - int rc = 0; - - if (dek) - { - sk->protect.algo = dek->algo; - sk->protect.s2k = *s2k; - rc = protect_secret_key (sk, dek); - if (rc) - log_error ("protect_secret_key failed: %s\n", gpg_strerror (rc) ); - } - - return rc; -} - -static void -genhelp_factors (gcry_sexp_t misc_key_info, KBNODE sec_root) -{ - (void)misc_key_info; - (void)sec_root; -#if 0 /* Not used anymore */ - size_t n; - char *buf; + int err; + PACKET *pkt; + PKT_public_key *pk; + gcry_sexp_t s_key; - if (misc_key_info) + err = agent_genkey (NULL, keyparms, &s_key); + if (err) { - /* DSA: don't know whether it makes sense to have the factors, so for now - we store them in the secret keyring (but they are not secret) - p = 2 * q * f1 * f2 * ... * fn - We store only f1 to f_n-1; fn can be calculated because p and q - are known. */ - n = gcry_sexp_sprint (misc_key_info, 0, NULL, 0); - buf = xmalloc (n+4); - strcpy (buf, "#::"); - n = gcry_sexp_sprint (misc_key_info, 0, buf+3, n); - if (n) - { - n += 3; - add_kbnode (sec_root, make_comment_node_from_buffer (buf, n)); - } - xfree (buf); - gcry_sexp_release (misc_key_info); + log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); + return err; } -#endif + + pk = xtrycalloc (1, sizeof *pk); + if (!pk) + { + err = gpg_error_from_syserror (); + gcry_sexp_release (s_key); + return err; + } + + pk->timestamp = timestamp; + pk->version = 4; + if (expireval) + pk->expiredate = pk->timestamp + expireval; + pk->pubkey_algo = algo; + + err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); + if (err) + { + log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); + gcry_sexp_release (s_key); + free_public_key (pk); + return err; + } + gcry_sexp_release (s_key); + + pkt = xtrycalloc (1, sizeof *pkt); + if (!pkt) + { + err = gpg_error_from_syserror (); + free_public_key (pk); + return err; + } + + pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; + pkt->pkt.public_key = pk; + add_kbnode (pub_root, new_kbnode (pkt)); + + return 0; } -/* Generate an Elgamal encryption key pair. TIMESTAMP is the creatuion - time to be put into the key structure. */ +/* + * Generate an Elgamal key. + */ static int -gen_elg (int algo, unsigned int nbits, - KBNODE pub_root, KBNODE sec_root, DEK *dek, - STRING2KEY *s2k, PKT_secret_key **ret_sk, +gen_elg (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey) { - int rc; - PACKET *pkt; - PKT_secret_key *sk; - PKT_public_key *pk; - gcry_sexp_t s_parms, s_key; - gcry_sexp_t misc_key_info; + int err; + char *keyparms; + char nbitsstr[35]; - assert( is_ELGAMAL(algo) ); + assert (is_ELGAMAL (algo)); if (nbits < 512) { @@ -1184,104 +1194,36 @@ gen_elg (int algo, unsigned int nbits, log_info (_("keysize rounded up to %u bits\n"), nbits ); } - - rc = gcry_sexp_build ( &s_parms, NULL, - "(genkey(%s(nbits %d)))", - algo == GCRY_PK_ELG_E ? "openpgp-elg" : - algo == GCRY_PK_ELG ? "elg" : "x-oops" , - (int)nbits); - if (rc) - log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); - - rc = gcry_pk_genkey (&s_key, s_parms); - gcry_sexp_release (s_parms); - if (rc) + snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); + keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)))", + algo == GCRY_PK_ELG_E ? "openpgp-elg" : + algo == GCRY_PK_ELG ? "elg" : "x-oops" , + strlen (nbitsstr), nbitsstr); + if (!keyparms) + err = gpg_error_from_syserror (); + else { - log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); - return rc; + err = common_gen (keyparms, algo, "pgy", + pub_root, timestamp, expireval, is_subkey); + xfree (keyparms); } - - sk = xmalloc_clear( sizeof *sk ); - pk = xmalloc_clear( sizeof *pk ); - sk->timestamp = pk->timestamp = timestamp; - sk->version = pk->version = 4; - if (expireval) - { - sk->expiredate = pk->expiredate = sk->timestamp + expireval; - } - sk->pubkey_algo = pk->pubkey_algo = algo; - rc = key_from_sexp (pk->pkey, s_key, "public-key", "pgy"); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); - gcry_sexp_release (s_key); - free_secret_key (sk); - free_public_key (pk); - return rc; - } - rc = key_from_sexp (sk->skey, s_key, "private-key", "pgyx"); - if (rc) - { - log_error("key_from_sexp failed: %s\n", gpg_strerror (rc) ); - gcry_sexp_release (s_key); - free_secret_key (sk); - free_public_key (pk); - return rc; - } - misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0); - gcry_sexp_release (s_key); - - sk->is_protected = 0; - sk->protect.algo = 0; - - sk->csum = checksum_mpi (sk->skey[3]); - if (ret_sk) /* Return an unprotected version of the sk. */ - *ret_sk = copy_secret_key ( NULL, sk ); - - rc = genhelp_protect (dek, s2k, sk); - if (rc) - { - free_public_key (pk); - free_secret_key (sk); - gcry_sexp_release (misc_key_info); - return rc; - } - - pkt = xmalloc_clear (sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; - pkt->pkt.public_key = pk; - add_kbnode (pub_root, new_kbnode( pkt )); - - /* Don't know whether it makes sense to have access to the factors, - so for now we store them in the secret keyring (but they are not - secret). */ - pkt = xmalloc_clear (sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY; - pkt->pkt.secret_key = sk; - add_kbnode (sec_root, new_kbnode( pkt )); - - genhelp_factors (misc_key_info, sec_root); - - return 0; + return err; } -/**************** - * Generate a DSA key +/* + * Generate an DSA key */ -static int -gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, - STRING2KEY *s2k, PKT_secret_key **ret_sk, +static gpg_error_t +gen_dsa (unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey) { - int rc; - PACKET *pkt; - PKT_secret_key *sk; - PKT_public_key *pk; - gcry_sexp_t s_parms, s_key; - gcry_sexp_t misc_key_info; + int err; unsigned int qbits; + char *keyparms; + char nbitsstr[35]; + char qbitsstr[35]; if ( nbits < 512) { @@ -1334,84 +1276,21 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, log_info (_("WARNING: some OpenPGP programs can't" " handle a DSA key with this digest size\n")); - rc = gcry_sexp_build (&s_parms, NULL, - "(genkey(dsa(nbits %d)(qbits %d)))", - (int)nbits, (int)qbits); - if (rc) - log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); - - rc = gcry_pk_genkey (&s_key, s_parms); - gcry_sexp_release (s_parms); - if (rc) + snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); + snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); + keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)))", + strlen (nbitsstr), nbitsstr, + strlen (qbitsstr), qbitsstr); + if (!keyparms) + err = gpg_error_from_syserror (); + else { - log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); - return rc; + err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", + pub_root, timestamp, expireval, is_subkey); + xfree (keyparms); } - sk = xmalloc_clear( sizeof *sk ); - pk = xmalloc_clear( sizeof *pk ); - sk->timestamp = pk->timestamp = timestamp; - sk->version = pk->version = 4; - if (expireval) - sk->expiredate = pk->expiredate = sk->timestamp + expireval; - sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA; - - rc = key_from_sexp (pk->pkey, s_key, "public-key", "pqgy"); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc)); - gcry_sexp_release (s_key); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - rc = key_from_sexp (sk->skey, s_key, "private-key", "pqgyx"); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); - gcry_sexp_release (s_key); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - misc_key_info = gcry_sexp_find_token (s_key, "misc-key-info", 0); - gcry_sexp_release (s_key); - - sk->is_protected = 0; - sk->protect.algo = 0; - - sk->csum = checksum_mpi ( sk->skey[4] ); - if( ret_sk ) /* return an unprotected version of the sk */ - *ret_sk = copy_secret_key( NULL, sk ); - - rc = genhelp_protect (dek, s2k, sk); - if (rc) - { - free_public_key (pk); - free_secret_key (sk); - gcry_sexp_release (misc_key_info); - return rc; - } - - pkt = xmalloc_clear(sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; - pkt->pkt.public_key = pk; - add_kbnode(pub_root, new_kbnode( pkt )); - - /* Don't know whether it makes sense to have the factors, so for now - * we store them in the secret keyring (but they are not secret) - * p = 2 * q * f1 * f2 * ... * fn - * We store only f1 to f_n-1; fn can be calculated because p and q - * are known. - */ - pkt = xmalloc_clear(sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY; - pkt->pkt.secret_key = sk; - add_kbnode(sec_root, new_kbnode( pkt )); - - genhelp_factors (misc_key_info, sec_root); - - return 0; + return err; } @@ -1419,15 +1298,12 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, * Generate an RSA key. */ static int -gen_rsa (int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, - STRING2KEY *s2k, PKT_secret_key **ret_sk, +gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey) { - int rc; - PACKET *pkt; - PKT_secret_key *sk; - PKT_public_key *pk; - gcry_sexp_t s_parms, s_key; + int err; + char *keyparms; + char nbitsstr[35]; assert (is_RSA(algo)); @@ -1446,79 +1322,19 @@ gen_rsa (int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, log_info (_("keysize rounded up to %u bits\n"), nbits ); } - rc = gcry_sexp_build (&s_parms, NULL, - "(genkey(rsa(nbits %d)))", - (int)nbits); - if (rc) - log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); - - rc = gcry_pk_genkey (&s_key, s_parms); - gcry_sexp_release (s_parms); - if (rc) + snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); + keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)))", + strlen (nbitsstr), nbitsstr); + if (!keyparms) + err = gpg_error_from_syserror (); + else { - log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); - return rc; + err = common_gen (keyparms, algo, "ne", + pub_root, timestamp, expireval, is_subkey); + xfree (keyparms); } - sk = xmalloc_clear( sizeof *sk ); - pk = xmalloc_clear( sizeof *pk ); - sk->timestamp = pk->timestamp = timestamp; - sk->version = pk->version = 4; - if (expireval) - { - sk->expiredate = pk->expiredate = sk->timestamp + expireval; - } - sk->pubkey_algo = pk->pubkey_algo = algo; - - rc = key_from_sexp (pk->pkey, s_key, "public-key", "ne"); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc)); - gcry_sexp_release (s_key); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu"); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); - gcry_sexp_release (s_key); - free_public_key(pk); - free_secret_key(sk); - return rc; - } - gcry_sexp_release (s_key); - - sk->is_protected = 0; - sk->protect.algo = 0; - - sk->csum = checksum_mpi (sk->skey[2] ); - sk->csum += checksum_mpi (sk->skey[3] ); - sk->csum += checksum_mpi (sk->skey[4] ); - sk->csum += checksum_mpi (sk->skey[5] ); - if( ret_sk ) /* return an unprotected version of the sk */ - *ret_sk = copy_secret_key( NULL, sk ); - - rc = genhelp_protect (dek, s2k, sk); - if (rc) - { - free_public_key (pk); - free_secret_key (sk); - return rc; - } - - pkt = xmalloc_clear(sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; - pkt->pkt.public_key = pk; - add_kbnode(pub_root, new_kbnode( pkt )); - - pkt = xmalloc_clear(sizeof *pkt); - pkt->pkttype = is_subkey ? PKT_SECRET_SUBKEY : PKT_SECRET_KEY; - pkt->pkt.secret_key = sk; - add_kbnode(sec_root, new_kbnode( pkt )); - - return 0; + return err; } @@ -2310,32 +2126,30 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled) /* Basic key generation. Here we divert to the actual generation routines based on the requested algorithm. */ static int -do_create (int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root, - DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, +do_create (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expiredate, int is_subkey ) { - int rc=0; + gpg_error_t err; - if( !opt.batch ) - tty_printf(_( + /* Fixme: The entropy collecting message should be moved to a + libgcrypt progress handler. */ + if (!opt.batch) + tty_printf (_( "We need to generate a lot of random bytes. It is a good idea to perform\n" "some other action (type on the keyboard, move the mouse, utilize the\n" "disks) during the prime generation; this gives the random number\n" "generator a better chance to gain enough entropy.\n") ); - if( algo == PUBKEY_ALGO_ELGAMAL_E ) - rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, - timestamp, expiredate, is_subkey); - else if( algo == PUBKEY_ALGO_DSA ) - rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, - timestamp, expiredate, is_subkey); - else if( algo == PUBKEY_ALGO_RSA ) - rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, - timestamp, expiredate, is_subkey); + if (algo == PUBKEY_ALGO_ELGAMAL_E) + err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey); + else if (algo == PUBKEY_ALGO_DSA) + err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey); + else if (algo == PUBKEY_ALGO_RSA) + err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey); else BUG(); - return rc; + return err; } @@ -2533,20 +2347,6 @@ get_parameter_uint( struct para_data_s *para, enum para_name key ) return get_parameter_u32( para, key ); } -static DEK * -get_parameter_dek( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - return r? r->u.dek : NULL; -} - -static STRING2KEY * -get_parameter_s2k( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - return r? r->u.s2k : NULL; -} - static struct revocation_key * get_parameter_revkey( struct para_data_s *para, enum para_name key ) { @@ -3050,8 +2850,6 @@ generate_keypair (const char *fname, const char *card_serialno, { unsigned int nbits; char *uid = NULL; - DEK *dek; - STRING2KEY *s2k; int algo; unsigned int use; int both = 0; @@ -3059,7 +2857,6 @@ generate_keypair (const char *fname, const char *card_serialno, struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; - int canceled; memset( &outctrl, 0, sizeof( outctrl ) ); @@ -3217,26 +3014,7 @@ generate_keypair (const char *fname, const char *card_serialno, r->next = para; para = r; - canceled = 0; - dek = card_serialno? NULL : do_ask_passphrase (&s2k, 0, &canceled); - if( dek ) - { - r = xmalloc_clear( sizeof *r ); - r->key = pPASSPHRASE_DEK; - r->u.dek = dek; - r->next = para; - para = r; - r = xmalloc_clear( sizeof *r ); - r->key = pPASSPHRASE_S2K; - r->u.s2k = s2k; - r->next = para; - para = r; - } - - if (canceled) - log_error (_("Key generation canceled.\n")); - else - proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno); + proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno); release_parameter_list( para ); } @@ -3356,16 +3134,16 @@ static void do_generate_keypair (struct para_data_s *para, struct output_control_s *outctrl, int card) { + gpg_error_t err; KBNODE pub_root = NULL; - KBNODE sec_root = NULL; - PKT_secret_key *pri_sk = NULL, *sub_sk = NULL; const char *s; + PKT_public_key *pri_psk = NULL; + PKT_public_key *sub_psk = NULL; struct revocation_key *revkey; - int rc; int did_sub = 0; u32 timestamp; - if( outctrl->dryrun ) + if (outctrl->dryrun) { log_info("dry-run mode - key generation skipped\n"); return; @@ -3403,51 +3181,9 @@ do_generate_keypair (struct para_data_s *para, push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); } } - if (outctrl->sec.newfname) - { - mode_t oldmask; - - iobuf_close(outctrl->sec.stream); - outctrl->sec.stream = NULL; - if (outctrl->sec.fname) - iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, - 0, (char*)outctrl->sec.fname); - xfree( outctrl->sec.fname ); - outctrl->sec.fname = outctrl->sec.newfname; - outctrl->sec.newfname = NULL; - - oldmask = umask (077); - if (is_secured_filename (outctrl->sec.fname) ) - { - outctrl->sec.stream = NULL; - gpg_err_set_errno (EPERM); - } - else - outctrl->sec.stream = iobuf_create( outctrl->sec.fname ); - umask (oldmask); - if (!outctrl->sec.stream) - { - log_error(_("can't create `%s': %s\n"), outctrl->sec.newfname, - strerror(errno) ); - return; - } - if (opt.armor) - { - outctrl->sec.afx->what = 5; - push_armor_filter (outctrl->sec.afx, outctrl->sec.stream); - } - } assert( outctrl->pub.stream ); - assert( outctrl->sec.stream ); if (opt.verbose) - { - log_info (_("writing public key to `%s'\n"), outctrl->pub.fname ); - if (card) - log_info (_("writing secret key stub to `%s'\n"), - outctrl->sec.fname); - else - log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname ); - } + log_info (_("writing public key to `%s'\n"), outctrl->pub.fname ); } @@ -3457,7 +3193,6 @@ do_generate_keypair (struct para_data_s *para, deleted. The very first packet must always be a KEY packet. */ start_tree (&pub_root); - start_tree (&sec_root); timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!timestamp) @@ -3473,42 +3208,31 @@ do_generate_keypair (struct para_data_s *para, current timestamp. */ if (!card) - { - rc = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), - get_parameter_uint( para, pKEYLENGTH ), - pub_root, sec_root, - get_parameter_dek( para, pPASSPHRASE_DEK ), - get_parameter_s2k( para, pPASSPHRASE_S2K ), - &pri_sk, - timestamp, - get_parameter_u32( para, pKEYEXPIRE ), 0 ); - } + err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), + get_parameter_uint( para, pKEYLENGTH ), + pub_root, + timestamp, + get_parameter_u32( para, pKEYEXPIRE ), 0 ); else + err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, + ×tamp, + get_parameter_u32 (para, pKEYEXPIRE), para); + + /* Get the pointer to the generated public key packet. */ + if (!err) { - rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE), para); - if (!rc) - { - pri_sk = sec_root->next->pkt->pkt.secret_key; - assert (pri_sk); - } + pri_psk = pub_root->next->pkt->pkt.public_key; + assert (pri_psk); } - if(!rc && (revkey=get_parameter_revkey(para,pREVOKER))) - { - rc = write_direct_sig (pub_root, pub_root, pri_sk, revkey, timestamp); - if (!rc) - rc = write_direct_sig (sec_root, pub_root, pri_sk, revkey, timestamp); - } + if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) + err = write_direct_sig (pub_root, pri_psk, revkey, timestamp); - if( !rc && (s=get_parameter_value(para, pUSERID)) ) + if (!err && (s = get_parameter_value (para, pUSERID))) { write_uid (pub_root, s ); - write_uid (sec_root, s ); - - rc = write_selfsigs (sec_root, pub_root, pri_sk, - get_parameter_uint (para, pKEYUSAGE), timestamp); + err = write_selfsigs (pub_root, pri_psk, + get_parameter_uint (para, pKEYUSAGE), timestamp); } /* Write the auth key to the card before the encryption key. This @@ -3518,32 +3242,36 @@ do_generate_keypair (struct para_data_s *para, actually an encryption type. In this case, the auth key is an RSA key so it succeeds. */ - if (!rc && card && get_parameter (para, pAUTHKEYTYPE)) + if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { - rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE), para); - - if (!rc) - rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk, - PUBKEY_USAGE_AUTH, timestamp); - if (!rc) - rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, - PUBKEY_USAGE_AUTH, timestamp); + err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, + ×tamp, + get_parameter_u32 (para, pKEYEXPIRE), para); + if (!err) + err = write_keybinding (pub_root, pri_psk, NULL, + PUBKEY_USAGE_AUTH, timestamp); } - if( !rc && get_parameter( para, pSUBKEYTYPE ) ) + if (!err && get_parameter (para, pSUBKEYTYPE)) { + sub_psk = NULL; if (!card) { - rc = do_create( get_parameter_algo( para, pSUBKEYTYPE, NULL ), - get_parameter_uint( para, pSUBKEYLENGTH ), - pub_root, sec_root, - get_parameter_dek( para, pPASSPHRASE_DEK ), - get_parameter_s2k( para, pPASSPHRASE_S2K ), - &sub_sk, - timestamp, - get_parameter_u32( para, pSUBKEYEXPIRE ), 1 ); + err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL), + get_parameter_uint (para, pSUBKEYLENGTH), + pub_root, + timestamp, + get_parameter_u32 (para, pSUBKEYEXPIRE), 1 ); + /* Get the pointer to the generated public subkey packet. */ + if (!err) + { + kbnode_t node; + + for (node = pub_root; node; node = node->next) + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + sub_psk = node->pkt->pkt.public_key; + assert (sub_psk); + } } else { @@ -3552,95 +3280,60 @@ do_generate_keypair (struct para_data_s *para, /* A backup of the encryption key has been requested. Generate the key in software and import it then to the card. Write a backup file. */ - rc = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0, - pub_root, sec_root, - timestamp, - get_parameter_u32 (para, - pKEYEXPIRE), - para, s); + err = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0, + pub_root, + timestamp, + get_parameter_u32 (para, + pKEYEXPIRE), + para, s); } else { - rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root, - NULL, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE), para); + err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, + ×tamp, + get_parameter_u32 (para, pKEYEXPIRE), para); } } - if( !rc ) - rc = write_keybinding(pub_root, pub_root, pri_sk, sub_sk, - get_parameter_uint (para, pSUBKEYUSAGE), - timestamp); - if( !rc ) - rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk, - get_parameter_uint (para, pSUBKEYUSAGE), - timestamp); + if (!err) + err = write_keybinding (pub_root, pri_psk, sub_psk, + get_parameter_uint (para, pSUBKEYUSAGE), + timestamp); did_sub = 1; } - if (!rc && outctrl->use_files) /* Direct write to specified files. */ + if (!err && outctrl->use_files) /* Direct write to specified files. */ { - rc = write_keyblock( outctrl->pub.stream, pub_root ); - if (rc) - log_error ("can't write public key: %s\n", g10_errstr(rc) ); - if (!rc) - { - rc = write_keyblock( outctrl->sec.stream, sec_root ); - if(rc) - log_error ("can't write secret key: %s\n", g10_errstr(rc) ); - } + err = write_keyblock (outctrl->pub.stream, pub_root); + if (err) + log_error ("can't write public key: %s\n", g10_errstr (err)); } - else if (!rc) /* Write to the standard keyrings. */ + else if (!err) /* Write to the standard keyrings. */ { KEYDB_HANDLE pub_hd = keydb_new (0); - KEYDB_HANDLE sec_hd = keydb_new (1); - rc = keydb_locate_writable (pub_hd, NULL); - if (rc) + err = keydb_locate_writable (pub_hd, NULL); + if (err) log_error (_("no writable public keyring found: %s\n"), - g10_errstr (rc)); - - if (!rc) - { - rc = keydb_locate_writable (sec_hd, NULL); - if (rc) - log_error (_("no writable secret keyring found: %s\n"), - g10_errstr (rc)); - } + g10_errstr (err)); - if (!rc && opt.verbose) + if (!err && opt.verbose) { log_info (_("writing public key to `%s'\n"), keydb_get_resource_name (pub_hd)); - if (card) - log_info (_("writing secret key stub to `%s'\n"), - keydb_get_resource_name (sec_hd)); - else - log_info (_("writing secret key to `%s'\n"), - keydb_get_resource_name (sec_hd)); } - if (!rc) + if (!err) { - rc = keydb_insert_keyblock (pub_hd, pub_root); - if (rc) + err = keydb_insert_keyblock (pub_hd, pub_root); + if (err) log_error (_("error writing public keyring `%s': %s\n"), - keydb_get_resource_name (pub_hd), g10_errstr(rc)); + keydb_get_resource_name (pub_hd), g10_errstr(err)); } - if (!rc) - { - rc = keydb_insert_keyblock (sec_hd, sec_root); - if (rc) - log_error (_("error writing secret keyring `%s': %s\n"), - keydb_get_resource_name (pub_hd), g10_errstr(rc)); - } - keydb_release (pub_hd); - keydb_release (sec_hd); - if (!rc) + if (!err) { int no_enc_rsa; PKT_public_key *pk; @@ -3653,8 +3346,8 @@ do_generate_keypair (struct para_data_s *para, pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; - keyid_from_pk(pk,pk->main_keyid); - register_trusted_keyid(pk->main_keyid); + keyid_from_pk (pk, pk->main_keyid); + register_trusted_keyid (pk->main_keyid); update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); @@ -3663,7 +3356,7 @@ do_generate_keypair (struct para_data_s *para, { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); - list_keyblock(pub_root,0,1,NULL); + list_keyblock (pub_root, 0, 1, NULL); } @@ -3680,13 +3373,13 @@ do_generate_keypair (struct para_data_s *para, } } - if (rc) + if (err) { if (opt.batch) - log_error ("key generation failed: %s\n", g10_errstr(rc) ); + log_error ("key generation failed: %s\n", g10_errstr(err) ); else - tty_printf (_("Key generation failed: %s\n"), g10_errstr(rc) ); - write_status_errcode (card? "card_key_generate":"key_generate", rc); + tty_printf (_("Key generation failed: %s\n"), g10_errstr(err) ); + write_status_error (card? "card_key_generate":"key_generate", err); print_status_key_not_created ( get_parameter_value (para, pHANDLE) ); } else @@ -3696,99 +3389,91 @@ do_generate_keypair (struct para_data_s *para, print_status_key_created (did_sub? 'B':'P', pk, get_parameter_value (para, pHANDLE)); } - release_kbnode( pub_root ); - release_kbnode( sec_root ); - if (pri_sk && !card) /* The unprotected secret key unless we */ - free_secret_key (pri_sk); /* have a shallow copy in card mode. */ - if (sub_sk) - free_secret_key(sub_sk); + release_kbnode (pub_root); } -/* Add a new subkey to an existing key. Returns true if a new key has +/* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. */ -int -generate_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock) +gpg_error_t +generate_subkeypair (KBNODE keyblock) { - int okay=0, rc=0; - KBNODE node; - PKT_secret_key *pri_sk = NULL, *sub_sk = NULL; + gpg_error_t err = 0; + kbnode_t node; + PKT_public_key *pri_psk = NULL; + PKT_public_key *sub_psk = NULL; int algo; unsigned int use; u32 expire; - unsigned nbits; - char *passphrase = NULL; - DEK *dek = NULL; - STRING2KEY *s2k = NULL; + unsigned int nbits; u32 cur_time; - int ask_pass = 0; - int canceled; - /* Break out the primary secret key. */ - node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); - if( !node ) + /* Break out the primary key. */ + node = find_kbnode (keyblock, PKT_PUBLIC_KEY); + if (!node) { - log_error ("Oops; secret key not found anymore!\n"); + log_error ("Oops; primary key missing in keyblock!\n"); + err = gpg_error (GPG_ERR_BUG); goto leave; } - - /* Make a copy of the sk to keep the protected one in the keyblock. */ - pri_sk = copy_secret_key (NULL, node->pkt->pkt.secret_key); + pri_psk = node->pkt->pkt.public_key; - cur_time = make_timestamp(); + cur_time = make_timestamp (); - if (pri_sk->timestamp > cur_time) + if (pri_psk->timestamp > cur_time) { - ulong d = pri_sk->timestamp - cur_time; + ulong d = pri_psk->timestamp - cur_time; log_info ( d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { - rc = G10ERR_TIME_CONFLICT; + err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } - if (pri_sk->version < 4) + if (pri_psk->version < 4) { log_info (_("NOTE: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); + err = gpg_error (GPG_ERR_CONFLICT); goto leave; } - if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) - { - tty_printf (_("Secret parts of primary key are not available.\n")); - rc = G10ERR_NO_SECKEY; - goto leave; - } +#warning ask gpg-agent on the availibility of the secret key + /* if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) */ + /* { */ + /* tty_printf (_("Secret parts of primary key are not available.\n")); */ + /* err = G10ERR_NO_SECKEY; */ + /* goto leave; */ + /* } */ - /* Unprotect to get the passphrase. */ - switch (is_secret_key_protected (pri_sk) ) - { - case -1: - rc = G10ERR_PUBKEY_ALGO; - break; - case 0: - tty_printf (_("This key is not protected.\n")); - break; - case -2: - tty_printf (_("Secret parts of primary key are stored on-card.\n")); - ask_pass = 1; - break; - default: - tty_printf (_("Key is protected.\n")); - rc = check_secret_key ( pri_sk, 0 ); - if (!rc) - passphrase = get_last_passphrase(); - break; - } - if (rc) - goto leave; + /* /\* Unprotect to get the passphrase. *\/ */ + /* switch (is_secret_key_protected (pri_sk) ) */ + /* { */ + /* case -1: */ + /* err = G10ERR_PUBKEY_ALGO; */ + /* break; */ + /* case 0: */ + /* tty_printf (_("This key is not protected.\n")); */ + /* break; */ + /* case -2: */ + /* tty_printf (_("Secret parts of primary key are stored on-card.\n")); */ + /* ask_pass = 1; */ + /* break; */ + /* default: */ + /* tty_printf (_("Key is protected.\n")); */ + /* err = check_secret_key ( pri_sk, 0 ); */ + /* if (!err) */ + /* passphrase = get_last_passphrase(); */ + /* break; */ + /* } */ + /* if (err) */ + /* goto leave; */ algo = ask_algo (1, NULL, &use); assert (algo); @@ -3796,52 +3481,31 @@ generate_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock) expire = ask_expire_interval (0, NULL); if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", _("Really create? (y/N) "))) + { + err = gpg_error (GPG_ERR_CANCELED); + goto leave; + } + + err = do_create (algo, nbits, keyblock, cur_time, expire, 1); + if (err) goto leave; - - canceled = 0; - if (ask_pass) - dek = do_ask_passphrase (&s2k, 0, &canceled); - else if (passphrase) - { - s2k = xmalloc_secure ( sizeof *s2k ); - s2k->mode = opt.s2k_mode; - s2k->hash_algo = S2K_DIGEST_ALGO; - set_next_passphrase ( passphrase ); - dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2, - NULL, NULL ); - } - - if (canceled) - rc = GPG_ERR_CANCELED; - - if (!rc) - rc = do_create (algo, nbits, pub_keyblock, sec_keyblock, - dek, s2k, &sub_sk, cur_time, expire, 1 ); - if (!rc) - rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, - use, cur_time); - if (!rc) - rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, - use, cur_time); - if (!rc) - { - okay = 1; - write_status_text (STATUS_KEY_CREATED, "S"); - } + + /* Get the pointer to the generated public subkey packet. */ + for (node = keyblock; node; node = node->next) + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + sub_psk = node->pkt->pkt.public_key; + + /* Write the binding signature. */ + err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time); + if (err) + goto leave; + + write_status_text (STATUS_KEY_CREATED, "S"); leave: - if (rc) - log_error (_("Key generation failed: %s\n"), g10_errstr(rc) ); - xfree (passphrase); - xfree (dek); - xfree (s2k); - /* Release the copy of the (now unprotected) secret keys. */ - if (pri_sk) - free_secret_key (pri_sk); - if (sub_sk) - free_secret_key (sub_sk); - set_next_passphrase (NULL); - return okay; + if (err) + log_error (_("Key generation failed: %s\n"), g10_errstr (err) ); + return err; } @@ -3851,8 +3515,9 @@ int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, int keyno, const char *serialno) { - int okay=0, rc=0; - KBNODE node; + gpg_error_t err = 0; + int okay = 0; + kbnode_t node; PKT_secret_key *pri_sk = NULL, *sub_sk; int algo; unsigned int use; @@ -3888,7 +3553,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { - rc = G10ERR_TIME_CONFLICT; + err = G10ERR_TIME_CONFLICT; goto leave; } } @@ -3904,19 +3569,19 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, switch( is_secret_key_protected (pri_sk) ) { case -1: - rc = G10ERR_PUBKEY_ALGO; + err = G10ERR_PUBKEY_ALGO; break; case 0: tty_printf("This key is not protected.\n"); break; default: tty_printf("Key is protected.\n"); - rc = check_secret_key( pri_sk, 0 ); - if (!rc) + err = check_secret_key( pri_sk, 0 ); + if (!err) passphrase = get_last_passphrase(); break; } - if (rc) + if (err) goto leave; algo = PUBKEY_ALGO_RSA; @@ -3936,23 +3601,22 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, /* Note, that depending on the backend, the card key generation may update CUR_TIME. */ - rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, - &sub_sk, &cur_time, expire, para); - if (!rc) - rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, + err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire, para); + if (!err) + err = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, + use, cur_time); + if (!err) + err = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use, cur_time); - if (!rc) - rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, - use, cur_time); - if (!rc) + if (!err) { okay = 1; write_status_text (STATUS_KEY_CREATED, "S"); } leave: - if (rc) - log_error (_("Key generation failed: %s\n"), g10_errstr(rc) ); + if (err) + log_error (_("Key generation failed: %s\n"), g10_errstr(err) ); xfree (passphrase); /* Release the copy of the (now unprotected) secret keys. */ if (pri_sk) @@ -3990,8 +3654,7 @@ write_keyblock( IOBUF out, KBNODE node ) /* Note that timestamp is an in/out arg. */ static int -gen_card_key (int algo, int keyno, int is_primary, - KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk, +gen_card_key (int algo, int keyno, int is_primary, KBNODE pub_root, u32 *timestamp, u32 expireval, struct para_data_s *para) { #ifdef ENABLE_CARD_SUPPORT @@ -4070,7 +3733,7 @@ gen_card_key (int algo, int keyno, int is_primary, return 0; #else - return -1; + return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } @@ -4078,8 +3741,7 @@ gen_card_key (int algo, int keyno, int is_primary, static int gen_card_key_with_backup (int algo, int keyno, int is_primary, - KBNODE pub_root, KBNODE sec_root, - u32 timestamp, + KBNODE pub_root, u32 timestamp, u32 expireval, struct para_data_s *para, const char *backup_dir) { @@ -4240,7 +3902,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary, return 0; #else - return -1; + return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } diff --git a/g10/keyid.c b/g10/keyid.c index 3ba7d4256..8f2d8f7fd 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -1,6 +1,6 @@ /* keyid.c - key ID and fingerprint handling * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004, 2006 Free Software Foundation, Inc. + * 2004, 2006, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -828,3 +828,90 @@ serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen, return buffer; } + + +/* Return the so called KEYGRIP which is the SHA-1 hash of the public + key parameters expressed as an canoncial encoded S-Exp. ARRAY must + be 20 bytes long. Returns 0 on sucess or an error code. */ +gpg_error_t +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"); + + switch (pk->pubkey_algo) + { + case GCRY_PK_DSA: + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", + pk->pkey[0], pk->pkey[1], + pk->pkey[2], pk->pkey[3]); + break; + + case GCRY_PK_ELG: + case GCRY_PK_ELG_E: + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(elg(p%m)(g%m)(y%m)))", + pk->pkey[0], pk->pkey[1], pk->pkey[2]); + break; + + case GCRY_PK_RSA: + case GCRY_PK_RSA_S: + case GCRY_PK_RSA_E: + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(rsa(n%m)(e%m)))", + pk->pkey[0], pk->pkey[1]); + break; + + default: + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + break; + } + + if (err) + return err; + + if (!gcry_pk_get_keygrip (s_pkey, array)) + { + log_error ("error computing keygrip\n"); + err = gpg_error (GPG_ERR_GENERAL); + } + else + { + if (DBG_PACKET) + log_printhex ("keygrip=", array, 20); + /* FIXME: Save the keygrip in PK. */ + } + gcry_sexp_release (s_pkey); + + return 0; +} + + +/* Store an allocated buffer with the keygrip of PK encoded as a + hexstring at r_GRIP. Returns 0 on success. */ +gpg_error_t +hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip) +{ + gpg_error_t err; + unsigned char grip[20]; + + *r_grip = NULL; + err = keygrip_from_pk (pk, grip); + if (!err) + { + char * buf = xtrymalloc (20*2+1); + if (!buf) + err = gpg_error_from_syserror (); + else + { + bin2hex (grip, 20, buf); + *r_grip = buf; + } + } + return err; +} + diff --git a/g10/keylist.c b/g10/keylist.c index 6d70b2bb4..5d08c0d53 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1063,6 +1063,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) int trustletter = 0; int ulti_hack = 0; int i; + char *p; /* Get the keyid from the keyblock. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); @@ -1128,8 +1129,15 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) if (fpr) print_fingerprint (pk, NULL, 0); if (opt.with_key_data) - print_key_data (pk); - + { + if (!hexkeygrip_from_pk (pk, &p)) + { + es_fprintf (es_stdout, "grp:::::::::%s:\n", p); + xfree (p); + } + print_key_data (pk); + } + for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode) @@ -1226,7 +1234,14 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) if (fpr > 1) print_fingerprint (pk2, NULL, 0); if (opt.with_key_data) - print_key_data (pk2); + { + if (!hexkeygrip_from_pk (pk2, &p)) + { + es_fprintf (es_stdout, "grp:::::::::%s:\n", p); + xfree (p); + } + print_key_data (pk2); + } } else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE) { @@ -1319,7 +1334,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr) else if (!opt.fast_list_mode) { size_t n; - char *p = get_user_id (sig->keyid, &n); + p = get_user_id (sig->keyid, &n); es_write_sanitized (es_stdout, p, n, ":", NULL); xfree (p); } diff --git a/g10/main.h b/g10/main.h index 540d9b1d9..c687ee2c6 100644 --- a/g10/main.h +++ b/g10/main.h @@ -237,10 +237,10 @@ int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_notations(PKT_signature *sig,void *opaque); int keygen_add_revkey(PKT_signature *sig, void *opaque); -int make_backsig(PKT_signature *sig,PKT_public_key *pk, - PKT_public_key *sub_pk,PKT_secret_key *sub_sk, - u32 timestamp); -int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); +gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk, + PKT_public_key *sub_pk, PKT_public_key *sub_psk, + u32 timestamp); +gpg_error_t generate_subkeypair (kbnode_t pub_keyblock); #ifdef ENABLE_CARD_SUPPORT int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, int keyno, const char *serialno); @@ -258,7 +258,7 @@ void try_make_homedir( const char *fname ); /*-- seskey.c --*/ void make_session_key( DEK *dek ); gcry_mpi_t encode_session_key( DEK *dek, unsigned nbits ); -gcry_mpi_t encode_md_value( PKT_public_key *pk, PKT_secret_key *sk, +gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo ); /*-- import.c --*/ diff --git a/g10/packet.h b/g10/packet.h index 54f8295c1..2a6aea2b1 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -206,7 +206,7 @@ struct revoke_info /**************** * Note about the pkey/skey elements: We assume that the secret keys - * has the same elemts as the public key at the begin of the array, so + * has the same elements as the public key at the begin of the array, so * that npkey < nskey and it is possible to compare the secret and * public keys by comparing the first npkey elements of pkey againts skey. */ @@ -477,9 +477,7 @@ int signature_check2( PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate int *r_expired, int *r_revoked, PKT_public_key *ret_pk ); /*-- seckey-cert.c --*/ -int is_secret_key_protected( PKT_secret_key *sk ); -int check_secret_key( PKT_secret_key *sk, int retries ); -int protect_secret_key( PKT_secret_key *sk, DEK *dek ); +int is_secret_key_protected (PKT_public_key *pk); /*-- pubkey-enc.c --*/ int get_session_key( PKT_pubkey_enc *k, DEK *dek ); diff --git a/g10/pkglue.c b/g10/pkglue.c index cbfe21ea8..f3001f549 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -44,63 +44,6 @@ mpi_from_sexp (gcry_sexp_t sexp, const char * item) } -/**************** - * Emulate our old PK interface here - sometime in the future we might - * change the internal design to directly fit to libgcrypt. - */ -int -pk_sign (int algo, gcry_mpi_t * data, gcry_mpi_t hash, gcry_mpi_t * skey) -{ - gcry_sexp_t s_sig, s_hash, s_skey; - int rc; - - /* make a sexp from skey */ - if (algo == GCRY_PK_DSA) - { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", - skey[0], skey[1], skey[2], skey[3], skey[4]); - } - else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S) - { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", - skey[0], skey[1], skey[2], skey[3], skey[4], - skey[5]); - } - else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) - { - rc = gcry_sexp_build (&s_skey, NULL, - "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", - skey[0], skey[1], skey[2], skey[3]); - } - else - return GPG_ERR_PUBKEY_ALGO; - - if (rc) - BUG (); - - /* put hash into a S-Exp s_hash */ - if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) - BUG (); - - rc = gcry_pk_sign (&s_sig, s_hash, s_skey); - gcry_sexp_release (s_hash); - gcry_sexp_release (s_skey); - - if (rc) - ; - else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S) - data[0] = mpi_from_sexp (s_sig, "s"); - else - { - data[0] = mpi_from_sexp (s_sig, "r"); - data[1] = mpi_from_sexp (s_sig, "s"); - } - - gcry_sexp_release (s_sig); - return rc; -} /**************** * Emulate our old PK interface here - sometime in the future we might @@ -304,7 +247,7 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data, /* Check whether SKEY is a suitable secret key. */ int -pk_check_secret_key (int algo, gcry_mpi_t *skey) +REMOVE_ME_pk_check_secret_key (int algo, gcry_mpi_t *skey) { gcry_sexp_t s_skey; int rc; diff --git a/g10/pkglue.h b/g10/pkglue.h index 89d2216b5..f97def153 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -20,8 +20,6 @@ #ifndef GNUPG_G10_PKGLUE_H #define GNUPG_G10_PKGLUE_H -int pk_sign (int algo, gcry_mpi_t *data, gcry_mpi_t hash, - gcry_mpi_t *skey); int pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey); int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index fedf4d9a9..b904c7976 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -114,10 +114,10 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) xfree(p); } - rc = check_secret_key( sk, opt.try_all_secrets?1:-1 ); /* ask - only - once */ - if( !rc ) + /* rc = check_secret_key( sk, opt.try_all_secrets?1:-1 ); /\* ask */ + /* only */ + /* once *\/ */ + /* if( !rc ) */ { rc = get_it( k, dek, sk, keyid ); /* Successfully checked the secret key (either it was diff --git a/g10/revoke.c b/g10/revoke.c index 5e22a709a..216c60389 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -436,181 +436,144 @@ gen_desig_revoke( const char *uname, strlist_t locusr ) * Generate a revocation certificate for UNAME */ int -gen_revoke( const char *uname ) +gen_revoke (const char *uname) { - int rc = 0; - armor_filter_context_t *afx; - PACKET pkt; - PKT_secret_key *sk; /* used as pointer into a kbnode */ - PKT_public_key *pk = NULL; - PKT_signature *sig = NULL; - u32 sk_keyid[2]; - IOBUF out = NULL; - KBNODE keyblock = NULL, pub_keyblock = NULL; - KBNODE node; - KEYDB_HANDLE kdbhd; - struct revocation_reason_info *reason = NULL; - KEYDB_SEARCH_DESC desc; + int rc = 0; + armor_filter_context_t *afx; + PACKET pkt; + PKT_public_key *psk; + PKT_signature *sig = NULL; + u32 keyid[2]; + iobuf_t out = NULL; + kbnode_t keyblock = NULL; + kbnode_t node; + KEYDB_HANDLE kdbhd; + struct revocation_reason_info *reason = NULL; + KEYDB_SEARCH_DESC desc; - if( opt.batch ) - { - log_error(_("can't do this in batch mode\n")); - return G10ERR_GENERAL; - } - - afx = new_armor_context (); - init_packet( &pkt ); - - /* search the userid: - * We don't want the whole getkey stuff here but the entire keyblock - */ - kdbhd = keydb_new (1); - rc = classify_user_id (uname, &desc); - if (!rc) - rc = keydb_search (kdbhd, &desc, 1); - if (rc) - { - log_error (_("secret key \"%s\" not found: %s\n"), - uname, g10_errstr (rc)); - goto leave; - } - - rc = keydb_get_keyblock (kdbhd, &keyblock ); - if( rc ) { - log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) ); - goto leave; + if( opt.batch ) + { + log_error(_("can't do this in batch mode\n")); + return G10ERR_GENERAL; } - /* get the keyid from the keyblock */ - node = find_kbnode( keyblock, PKT_SECRET_KEY ); - if( !node ) - BUG (); + afx = new_armor_context (); + init_packet( &pkt ); - /* fixme: should make a function out of this stuff, - * it's used all over the source */ - sk = node->pkt->pkt.secret_key; - keyid_from_sk( sk, sk_keyid ); - print_seckey_info (sk); - - /* FIXME: We should get the public key direct from the secret one */ - - pub_keyblock=get_pubkeyblock(sk_keyid); - if(!pub_keyblock) - { - log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) ); - goto leave; - } - - node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY); - if(!node) - BUG(); - - pk=node->pkt->pkt.public_key; - - if( cmp_public_secret_key( pk, sk ) ) { - log_error(_("public key does not match secret key!\n") ); - rc = G10ERR_GENERAL; - goto leave; + /* Search the userid; we don't want the whole getkey stuff here. */ + kdbhd = keydb_new (1); + rc = classify_user_id (uname, &desc); + if (!rc) + rc = keydb_search (kdbhd, &desc, 1); + if (rc) + { + log_error (_("secret key \"%s\" not found: %s\n"), + uname, g10_errstr (rc)); + goto leave; } - tty_printf("\n"); - if( !cpr_get_answer_is_yes("gen_revoke.okay", - _("Create a revocation certificate for this key? (y/N) ")) ) - { - rc = 0; - goto leave; - } + rc = keydb_get_keyblock (kdbhd, &keyblock ); + if( rc ) { + log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) ); + goto leave; + } - if(sk->version>=4 || opt.force_v4_certs) { - /* get the reason for the revocation */ - reason = ask_revocation_reason( 1, 0, 1 ); - if( !reason ) { /* user decided to cancel */ - rc = 0; - goto leave; - } + /* Get the keyid from the keyblock. */ + node = find_kbnode (keyblock, PKT_PUBLIC_KEY); + if (!node) + BUG (); + + /* fixme: should make a function out of this stuff, + * it's used all over the source */ + psk = node->pkt->pkt.public_key; + keyid_from_pk (psk, keyid ); + print_seckey_info (psk); + +#warning add code to check that the secret key is available + + tty_printf("\n"); + if (!cpr_get_answer_is_yes ("gen_revoke.okay", + _("Create a revocation certificate for this key? (y/N) "))) + { + rc = 0; + goto leave; } - - switch( is_secret_key_protected( sk ) ) { - case -1: - log_error(_("unknown protection algorithm\n")); - rc = G10ERR_PUBKEY_ALGO; - break; - case -3: - tty_printf (_("Secret parts of primary key are not available.\n")); - rc = G10ERR_NO_SECKEY; - break; - case 0: - tty_printf(_("NOTE: This key is not protected!\n")); - break; - default: - rc = check_secret_key( sk, 0 ); - break; + + if (psk->version >= 4 || opt.force_v4_certs) + { + /* Get the reason for the revocation. */ + reason = ask_revocation_reason (1, 0, 1); + if (!reason) + { + /* user decided to cancel */ + rc = 0; + goto leave; + } } - if( rc ) - goto leave; + + if (!opt.armor) + tty_printf (_("ASCII armored output forced.\n")); + if ((rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out ))) + goto leave; - if( !opt.armor ) - tty_printf(_("ASCII armored output forced.\n")); + afx->what = 1; + afx->hdrlines = "Comment: A revocation certificate should follow\n"; + push_armor_filter (afx, out); - if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out )) ) - goto leave; - - afx->what = 1; - afx->hdrlines = "Comment: A revocation certificate should follow\n"; - push_armor_filter (afx, out); - - /* create it */ - rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, - opt.force_v4_certs?4:0, 0, 0, - revocation_reason_build_cb, reason ); - if( rc ) { - log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc)); - goto leave; + /* create it */ + rc = make_keysig_packet (&sig, psk, NULL, NULL, psk, 0x20, 0, + opt.force_v4_certs?4:0, 0, 0, + revocation_reason_build_cb, reason ); + if (rc) + { + log_error (_("make_keysig_packet failed: %s\n"), g10_errstr (rc)); + goto leave; } - - if(PGP2 || PGP6 || PGP7 || PGP8) - { - /* Use a minimal pk for PGPx mode, since PGP can't import bare - revocation certificates. */ - rc=export_minimal_pk(out,pub_keyblock,sig,NULL); - if(rc) - goto leave; - } - else - { - init_packet( &pkt ); - pkt.pkttype = PKT_SIGNATURE; - pkt.pkt.signature = sig; - - rc = build_packet( out, &pkt ); - if( rc ) { - log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); - goto leave; - } - } - - /* and issue a usage notice */ - tty_printf(_("Revocation certificate created.\n\n" + + if (PGP2 || PGP6 || PGP7 || PGP8) + { + /* Use a minimal pk for PGPx mode, since PGP can't import bare + revocation certificates. */ + rc = export_minimal_pk (out, keyblock, sig, NULL); + if(rc) + goto leave; + } + else + { + init_packet( &pkt ); + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + + rc = build_packet (out, &pkt); + if (rc) + { + log_error(_("build_packet failed: %s\n"), g10_errstr(rc) ); + goto leave; + } + } + + /* and issue a usage notice */ + tty_printf (_( +"Revocation certificate created.\n\n" "Please move it to a medium which you can hide away; if Mallory gets\n" "access to this certificate he can use it to make your key unusable.\n" "It is smart to print this certificate and store it away, just in case\n" "your media become unreadable. But have some caution: The print system of\n" "your machine might store the data and make it available to others!\n")); - leave: - if( sig ) - free_seckey_enc( sig ); - release_kbnode( keyblock ); - release_kbnode( pub_keyblock ); - keydb_release (kdbhd); - if( rc ) - iobuf_cancel(out); - else - iobuf_close(out); - release_revocation_reason_info( reason ); - release_armor_context (afx); - return rc; + leave: + if (sig) + free_seckey_enc (sig); + release_kbnode (keyblock); + keydb_release (kdbhd); + if (rc) + iobuf_cancel(out); + else + iobuf_close(out); + release_revocation_reason_info( reason ); + release_armor_context (afx); + return rc; } diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 9995aa416..fed92134e 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -259,58 +259,6 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, -/**************** - * Check the secret key - * Ask up to 3 (or n) times for a correct passphrase - * If n is negative, disable the key info prompt and make n=abs(n) - */ -int -check_secret_key( PKT_secret_key *sk, int n ) -{ - int rc = gpg_error (GPG_ERR_BAD_PASSPHRASE); - int i,mode; - - if (sk && sk->is_protected && sk->protect.s2k.mode == 1002) - return 0; /* Let the scdaemon handle this. */ - - if(n<0) - { - n=abs(n); - mode=1; - } - else - mode=0; - - if( n < 1 ) - n = 3; /* Use the default value */ - - for(i=0; i < n && gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE; i++ ) { - int canceled = 0; - const char *tryagain = NULL; - if (i) { - tryagain = N_("Invalid passphrase; please try again"); - log_info (_("%s ...\n"), _(tryagain)); - } - rc = do_check( sk, tryagain, mode, &canceled ); - if ( gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE - && is_status_enabled () ) { - u32 kid[2]; - char buf[50]; - - keyid_from_sk( sk, kid ); - sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]); - write_status_text( STATUS_BAD_PASSPHRASE, buf ); - } - if( have_static_passphrase() || canceled) - break; - } - - if( !rc ) - write_status( STATUS_GOOD_PASSPHRASE ); - - return rc; -} - /**************** * check whether the secret key is protected. * Returns: 0 not protected, -1 on error or the protection algorithm @@ -318,156 +266,10 @@ check_secret_key( PKT_secret_key *sk, int n ) * -3 indicates a not-online stub. */ int -is_secret_key_protected( PKT_secret_key *sk ) +is_secret_key_protected (PKT_public_key *pk) { - return sk->is_protected? - sk->protect.s2k.mode == 1002? -2 : - sk->protect.s2k.mode == 1001? -3 : sk->protect.algo : 0; -} - - - -/**************** - * Protect the secret key with the passphrase from DEK - */ -int -protect_secret_key( PKT_secret_key *sk, DEK *dek ) -{ - int i,j, rc = 0; - byte *buffer; - size_t nbytes; - u16 csum; - - if( !dek ) - return 0; - - if( !sk->is_protected ) { /* okay, apply the protection */ - gcry_cipher_hd_t cipher_hd=NULL; - - if ( openpgp_cipher_test_algo ( sk->protect.algo ) ) { - /* Unsupport protection algorithm. */ - rc = gpg_error (GPG_ERR_CIPHER_ALGO); - } - else { - print_cipher_algo_note( sk->protect.algo ); - - if ( openpgp_cipher_open (&cipher_hd, sk->protect.algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | (sk->protect.algo >= 100 ? - 0 : GCRY_CIPHER_ENABLE_SYNC))) ) - BUG(); - if ( gcry_cipher_setkey ( cipher_hd, dek->key, dek->keylen ) ) - log_info(_("WARNING: Weak key detected" - " - please change passphrase again.\n")); - sk->protect.ivlen = openpgp_cipher_get_algo_blklen (sk->protect.algo); - assert( sk->protect.ivlen <= DIM(sk->protect.iv) ); - if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 ) - BUG(); /* yes, we are very careful */ - gcry_create_nonce (sk->protect.iv, sk->protect.ivlen); - gcry_cipher_setiv (cipher_hd, sk->protect.iv, sk->protect.ivlen); - if( sk->version >= 4 ) { - byte *bufarr[PUBKEY_MAX_NSKEY]; - size_t narr[PUBKEY_MAX_NSKEY]; - unsigned int nbits[PUBKEY_MAX_NSKEY]; - int ndata=0; - byte *p, *data; - - for (j=0, i = pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) - { - assert (!gcry_mpi_get_flag (sk->skey[i], - GCRYMPI_FLAG_OPAQUE)); - if (gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, - narr+j, sk->skey[i])) - BUG(); - nbits[j] = gcry_mpi_get_nbits (sk->skey[i]); - ndata += narr[j] + 2; - } - for ( ; j < PUBKEY_MAX_NSKEY; j++ ) - bufarr[j] = NULL; - - ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */ - - data = xmalloc_secure( ndata ); - p = data; - for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) { - p[0] = nbits[j] >> 8 ; - p[1] = nbits[j]; - p += 2; - memcpy(p, bufarr[j], narr[j] ); - p += narr[j]; - xfree(bufarr[j]); - } - - if (opt.simple_sk_checksum) { - log_info (_("generating the deprecated 16-bit checksum" - " for secret key protection\n")); - csum = checksum( data, ndata-2); - sk->csum = csum; - *p++ = csum >> 8; - *p++ = csum; - sk->protect.sha1chk = 0; - } - else { - 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); - gcry_md_final (h); - memcpy (p, gcry_md_read (h, DIGEST_ALGO_SHA1), 20); - p += 20; - gcry_md_close (h); - sk->csum = csum = 0; - sk->protect.sha1chk = 1; - } - assert( p == data+ndata ); - - gcry_cipher_encrypt (cipher_hd, data, ndata, NULL, 0); - for (i = pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++ ) - { - gcry_mpi_release (sk->skey[i]); - sk->skey[i] = NULL; - } - i = pubkey_get_npkey(sk->pubkey_algo); - sk->skey[i] = gcry_mpi_set_opaque (NULL, data, ndata*8 ); - } - else { - csum = 0; - for(i=pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { - byte *data; - unsigned int nbits; - - csum += checksum_mpi (sk->skey[i]); - - if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, - &nbytes, sk->skey[i] )) - BUG(); - gcry_cipher_sync (cipher_hd); - assert (!gcry_mpi_get_flag (sk->skey[i], - GCRYMPI_FLAG_OPAQUE)); - - data = xmalloc (nbytes+2); /* fixme: need xtrymalloc. */ - nbits = gcry_mpi_get_nbits (sk->skey[i]); - assert (nbytes == (nbits + 7)/8); - data[0] = nbits >> 8; - data[1] = nbits; - gcry_cipher_encrypt (cipher_hd, data+2, nbytes, - buffer, nbytes); - xfree( buffer ); - - gcry_mpi_release (sk->skey[i]); - sk->skey[i] = gcry_mpi_set_opaque (NULL, - data, (nbytes+2)*8 ); - } - sk->csum = csum; - } - sk->is_protected = 1; - gcry_cipher_close (cipher_hd); - } - } - return rc; + return 0; /* FIXME: use agent_get_keyinfo?*/ + /* return sk->is_protected? */ + /* sk->protect.s2k.mode == 1002? -2 : */ + /* sk->protect.s2k.mode == 1001? -3 : sk->protect.algo : 0; */ } diff --git a/g10/seskey.c b/g10/seskey.c index ccbfe30af..ee5584c66 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -206,19 +206,18 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits, * bits. */ gcry_mpi_t -encode_md_value (PKT_public_key *pk, PKT_secret_key *sk, - gcry_md_hd_t md, int hash_algo) +encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo) { gcry_mpi_t frame; - assert(hash_algo); - assert(pk || sk); + assert (hash_algo); + assert (pk); - if((pk?pk->pubkey_algo:sk->pubkey_algo) == GCRY_PK_DSA) + if (pk->pubkey_algo == GCRY_PK_DSA) { /* It's a DSA signature, so find out the size of q. */ - size_t qbytes = gcry_mpi_get_nbits (pk?pk->pkey[1]:sk->skey[1]); + size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]); /* Make sure it is a multiple of 8 bits. */ @@ -237,21 +236,19 @@ encode_md_value (PKT_public_key *pk, PKT_secret_key *sk, DSA. ;) */ if (qbytes < 160) { - log_error (_("DSA key %s uses an unsafe (%u bit) hash\n"), - pk?keystr_from_pk(pk):keystr_from_sk(sk), - (unsigned int)qbytes); + log_error (_("DSA key %s uses an unsafe (%zu bit) hash\n"), + keystr_from_pk (pk), qbytes); return NULL; } - qbytes/=8; + qbytes /= 8; /* Check if we're too short. Too long is safe as we'll automatically left-truncate. */ if (gcry_md_get_algo_dlen (hash_algo) < qbytes) { - log_error (_("DSA key %s requires a %u bit or larger hash\n"), - pk?keystr_from_pk(pk):keystr_from_sk(sk), - (unsigned int)(qbytes*8)); + log_error (_("DSA key %s requires a %zu bit or larger hash\n"), + keystr_from_pk(pk), qbytes*8); return NULL; } @@ -269,12 +266,13 @@ encode_md_value (PKT_public_key *pk, PKT_secret_key *sk, if (rc) log_fatal ("can't get OID of digest algorithm %d: %s\n", hash_algo, gpg_strerror (rc)); - asn = xmalloc (asnlen); + asn = xtrymalloc (asnlen); + if (!asn) + return NULL; if ( gcry_md_algo_info (hash_algo, GCRYCTL_GET_ASNOID, asn, &asnlen) ) BUG(); frame = do_encode_md (md, hash_algo, gcry_md_get_algo_dlen (hash_algo), - gcry_mpi_get_nbits (pk?pk->pkey[0]:sk->skey[0]), - asn, asnlen); + gcry_mpi_get_nbits (pk->pkey[0]), asn, asnlen); xfree (asn); } diff --git a/g10/sig-check.c b/g10/sig-check.c index 1feac3862..a24890fd5 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -315,7 +315,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, gcry_md_hd_t digest, } gcry_md_final( digest ); - result = encode_md_value( pk, NULL, digest, sig->digest_algo ); + result = encode_md_value (pk, digest, sig->digest_algo ); if (!result) return G10ERR_GENERAL; ctx.sig = sig; diff --git a/g10/sign.c b/g10/sign.c index d06a9cc5f..eb3ec1f48 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -228,37 +228,55 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig) } +static gcry_mpi_t +mpi_from_sexp (gcry_sexp_t sexp, const char * item) +{ + gcry_sexp_t list; + gcry_mpi_t data; + + list = gcry_sexp_find_token (sexp, item, 0); + assert (list); + data = gcry_sexp_nth_mpi (list, 1, 0); + assert (data); + gcry_sexp_release (list); + return data; +} + + static int do_sign (PKT_public_key *pksk, PKT_signature *sig, - gcry_md_hd_t md, int digest_algo) + gcry_md_hd_t md, int mdalgo) { - gcry_mpi_t frame; - byte *dp; - int rc; + gpg_error_t err; + gcry_mpi_t frame; + byte *dp; - if (pksk->timestamp > sig->timestamp ) { - ulong d = pksk->timestamp - sig->timestamp; - log_info( d==1 ? _("key has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key has been created %lu seconds " - "in future (time warp or clock problem)\n"), d ); - if( !opt.ignore_time_conflict ) - return G10ERR_TIME_CONFLICT; + if (pksk->timestamp > sig->timestamp ) + { + ulong d = pksk->timestamp - sig->timestamp; + log_info (d==1 ? _("key has been created %lu second " + "in future (time warp or clock problem)\n") + : _("key has been created %lu seconds " + "in future (time warp or clock problem)\n"), d ); + if (!opt.ignore_time_conflict) + return gpg_error (GPG_ERR_TIME_CONFLICT); } + + print_pubkey_algo_note (pksk->pubkey_algo); - print_pubkey_algo_note (pksk->pubkey_algo); + if (!mdalgo) + mdalgo = gcry_md_get_algo (md); - if( !digest_algo ) - digest_algo = gcry_md_get_algo (md); + print_digest_algo_note (mdalgo); + dp = gcry_md_read (md, mdalgo); + sig->digest_algo = mdalgo; + sig->digest_start[0] = dp[0]; + sig->digest_start[1] = dp[1]; + sig->data[0] = NULL; + sig->data[1] = NULL; - print_digest_algo_note( digest_algo ); - dp = gcry_md_read ( md, digest_algo ); - sig->digest_algo = digest_algo; - sig->digest_start[0] = dp[0]; - sig->digest_start[1] = dp[1]; - - /* FIXME: Use agent. */ +#warning fixme: Use the agent for the card /* if (pksk->is_protected && pksk->protect.s2k.mode == 1002) */ /* { */ /* #ifdef ENABLE_CARD_SUPPORT */ @@ -285,57 +303,89 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig, /* #endif /\* ENABLE_CARD_SUPPORT *\/ */ /* } */ /* else */ - { - frame = encode_md_value (NULL, pksk, md, digest_algo ); - if (!frame) - return G10ERR_GENERAL; - rc = pk_sign (pksk->pubkey_algo, sig->data, frame, pksk->pkey ); - gcry_mpi_release (frame); - } - - if (!rc && !opt.no_sig_create_check) { - /* Check that the signature verification worked and nothing is - * fooling us e.g. by a bug in the signature create - * code or by deliberately introduced faults. */ - PKT_public_key *pk = xmalloc_clear (sizeof *pk); - - if( get_pubkey( pk, sig->keyid ) ) - rc = G10ERR_NO_PUBKEY; - else { - frame = encode_md_value (pk, NULL, md, sig->digest_algo ); - if (!frame) - rc = G10ERR_GENERAL; - else - rc = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey ); - gcry_mpi_release (frame); + if (1) + { + char *hexgrip; + + err = hexkeygrip_from_pk (pksk, &hexgrip); + if (!err) + { + char *desc; + gcry_sexp_t s_sigval; + + /* FIXME: desc = gpgsm_format_keydesc (cert); */ + desc = xtrystrdup ("FIXME: Format a decription"); + + err = agent_pksign (NULL/*ctrl*/, hexgrip, desc, + dp, gcry_md_get_algo_dlen (mdalgo), mdalgo, + &s_sigval); + + xfree (desc); + + if (err) + ; + else if (pksk->pubkey_algo == GCRY_PK_RSA + || pksk->pubkey_algo == GCRY_PK_RSA_S) + sig->data[0] = mpi_from_sexp (s_sigval, "s"); + else + { + sig->data[0] = mpi_from_sexp (s_sigval, "r"); + sig->data[1] = mpi_from_sexp (s_sigval, "s"); + } + + gcry_sexp_release (s_sigval); } - if (rc) - log_error (_("checking created signature failed: %s\n"), - g10_errstr (rc)); - free_public_key (pk); + xfree (hexgrip); } - if( rc ) - log_error(_("signing failed: %s\n"), g10_errstr(rc) ); - else { - if( opt.verbose ) { - char *ustr = get_user_id_string_native (sig->keyid); - log_info(_("%s/%s signature from: \"%s\"\n"), - gcry_pk_algo_name (pksk->pubkey_algo), - gcry_md_algo_name (sig->digest_algo), - ustr ); - xfree(ustr); + + /* Check that the signature verification worked and nothing is + * fooling us e.g. by a bug in the signature create code or by + * deliberately introduced faults. */ + if (!err && !opt.no_sig_create_check) + { + PKT_public_key *pk = xmalloc_clear (sizeof *pk); + + if (get_pubkey (pk, sig->keyid )) + err = gpg_error (GPG_ERR_NO_PUBKEY); + else + { + frame = encode_md_value (pk, md, sig->digest_algo ); + if (!frame) + err = gpg_error (GPG_ERR_GENERAL); + else + err = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey); + gcry_mpi_release (frame); + } + if (err) + log_error (_("checking created signature failed: %s\n"), + g10_errstr (err)); + free_public_key (pk); + } + + if (err) + log_error (_("signing failed: %s\n"), g10_errstr (err)); + else + { + if (opt.verbose) + { + char *ustr = get_user_id_string_native (sig->keyid); + log_info (_("%s/%s signature from: \"%s\"\n"), + gcry_pk_algo_name (pksk->pubkey_algo), + gcry_md_algo_name (sig->digest_algo), + ustr); + xfree (ustr); } } - return rc; + return err; } int -complete_sig( PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md ) +complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md) { int rc; - if (!(rc = check_secret_key (pksk, 0))) + /* if (!(rc = check_secret_key (pksk, 0))) */ rc = do_sign (pksk, sig, md, 0); return rc; }