diff --git a/agent/ChangeLog b/agent/ChangeLog index e584005ff..5d726eab3 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,16 @@ +2010-09-01 Werner Koch + + * call-pinentry.c (start_pinentry): Disable pinentry logging. + + * command.c (cmd_import_key, cmd_genkey): Add CACHE handling. + * cvt-openpgp.c (convert_openpgp): Add arg CACHE_NONCE and try the + cached nonce first. + * genkey.c (agent_genkey): Add arg CACHE_NONCE. + * cache.c (agent_get_cache): Require user and impgen cache modes + to match the requested mode. + (agent_put_cache): Ditto. + * agent.h (CACHE_MODE_IMPGEN): New. + 2010-08-31 Werner Koch * pksign.c (do_encode_dsa): Fix sign problem. diff --git a/agent/agent.h b/agent/agent.h index 57078ab40..cb06faca3 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -193,7 +193,9 @@ typedef enum CACHE_MODE_ANY, /* Any mode except ignore matches. */ CACHE_MODE_NORMAL, /* Normal cache (gpg-agent). */ CACHE_MODE_USER, /* GET_PASSPHRASE related cache. */ - CACHE_MODE_SSH /* SSH related cache. */ + CACHE_MODE_SSH, /* SSH related cache. */ + CACHE_MODE_IMPGEN /* Used for import and genkey. This is a + non-predictable nonce. */ } cache_mode_t; @@ -286,7 +288,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, char **r_passphrase); -int agent_genkey (ctrl_t ctrl, +int agent_genkey (ctrl_t ctrl, const char *cache_nonce, const char *keyparam, size_t keyparmlen, membuf_t *outbuf); int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); diff --git a/agent/cache.c b/agent/cache.c index 10f9ef65a..0a2dd00cb 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -1,5 +1,5 @@ /* cache.c - keep a cache of passphrases - * Copyright (C) 2002 Free Software Foundation, Inc. + * Copyright (C) 2002, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -131,9 +131,9 @@ housekeeping (void) { if (r->lockcount) { - log_error ("can't remove unused cache entry `%s' due to" + log_error ("can't remove unused cache entry `%s' (mode %d) due to" " lockcount=%d\n", - r->key, r->lockcount); + r->key, r->cache_mode, r->lockcount); r->accessed += 60*10; /* next error message in 10 minutes */ rprev = r; r = r->next; @@ -142,7 +142,8 @@ housekeeping (void) { ITEM r2 = r->next; if (DBG_CACHE) - log_debug (" removed `%s' (slot not used for 30m)\n", r->key); + log_debug (" removed `%s' (mode %d) (slot not used for 30m)\n", + r->key, r->cache_mode); xfree (r); if (!rprev) thecache = r2; @@ -203,8 +204,8 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, ITEM r; if (DBG_CACHE) - log_debug ("agent_put_cache `%s' requested ttl=%d mode=%d\n", - key, ttl, cache_mode); + log_debug ("agent_put_cache `%s' (mode %d) requested ttl=%d\n", + key, cache_mode, ttl); housekeeping (); if (!ttl) @@ -220,7 +221,11 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, for (r=thecache; r; r = r->next) { - if (!r->lockcount && !strcmp (r->key, key)) + if (!r->lockcount + && ((cache_mode != CACHE_MODE_USER + && cache_mode != CACHE_MODE_IMPGEN) + || r->cache_mode == cache_mode) + && !strcmp (r->key, key)) break; } if (r) @@ -269,7 +274,8 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, /* Try to find an item in the cache. Note that we currently don't - make use of CACHE_MODE. */ + make use of CACHE_MODE except for CACHE_MODE_IMPGEN and + CACHE_MODE_USER. */ const char * agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id) { @@ -279,7 +285,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id) return NULL; if (DBG_CACHE) - log_debug ("agent_get_cache `%s'...\n", key); + log_debug ("agent_get_cache `%s' (mode %d) ...\n", key, cache_mode); housekeeping (); /* first try to find one with no locks - this is an updated cache @@ -287,7 +293,11 @@ agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id) lockcount. */ for (r=thecache; r; r = r->next) { - if (!r->lockcount && r->pw && !strcmp (r->key, key)) + if (!r->lockcount && r->pw + && ((cache_mode != CACHE_MODE_USER + && cache_mode != CACHE_MODE_IMPGEN) + || r->cache_mode == cache_mode) + && !strcmp (r->key, key)) { /* put_cache does only put strings into the cache, so we don't need the lengths */ @@ -302,7 +312,11 @@ agent_get_cache (const char *key, cache_mode_t cache_mode, void **cache_id) /* again, but this time get even one with a lockcount set */ for (r=thecache; r; r = r->next) { - if (r->pw && !strcmp (r->key, key)) + if (r->pw + && ((cache_mode != CACHE_MODE_USER + && cache_mode != CACHE_MODE_IMPGEN) + || r->cache_mode == cache_mode) + && !strcmp (r->key, key)) { r->accessed = gnupg_get_time (); if (DBG_CACHE) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index d00fdf6fc..6ab845a0c 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -316,6 +316,12 @@ start_pinentry (ctrl_t ctrl) log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc)); return rc; } + /* We don't want to log the pinentry communication to make the logs + easier to read. We might want to add a new debug option to enable + pinentry logging. */ +#ifdef ASSUAN_NO_LOGGING + assuan_set_flag (ctx, ASSUAN_NO_LOGGING, 1); +#endif /* Connect to the pinentry and perform initial handshaking. Note that atfork is used to change the environment for pinentry. We diff --git a/agent/command.c b/agent/command.c index 4b847e503..965d24d84 100644 --- a/agent/command.c +++ b/agent/command.c @@ -766,7 +766,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) static const char hlp_genkey[] = - "GENKEY\n" + "GENKEY []\n" "\n" "Generate a new key, store the secret part and return the public\n" "part. Here is an example transaction:\n" @@ -787,8 +787,15 @@ cmd_genkey (assuan_context_t ctx, char *line) unsigned char *value; size_t valuelen; membuf_t outbuf; - - (void)line; + char *cache_nonce = NULL; + char *p; + + p = line; + for (p=line; *p && *p != ' ' && *p != '\t'; p++) + ; + *p = '\0'; + if (*line) + cache_nonce = xtrystrdup (line); /* First inquire the parameters */ rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM); @@ -797,12 +804,13 @@ cmd_genkey (assuan_context_t ctx, char *line) init_membuf (&outbuf, 512); - rc = agent_genkey (ctrl, (char*)value, valuelen, &outbuf); + rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, &outbuf); xfree (value); if (rc) clear_outbuf (&outbuf); else rc = write_and_clear_outbuf (ctx, &outbuf); + xfree (cache_nonce); return leave_cmd (ctx, rc); } @@ -1463,7 +1471,7 @@ cmd_keywrap_key (assuan_context_t ctx, char *line) static const char hlp_import_key[] = - "IMPORT_KEY\n" + "IMPORT_KEY []\n" "\n" "Import a secret key into the key store. The key is expected to be\n" "encrypted using the current session's key wrapping key (cf. command\n" @@ -1485,15 +1493,22 @@ cmd_import_key (assuan_context_t ctx, char *line) size_t finalkeylen; unsigned char grip[20]; gcry_sexp_t openpgp_sexp = NULL; + char *cache_nonce = NULL; + char *p; - (void)line; - if (!ctrl->server_local->import_key) { err = gpg_error (GPG_ERR_MISSING_KEY); goto leave; } + p = line; + for (p=line; *p && *p != ' ' && *p != '\t'; p++) + ; + *p = '\0'; + if (*line) + cache_nonce = xtrystrdup (line); + assuan_begin_confidential (ctx); err = assuan_inquire (ctx, "KEYDATA", &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA); @@ -1567,13 +1582,26 @@ cmd_import_key (assuan_context_t ctx, char *line) key import. */ err = convert_openpgp (ctrl, openpgp_sexp, grip, - ctrl->server_local->keydesc, + ctrl->server_local->keydesc, cache_nonce, &key, &passphrase); if (err) goto leave; realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); if (!realkeylen) goto leave; /* Invalid canonical encoded S-expression. */ + if (passphrase) + { + if (!cache_nonce) + { + char buf[12]; + gcry_create_nonce (buf, 12); + cache_nonce = bin2hex (buf, 12, NULL); + } + if (cache_nonce + && !agent_put_cache (cache_nonce, CACHE_MODE_IMPGEN, + passphrase, 120 /*seconds*/)) + assuan_write_status (ctx, "CACHE_NONCE", cache_nonce); + } } else { @@ -1604,6 +1632,7 @@ cmd_import_key (assuan_context_t ctx, char *line) xfree (key); gcry_cipher_close (cipherhd); xfree (wrappedkey); + xfree (cache_nonce); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; return leave_cmd (ctx, err); diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index a392518ba..87f62042a 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -497,7 +497,8 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi) gpg_error_t err; struct try_do_unprotect_arg_s *arg = pi->check_cb_arg; - err = do_unprotect (pi->pin, arg->is_v4? 4:3, + err = do_unprotect (pi->pin, + arg->is_v4? 4:3, arg->pubkey_algo, arg->is_protected, arg->skey, arg->skeysize, arg->protect_algo, arg->iv, arg->ivlen, @@ -507,15 +508,16 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi) /* SKEY may be modified now, thus we need to re-compute SKEYIDX. */ for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize && arg->skey[arg->skeyidx]); arg->skeyidx++) - ; + ; return err; } /* Convert an OpenPGP transfer key into our internal format. Before asking for a passphrase we check whether the key already exists in - our key storage. S_PGP is the OpenPGP key in transfer format. On - success R_KEY will receive a canonical encoded S-expression with + our key storage. S_PGP is the OpenPGP key in transfer format. If + CACHE_NONCE is given the passphrase will be looked up in the cache. + On success R_KEY will receive a canonical encoded S-expression with the unprotected key in our internal format; the caller needs to release that memory. The passphrase used to decrypt the OpenPGP key will be returned at R_PASSPHRASE; the caller must release this @@ -525,6 +527,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi) gpg_error_t convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, unsigned char *grip, const char *prompt, + const char *cache_nonce, unsigned char **r_key, char **r_passphrase) { gpg_error_t err; @@ -759,7 +762,26 @@ convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, pi_arg.skeysize = DIM (skey); pi_arg.skeyidx = skeyidx; pi_arg.r_key = &s_skey; - err = agent_askpin (ctrl, prompt, NULL, NULL, pi); + + err = gpg_error (GPG_ERR_BAD_PASSPHRASE); + if (cache_nonce) + { + void *cache_marker = NULL; + const char *cache_value; + + cache_value = agent_get_cache (cache_nonce, CACHE_MODE_IMPGEN, + &cache_marker); + if (cache_value) + { + if (strlen (cache_value) < pi->max_length) + strcpy (pi->pin, cache_value); + agent_unlock_cache_entry (&cache_marker); + } + if (*pi->pin) + err = try_do_unprotect_cb (pi); + } + if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE) + err = agent_askpin (ctrl, prompt, NULL, NULL, pi); skeyidx = pi_arg.skeyidx; if (!err) { diff --git a/agent/cvt-openpgp.h b/agent/cvt-openpgp.h index 17b1a6ead..8dafbc454 100644 --- a/agent/cvt-openpgp.h +++ b/agent/cvt-openpgp.h @@ -21,6 +21,7 @@ gpg_error_t convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, unsigned char *grip, const char *prompt, + const char *cache_nonce, unsigned char **r_key, char **r_passphrase); diff --git a/agent/genkey.c b/agent/genkey.c index b064c98ed..60cc3416f 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -351,9 +351,11 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, /* Generate a new keypair according to the parameters given in - KEYPARAM */ + KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase + using the cache nonce. */ int -agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, +agent_genkey (ctrl_t ctrl, const char *cache_nonce, + const char *keyparam, size_t keyparamlen, membuf_t *outbuf) { gcry_sexp_t s_keyparam, s_key, s_private, s_public; @@ -370,10 +372,28 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, } /* Get the passphrase now, cause key generation may take a while. */ - rc = agent_ask_new_passphrase (ctrl, - _("Please enter the passphrase to%0A" - "to protect your new key"), - &passphrase); + if (cache_nonce) + { + void *cache_marker = NULL; + const char *cache_value; + + cache_value = agent_get_cache (cache_nonce, CACHE_MODE_IMPGEN, + &cache_marker); + if (cache_value) + { + passphrase = xtrymalloc_secure (strlen (cache_value)+1); + if (passphrase) + strcpy (passphrase, cache_value); + agent_unlock_cache_entry (&cache_marker); + } + } + if (passphrase) + rc = 0; + else + rc = agent_ask_new_passphrase (ctrl, + _("Please enter the passphrase to%0A" + "to protect your new key"), + &passphrase); if (rc) return rc; @@ -410,6 +430,19 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen, if (DBG_CRYPTO) log_debug ("storing private key\n"); rc = store_key (s_private, passphrase, 0); + if (!rc) + { + if (!cache_nonce) + { + char tmpbuf[12]; + gcry_create_nonce (tmpbuf, 12); + cache_nonce = bin2hex (tmpbuf, 12, NULL); + } + if (cache_nonce + && !agent_put_cache (cache_nonce, CACHE_MODE_IMPGEN, + passphrase, 900 /*seconds*/)) + agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL); + } xfree (passphrase); passphrase = NULL; gcry_sexp_release (s_private); diff --git a/g10/ChangeLog b/g10/ChangeLog index abfa6f7af..ce97e1671 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,13 @@ +2010-09-01 Werner Koch + + * keygen.c (gen_elg, gen_dsa, gen_rsa, do_create, common_gen): Add + arg CACHE_NONCE_ADDR. + (generate_subkeypair): Pass NULL for CACHE_NONCE_ADDR. + (do_generate_keypair): Add cache nonce handling. + * import.c (transfer_secret_keys): Support a cache nonce. + * call-agent.c (cache_nonce_status_cb): New. + (agent_genkey, agent_import_key): Add arg CACHE_NONCE_ADDR. + 2010-08-30 Werner Koch * keyid.c (KEYID_STR_SIZE): New diff --git a/g10/call-agent.c b/g10/call-agent.c index 7f98cfba9..2ffa28b69 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1392,6 +1392,32 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno) return err; } + +/* Status callback for agent_import_key and agent_genkey. */ +static gpg_error_t +cache_nonce_status_cb (void *opaque, const char *line) +{ + char **cache_nonce = opaque; + const char *keyword = line; + int keywordlen; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + + if (keywordlen == 11 && !memcmp (keyword, "CACHE_NONCE", keywordlen)) + { + if (cache_nonce) + { + xfree (*cache_nonce); + *cache_nonce = xtrystrdup (line); + } + } + + return 0; +} + /* Handle a KEYPARMS inquiry. Note, we only send the data, @@ -1418,13 +1444,15 @@ inq_genkey_parms (void *opaque, const char *line) 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) +agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, + 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; + char line[ASSUAN_LINELENGTH]; *r_pubkey = NULL; err = start_agent (ctrl, 0); @@ -1440,9 +1468,13 @@ agent_genkey (ctrl_t ctrl, const char *keyparms, gcry_sexp_t *r_pubkey) gk_parm.ctrl = ctrl; gk_parm.ctx = agent_ctx; gk_parm.keyparms = keyparms; - err = assuan_transact (agent_ctx, "GENKEY", + snprintf (line, sizeof line, "GENKEY%s%s", + cache_nonce_addr && *cache_nonce_addr? " ":"", + cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:""); + err = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - inq_genkey_parms, &gk_parm, NULL, NULL); + inq_genkey_parms, &gk_parm, + cache_nonce_status_cb, cache_nonce_addr); if (err) { xfree (get_membuf (&data, &len)); @@ -1775,10 +1807,12 @@ inq_import_key_parms (void *opaque, const char *line) /* Call the agent to import a key into the agent. */ gpg_error_t -agent_import_key (ctrl_t ctrl, const char *desc, const void *key, size_t keylen) +agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, + const void *key, size_t keylen) { gpg_error_t err; struct import_key_parm_s parm; + char line[ASSUAN_LINELENGTH]; err = start_agent (ctrl, 0); if (err) @@ -1786,8 +1820,6 @@ agent_import_key (ctrl_t ctrl, const char *desc, const void *key, size_t keylen) if (desc) { - char line[ASSUAN_LINELENGTH]; - snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc); line[DIM(line)-1] = 0; err = assuan_transact (agent_ctx, line, @@ -1801,8 +1833,12 @@ agent_import_key (ctrl_t ctrl, const char *desc, const void *key, size_t keylen) parm.key = key; parm.keylen = keylen; - err = assuan_transact (agent_ctx, "IMPORT_KEY", - NULL, NULL, inq_import_key_parms, &parm, NULL, NULL); + snprintf (line, sizeof line, "IMPORT_KEY%s%s", + cache_nonce_addr && *cache_nonce_addr? " ":"", + cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:""); + err = assuan_transact (agent_ctx, line, + NULL, NULL, inq_import_key_parms, &parm, + cache_nonce_status_cb, cache_nonce_addr); return err; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 7495b2ac6..c0611ed2b 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -149,7 +149,8 @@ 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, +gpg_error_t agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, + const char *keyparms, gcry_sexp_t *r_pubkey); /* Create a signature. */ @@ -169,6 +170,7 @@ gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport, /* Send a key to the agent. */ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc, + char **cache_nonce_addr, const void *key, size_t keylen); diff --git a/g10/import.c b/g10/import.c index 13773da25..2e0b2fee2 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1105,6 +1105,7 @@ transfer_secret_keys (ctrl_t ctrl, kbnode_t sec_keyblock) gcry_cipher_hd_t cipherhd = NULL; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; + char *cache_nonce = NULL; /* Get the current KEK. */ err = agent_keywrap_key (ctrl, 0, &kek, &keklen); @@ -1266,7 +1267,8 @@ transfer_secret_keys (ctrl_t ctrl, kbnode_t sec_keyblock) xfree (desc); desc = uid; } - err = agent_import_key (ctrl, desc, wrappedkey, wrappedkeylen); + err = agent_import_key (ctrl, desc, &cache_nonce, + wrappedkey, wrappedkeylen); xfree (desc); } if (!err) @@ -1305,6 +1307,7 @@ transfer_secret_keys (ctrl_t ctrl, kbnode_t sec_keyblock) } leave: + xfree (cache_nonce); xfree (wrappedkey); xfree (transferkey); gcry_cipher_close (cipherhd); @@ -1409,7 +1412,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, pubkey_letter (sk->pubkey_algo), keystr_from_sk (sk), datestr_from_sk (sk)); if (uidnode) - print_utf8_buffer (es_stderr, uidnode->pkt->pkt.user_id->name, + print_utf8_buffer (log_get_stream (), uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len); log_printf ("\n"); } diff --git a/g10/keygen.c b/g10/keygen.c index 1be92db06..0f4fb96ef 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1134,14 +1134,15 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, /* Common code for the key generation fucntion gen_xxx. */ static int common_gen (const char *keyparms, int algo, const char *algoelem, - kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey) + kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, + char **cache_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; - err = agent_genkey (NULL, keyparms, &s_key); + err = agent_genkey (NULL, cache_nonce_addr, keyparms, &s_key); if (err) { log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); @@ -1193,7 +1194,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem, */ static int gen_elg (int algo, unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey) + u32 timestamp, u32 expireval, int is_subkey, char **cache_nonce_addr) { int err; char *keyparms; @@ -1223,7 +1224,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root, else { err = common_gen (keyparms, algo, "pgy", - pub_root, timestamp, expireval, is_subkey); + pub_root, timestamp, expireval, is_subkey, + cache_nonce_addr); xfree (keyparms); } @@ -1236,7 +1238,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root, */ static gpg_error_t gen_dsa (unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey) + u32 timestamp, u32 expireval, int is_subkey, char **cache_nonce_addr) { int err; unsigned int qbits; @@ -1305,7 +1307,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, else { err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", - pub_root, timestamp, expireval, is_subkey); + pub_root, timestamp, expireval, is_subkey, + cache_nonce_addr); xfree (keyparms); } @@ -1318,7 +1321,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root, */ static int gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey) + u32 timestamp, u32 expireval, int is_subkey, char **cache_nonce_addr) { int err; char *keyparms; @@ -1349,7 +1352,8 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, else { err = common_gen (keyparms, algo, "ne", - pub_root, timestamp, expireval, is_subkey); + pub_root, timestamp, expireval, is_subkey, + cache_nonce_addr); xfree (keyparms); } @@ -2146,7 +2150,8 @@ do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled) routines based on the requested algorithm. */ static int do_create (int algo, unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expiredate, int is_subkey ) + u32 timestamp, u32 expiredate, int is_subkey, + char **cache_nonce_addr) { gpg_error_t err; @@ -2160,11 +2165,14 @@ do_create (int algo, unsigned int nbits, KBNODE pub_root, "generator a better chance to gain enough entropy.\n") ); if (algo == PUBKEY_ALGO_ELGAMAL_E) - err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey); + err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey, + cache_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) - err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey); + err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, + cache_nonce_addr); else if (algo == PUBKEY_ALGO_RSA) - err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey); + err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, + cache_nonce_addr); else BUG(); @@ -3161,6 +3169,7 @@ do_generate_keypair (struct para_data_s *para, struct revocation_key *revkey; int did_sub = 0; u32 timestamp; + char *cache_nonce = NULL; if (outctrl->dryrun) { @@ -3231,7 +3240,7 @@ do_generate_keypair (struct para_data_s *para, get_parameter_uint( para, pKEYLENGTH ), pub_root, timestamp, - get_parameter_u32( para, pKEYEXPIRE ), 0 ); + get_parameter_u32( para, pKEYEXPIRE ), 0, &cache_nonce); else err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, ×tamp, @@ -3280,7 +3289,8 @@ do_generate_keypair (struct para_data_s *para, get_parameter_uint (para, pSUBKEYLENGTH), pub_root, timestamp, - get_parameter_u32 (para, pSUBKEYEXPIRE), 1 ); + get_parameter_u32 (para, pSUBKEYEXPIRE), 1, + &cache_nonce); /* Get the pointer to the generated public subkey packet. */ if (!err) { @@ -3410,6 +3420,7 @@ do_generate_keypair (struct para_data_s *para, } release_kbnode (pub_root); + xfree (cache_nonce); } @@ -3505,7 +3516,7 @@ generate_subkeypair (KBNODE keyblock) goto leave; } - err = do_create (algo, nbits, keyblock, cur_time, expire, 1); + err = do_create (algo, nbits, keyblock, cur_time, expire, 1, NULL); if (err) goto leave;