From 9c719c9c1ff34cc06a0fef2bfe29cfd7182753eb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 11 Feb 2020 20:51:33 +0100 Subject: gpg: Improve key creation direct from the card. * g10/call-agent.c (readkey_status_cb): New. (agent_scd_readkey): Add new arg r_keytime and allow NULL for r_result. Change all callers. (agent_readkey): Minor code reformatting. * g10/keygen.c (pCARDKEY): New. (struct para_data_s): Add u.bool. (get_parameter_bool): New. (do_create_from_keygrip): Add arg cardkey and make use of it. (ask_algo): Add args r_cardkey and r_keytime. Read the keytime of the selected card key and return it. (generate_keypair): Store CARDKEY and KEYTIME. (do_generate_keypair): Pass CARDKEY to do_create_from_keygrip. (generate_subkeypair): Ditto. -- This allows to first create keys on the card (e.g. using gpg-card) even without having any public key for OpenPGP. Then the key generation option 14 (cardkey) can be used to create a primary OpenPGP key from the key on the card. There are still a couple of problems related to the agent which creates the stub key and may run into problems if creating a second key from the card. This will be fixed in a future patch. Signed-off-by: Werner Koch --- g10/call-agent.c | 65 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 12 deletions(-) (limited to 'g10/call-agent.c') 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, -- cgit v1.2.3