summaryrefslogtreecommitdiffstats
path: root/g10/call-agent.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-02-13 14:03:59 +0100
committerWerner Koch <wk@gnupg.org>2020-02-13 14:07:04 +0100
commit14ac350f868ca71492c20c7b682d0b55b4893c9c (patch)
tree207b17268be76f727b0ed4fc8a391fb516a6b02d /g10/call-agent.c
parentcard: Take the key creation time from the KEYPAIRINFO (diff)
downloadgnupg2-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.c197
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)
{