diff options
author | Werner Koch <wk@gnupg.org> | 2020-02-13 14:03:59 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2020-02-13 14:07:04 +0100 |
commit | 14ac350f868ca71492c20c7b682d0b55b4893c9c (patch) | |
tree | 207b17268be76f727b0ed4fc8a391fb516a6b02d /g10/call-agent.c | |
parent | card: Take the key creation time from the KEYPAIRINFO (diff) | |
download | gnupg2-14ac350f868ca71492c20c7b682d0b55b4893c9c.tar.xz gnupg2-14ac350f868ca71492c20c7b682d0b55b4893c9c.zip |
gpg: Changes to allow direct key generation from an OpenPGP card.
* g10/call-agent.h (struct keypair_info_s): Add fields keytime and
usage.
* g10/call-agent.c (struct keypairinfo_cb_parm_s): New.
(scd_keypairinfo_status_cb): Rework to store parsed KEYPAIRINFO data.
(agent_scd_keypairinfo): Change accordingly.
(agent_scd_readkey): Add arg ctrl and change callers. Change return
arg from an strlist_t to a keypair_info_t.
(readkey_status_cb): Use KEYPAIRINFO instead of KEY-TIME.
* g10/keygen.c (pSUBKEYCREATIONDATE): New.
(pAUTHKEYCREATIONDATE): New.
(get_parameter_u32): Allow for new parameters.
(do_create_from_keygrip): For card keys use direct scd call which does
not create a stub file.
(ask_algo): Rework to use the new keypair_info_t as return from
agent_scd_keypairinfo.
(parse_key_parameter_part): Likewise. Also get and return the key
creation time using a arg.
(parse_key_parameter_string): New args r_keytime and r_subkeytime.
(parse_algo_usage_expire): New arg r_keytime.
(proc_parameter_file): Ignore the explict pCREATIONDATE for card keys.
(quickgen_set_para): New arg keytime.
(quick_generate_keypair): Get the keytimes and set the pCARDKEY flag.
(generate_keypair): Likewise.
(do_generate_keypair): Implement the cardkey with keytime thingy.
(generate_subkeypair): Use the keytime parameters.
* g10/keygen.c (pAUTHKEYCREATIONDATE): New. Not yet set but may come
handy later.
(get_parameter_u32): Take care of that.
(do_generate_keypair): For cardkeys sign with the current time.
--
Key generation direct from the card used to work for all cards except
the OpenPGP cards. The key generation from card using an OpenPGP card
is special because the fingerprint is stored on the card and we must
make sure that the newly created key has the same fingerprint. This
requires that we take the key creation date as stored on the card into
account.
Along with the recent change in gpg-agent this change also fixes a
problem with existing stub files.
Note that with a key take from a card the self-signature are created
with the current time and not the creation time. This allows to
better distinguish keys created using the same card.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r-- | g10/call-agent.c | 197 |
1 files changed, 145 insertions, 52 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c index 6eb4ad32c..7e56d8d14 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -810,15 +810,23 @@ agent_scd_learn (struct agent_card_info_s *info, int force) +struct keypairinfo_cb_parm_s +{ + keypair_info_t kpinfo; + keypair_info_t *kpinfo_tail; +}; + + /* Callback for the agent_scd_keypairinfo function. */ static gpg_error_t scd_keypairinfo_status_cb (void *opaque, const char *line) { - strlist_t *listaddr = opaque; + struct keypairinfo_cb_parm_s *parm = opaque; + gpg_error_t err = 0; const char *keyword = line; int keywordlen; - strlist_t sl; - char *p; + char *line_buffer = NULL; + keypair_info_t kpi = NULL; for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) ; @@ -827,39 +835,93 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen)) { - sl = append_to_strlist (listaddr, line); - p = sl->d; - /* Make sure that we only have two tokens so that future - * extensions of the format won't change the format expected by - * the caller. */ - while (*p && !spacep (p)) - p++; - if (*p) + /* The format of such a line is: + * KEYPAIRINFO <hexgrip> <keyref> [usage] [keytime] + */ + char *fields[4]; + int nfields; + const char *hexgrp, *keyref, *usage; + time_t atime; + u32 keytime; + + line_buffer = xtrystrdup (line); + if (!line_buffer) { - while (spacep (p)) - p++; - while (*p && !spacep (p)) - p++; - if (*p) + err = gpg_error_from_syserror (); + goto leave; + } + if ((nfields = split_fields (line_buffer, fields, DIM (fields))) < 2) + goto leave; /* not enough args - invalid status line - ignore */ + + hexgrp = fields[0]; + keyref = fields[1]; + if (nfields > 2) + usage = fields[2]; + else + usage = ""; + if (nfields > 3) + { + atime = parse_timestamp (fields[3], NULL); + if (atime == (time_t)(-1)) + atime = 0; + keytime = atime; + } + else + keytime = 0; + + kpi = xtrycalloc (1, sizeof *kpi); + if (!kpi) + { + err = gpg_error_from_syserror (); + goto leave; + } + + if (*hexgrp == 'X' && !hexgrp[1]) + *kpi->keygrip = 0; /* No hexgrip. */ + else if (strlen (hexgrp) == 2*KEYGRIP_LEN) + mem2str (kpi->keygrip, hexgrp, sizeof kpi->keygrip); + else + { + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + + if (!*keyref) + { + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + kpi->idstr = xtrystrdup (keyref); + if (!kpi->idstr) + { + err = gpg_error_from_syserror (); + goto leave; + } + + /* Parse and set the usage. */ + for (; *usage; usage++) + { + switch (*usage) { - *p++ = 0; - while (spacep (p)) - p++; - while (*p && !spacep (p)) - { - switch (*p++) - { - case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break; - case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break; - case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break; - case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break; - } - } + case 's': kpi->usage |= GCRY_PK_USAGE_SIGN; break; + case 'c': kpi->usage |= GCRY_PK_USAGE_CERT; break; + case 'a': kpi->usage |= GCRY_PK_USAGE_AUTH; break; + case 'e': kpi->usage |= GCRY_PK_USAGE_ENCR; break; } } + + kpi->keytime = keytime; + + /* Append to the list. */ + *parm->kpinfo_tail = kpi; + parm->kpinfo_tail = &kpi->next; + kpi = NULL; } - return 0; + leave: + free_keypair_info (kpi); + xfree (line_buffer); + return err; } @@ -869,10 +931,10 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) * bits. If KEYREF is not NULL, only a single string is returned * which matches the given keyref. */ gpg_error_t -agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list) +agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, keypair_info_t *r_list) { gpg_error_t err; - strlist_t list = NULL; + struct keypairinfo_cb_parm_s parm; struct default_inq_parm_s inq_parm; char line[ASSUAN_LINELENGTH]; @@ -883,6 +945,9 @@ agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list) memset (&inq_parm, 0, sizeof inq_parm); inq_parm.ctx = agent_ctx; + parm.kpinfo = NULL; + parm.kpinfo_tail = &parm.kpinfo; + if (keyref) snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref); else @@ -891,16 +956,15 @@ agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list) err = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &inq_parm, - scd_keypairinfo_status_cb, &list); - if (!err && !list) + scd_keypairinfo_status_cb, &parm); + if (!err && !parm.kpinfo) err = gpg_error (GPG_ERR_NO_DATA); + if (err) - { - free_strlist (list); - return err; - } - *r_list = list; - return 0; + free_keypair_info (parm.kpinfo); + else + *r_list = parm.kpinfo; + return err; } @@ -1384,30 +1448,58 @@ agent_scd_readcert (const char *certidstr, static gpg_error_t readkey_status_cb (void *opaque, const char *line) { - u32 *keytimep = opaque; + u32 *keytimep = opaque; + gpg_error_t err = 0; const char *args; + char *line_buffer = NULL; - if ((args = has_leading_keyword (line, "KEY-TIME"))) + /* FIXME: Get that info from the KEYPAIRINFO line. */ + if ((args = has_leading_keyword (line, "KEYPAIRINFO")) + && !*keytimep) { - /* 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); + /* The format of such a line is: + * KEYPAIRINFO <hexgrip> <keyref> [usage] [keytime] + * + * Note that we use only the first valid KEYPAIRINFO line. More + * lines are possible if a second card carries the same key. + */ + char *fields[4]; + int nfields; + time_t atime; + + line_buffer = xtrystrdup (line); + if (!line_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + if ((nfields = split_fields (line_buffer, fields, DIM (fields))) < 4) + goto leave; /* not enough args - ignore */ + + if (nfields > 3) + { + atime = parse_timestamp (fields[3], NULL); + if (atime == (time_t)(-1)) + atime = 0; + *keytimep = atime; + } + else + *keytimep = 0; } - return 0; + leave: + xfree (line_buffer); + return err; } + /* 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. 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, +agent_scd_readkey (ctrl_t ctrl, const char *keyrefstr, gcry_sexp_t *r_result, u32 *r_keytime) { gpg_error_t err; @@ -1425,7 +1517,7 @@ agent_scd_readkey (const char *keyrefstr, *r_result = NULL; if (r_keytime) *r_keytime = 0; - err = start_agent (NULL, 1); + err = start_agent (ctrl, 1); if (err) return err; @@ -1637,6 +1729,7 @@ card_keyinfo_cb (void *opaque, const char *line) } +/* Free a keypair info list. */ void free_keypair_info (keypair_info_t l) { |