diff --git a/g10/call-agent.c b/g10/call-agent.c index 5a877c38f..5faa2d311 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1,6 +1,7 @@ /* call-agent.c - Divert GPG operations to the agent. * Copyright (C) 2001-2003, 2006-2011, 2013 Free Software Foundation, Inc. * Copyright (C) 2013-2015 Werner Koch + * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -1379,11 +1380,35 @@ agent_scd_readcert (const char *certidstr, } +/* Callback for the agent_scd_readkey fucntion. */ +static gpg_error_t +readkey_status_cb (void *opaque, const char *line) +{ + u32 *keytimep = opaque; + const char *args; + + if ((args = has_leading_keyword (line, "KEY-TIME"))) + { + /* Skip the keyref - READKEY returns just one. */ + while (*args && !spacep (args)) + args++; + while (spacep (args)) + args++; + /* We are at the keytime. */ + *keytimep = strtoul (args, NULL, 10); + } + + return 0; +} + /* This is a variant of agent_readkey which sends a READKEY command * directly Scdaemon. On success a new s-expression is stored at - * R_RESULT. */ + * R_RESULT. If R_KEYTIME is not NULL the key cresation time of an + * OpenPGP card is stored there - if that is not known 0 is stored. + * In the latter case it is allowed to pass NULL for R_RESULT. */ gpg_error_t -agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result) +agent_scd_readkey (const char *keyrefstr, + gcry_sexp_t *r_result, u32 *r_keytime) { gpg_error_t err; char line[ASSUAN_LINELENGTH]; @@ -1391,21 +1416,28 @@ agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result) unsigned char *buf; size_t len, buflen; struct default_inq_parm_s dfltparm; + u32 keytime; memset (&dfltparm, 0, sizeof dfltparm); dfltparm.ctx = agent_ctx; - *r_result = NULL; + if (r_result) + *r_result = NULL; + if (r_keytime) + *r_keytime = 0; err = start_agent (NULL, 1); if (err) return err; init_membuf (&data, 1024); - snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr); + snprintf (line, DIM(line), + "SCD READKEY --info%s -- %s", + r_result? "":"-only", keyrefstr); + keytime = 0; err = assuan_transact (agent_ctx, line, put_membuf_cb, &data, default_inq_cb, &dfltparm, - NULL, NULL); + readkey_status_cb, &keytime); if (err) { xfree (get_membuf (&data, &len)); @@ -1415,9 +1447,14 @@ agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result) if (!buf) return gpg_error_from_syserror (); - err = gcry_sexp_new (r_result, buf, buflen, 0); + if (r_result) + err = gcry_sexp_new (r_result, buf, buflen, 0); + else + err = 0; xfree (buf); + if (!err && r_keytime) + *r_keytime = keytime; return err; } @@ -2250,10 +2287,12 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, char **passwd_nonce_addr, -/* 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). */ +/* Call the agent to read the public key part for a given keygrip. + * Values from FROMCARD: + * 0 - Standard + * 1 - The key is read from the current card + * via the agent and a stub file is created. + */ gpg_error_t agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, unsigned char **r_pubkey) @@ -2278,8 +2317,10 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, if (err) return err; - snprintf (line, DIM(line), "READKEY %s%s", fromcard? "--card ":"", - hexkeygrip); + if (fromcard) + snprintf (line, DIM(line), "READKEY --card -- %s", hexkeygrip); + else + snprintf (line, DIM(line), "READKEY -- %s", hexkeygrip); init_membuf (&data, 1024); err = assuan_transact (agent_ctx, line, diff --git a/g10/call-agent.h b/g10/call-agent.h index 9d865b90f..5d0fc5e7e 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -137,7 +137,8 @@ int agent_scd_readcert (const char *certidstr, void **r_buf, size_t *r_buflen); /* Send a READKEY command to the SCdaemon. */ -gpg_error_t agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result); +gpg_error_t agent_scd_readkey (const char *keyrefstr, + gcry_sexp_t *r_result, u32 *r_keytime); /* Change the PIN of an OpenPGP card or reset the retry counter. */ int agent_scd_change_pin (int chvno, const char *serialno); @@ -183,7 +184,7 @@ gpg_error_t agent_genkey (ctrl_t ctrl, const char *passphrase, gcry_sexp_t *r_pubkey); -/* Read a public key. */ +/* Read a public key. FROMCARD may be 0, 1, or 2. */ gpg_error_t agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, unsigned char **r_pubkey); diff --git a/g10/keygen.c b/g10/keygen.c index 06b098822..d4b5fc121 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -94,6 +94,7 @@ enum para_name { pSUBKEYGRIP, pVERSION, /* Desired version of the key packet. */ pSUBVERSION, /* Ditto for the subpacket. */ + pCARDKEY /* The keygrips have been taken from active card (bool). */ }; struct para_data_s { @@ -103,6 +104,7 @@ struct para_data_s { union { u32 expire; u32 creation; + int abool; unsigned int usage; struct revocation_key revkey; char value[1]; @@ -1419,7 +1421,8 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, /* Create a keyblock using the given KEYGRIP. ALGO is the OpenPGP algorithm of that keygrip. */ static int -do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip, +do_create_from_keygrip (ctrl_t ctrl, int algo, + const char *hexkeygrip, int cardkey, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags) { @@ -1448,7 +1451,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo, const char *hexkeygrip, { unsigned char *public; - err = agent_readkey (ctrl, 0, hexkeygrip, &public); + err = agent_readkey (ctrl, cardkey? 1:0, hexkeygrip, &public); if (err) return err; err = gcry_sexp_sscan (&s_key, NULL, @@ -2060,14 +2063,18 @@ check_keygrip (ctrl_t ctrl, const char *hexgrip) * algorithm is stored at R_SUBKEY_ALGO. If R_KEYGRIP is given, the * user has the choice to enter the keygrip of an existing key. That * keygrip is then stored at this address. The caller needs to free - * it. */ + * it. If R_CARDKEY is not NULL and the keygrip has been taken from + * an active card, true is stored there; if R_KEYTIME is not NULL the + * cretion time of that key is then stored there. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, - char **r_keygrip) + char **r_keygrip, int *r_cardkey, u32 *r_keytime) { gpg_error_t err; char *keygrip = NULL; + u32 keytime = 0; char *answer = NULL; + int cardkey = 0; int algo; int dummy_algo; char *p; @@ -2288,7 +2295,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, if (keyref) { keyref++; - if (!agent_scd_readkey (keyref, &s_pkey)) + if (!agent_scd_readkey (keyref, &s_pkey, NULL)) { algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); @@ -2296,7 +2303,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, } /* We use the flags also encode the algo for use * below. We need to tweak the algo in case - * GCRY_PK_ECC is returned becuase pubkey_algo_string + * GCRY_PK_ECC is returned because pubkey_algo_string * is not aware of the OpenPGP algo mapping. * FIXME: This is an ugly hack. */ sl->flags &= 0xff; @@ -2366,9 +2373,22 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, xfree (keygrip); keygrip = xstrdup (sl->d); + cardkey = 1; if ((p = strchr (keygrip, ' '))) *p = 0; algo = (sl->flags >>8); + + err = agent_scd_readkey (keygrip, NULL, &keytime); + if (err) + { + tty_printf (_("error reading the card: %s\n"), + gpg_strerror (err)); + free_strlist (keypairlist); + xfree (keygrip); + keygrip = NULL; + goto ask_again; + } + if (opt.expert) *r_usage = ask_key_flags_with_mask (algo, addmode, (sl->flags & 0xff), @@ -2392,6 +2412,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, xfree(answer); if (r_keygrip) *r_keygrip = keygrip; + if (r_cardkey) + *r_cardkey = cardkey; + if (r_keytime) + *r_keytime = keytime; return algo; } @@ -3431,7 +3455,7 @@ parse_key_parameter_part (ctrl_t ctrl, else continue; /* Not usable for us. */ - if (agent_scd_readkey (keyref, &s_pkey)) + if (agent_scd_readkey (keyref, &s_pkey, NULL)) continue; /* Could not read the key. */ algostr = pubkey_algo_string (s_pkey, &algoid); @@ -3961,6 +3985,14 @@ get_parameter_revkey( struct para_data_s *para, enum para_name key ) return r? &r->u.revkey : NULL; } +static int +get_parameter_bool (struct para_data_s *para, enum para_name key) +{ + struct para_data_s *r = get_parameter (para, key); + return (r && r->u.abool); +} + + static int proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname, struct output_control_s *outctrl, int card ) @@ -4757,8 +4789,11 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, { int subkey_algo; char *key_from_hexgrip = NULL; + int cardkey; + u32 keytime; - algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip); + algo = ask_algo (ctrl, 0, &subkey_algo, &use, + &key_from_hexgrip, &cardkey, &keytime); if (key_from_hexgrip) { r = xmalloc_clear( sizeof *r + 20 ); @@ -4785,6 +4820,21 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname, r->next = para; para = r; + r = xmalloc_clear (sizeof *r); + r->key = pCARDKEY; + r->u.abool = cardkey; + r->next = para; + para = r; + + if (cardkey) + { + r = xmalloc_clear (sizeof *r); + r->key = pKEYCREATIONDATE; + r->u.creation = keytime; + r->next = para; + para = r; + } + xfree (key_from_hexgrip); } else @@ -5169,6 +5219,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, int algo; u32 expire; const char *key_from_hexgrip = NULL; + int cardkey; unsigned int keygen_flags; if (outctrl->dryrun) @@ -5238,13 +5289,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); + cardkey = get_parameter_bool (para, pCARDKEY); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) - err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, + err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, pub_root, timestamp, expire, 0, keygen_flags); else if (!card) err = do_create (algo, @@ -5318,7 +5370,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) - err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip, + err = do_create_from_keygrip (ctrl, subkey_algo, + key_from_hexgrip, cardkey, pub_root, timestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, keygen_flags); @@ -5596,6 +5649,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *curve = NULL; u32 cur_time; char *key_from_hexgrip = NULL; + int cardkey = 0; char *hexgrip = NULL; char *serialno = NULL; char *cache_nonce = NULL; @@ -5660,7 +5714,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, if (interactive) { - algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip); + algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, NULL); log_assert (algo); if (key_from_hexgrip) @@ -5713,7 +5767,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, /* Start creation. */ if (key_from_hexgrip) { - err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, + err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, keyblock, cur_time, expire, 1, keygen_flags); }