mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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 <wk@gnupg.org>
This commit is contained in:
parent
77ea916533
commit
9c719c9c1f
@ -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;
|
||||
|
||||
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 ();
|
||||
|
||||
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,
|
||||
|
@ -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);
|
||||
|
||||
|
78
g10/keygen.c
78
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user