1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-08 23:37:47 +02:00

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>
This commit is contained in:
Werner Koch 2020-02-13 14:03:59 +01:00
parent e63f8bee40
commit 14ac350f86
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 344 additions and 183 deletions

View File

@ -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. */ /* Callback for the agent_scd_keypairinfo function. */
static gpg_error_t static gpg_error_t
scd_keypairinfo_status_cb (void *opaque, const char *line) 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; const char *keyword = line;
int keywordlen; int keywordlen;
strlist_t sl; char *line_buffer = NULL;
char *p; keypair_info_t kpi = NULL;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) 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)) if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
{ {
sl = append_to_strlist (listaddr, line); /* The format of such a line is:
p = sl->d; * KEYPAIRINFO <hexgrip> <keyref> [usage] [keytime]
/* Make sure that we only have two tokens so that future */
* extensions of the format won't change the format expected by char *fields[4];
* the caller. */ int nfields;
while (*p && !spacep (p)) const char *hexgrp, *keyref, *usage;
p++; time_t atime;
if (*p) u32 keytime;
line_buffer = xtrystrdup (line);
if (!line_buffer)
{ {
while (spacep (p)) err = gpg_error_from_syserror ();
p++; goto leave;
while (*p && !spacep (p)) }
p++; if ((nfields = split_fields (line_buffer, fields, DIM (fields))) < 2)
if (*p) 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; case 's': kpi->usage |= GCRY_PK_USAGE_SIGN; break;
while (spacep (p)) case 'c': kpi->usage |= GCRY_PK_USAGE_CERT; break;
p++; case 'a': kpi->usage |= GCRY_PK_USAGE_AUTH; break;
while (*p && !spacep (p)) case 'e': kpi->usage |= GCRY_PK_USAGE_ENCR; break;
{
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;
}
}
} }
} }
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 * bits. If KEYREF is not NULL, only a single string is returned
* which matches the given keyref. */ * which matches the given keyref. */
gpg_error_t 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; gpg_error_t err;
strlist_t list = NULL; struct keypairinfo_cb_parm_s parm;
struct default_inq_parm_s inq_parm; struct default_inq_parm_s inq_parm;
char line[ASSUAN_LINELENGTH]; 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); memset (&inq_parm, 0, sizeof inq_parm);
inq_parm.ctx = agent_ctx; inq_parm.ctx = agent_ctx;
parm.kpinfo = NULL;
parm.kpinfo_tail = &parm.kpinfo;
if (keyref) if (keyref)
snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref); snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref);
else else
@ -891,16 +956,15 @@ agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list)
err = assuan_transact (agent_ctx, line, err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL,
default_inq_cb, &inq_parm, default_inq_cb, &inq_parm,
scd_keypairinfo_status_cb, &list); scd_keypairinfo_status_cb, &parm);
if (!err && !list) if (!err && !parm.kpinfo)
err = gpg_error (GPG_ERR_NO_DATA); err = gpg_error (GPG_ERR_NO_DATA);
if (err) if (err)
{ free_keypair_info (parm.kpinfo);
free_strlist (list); else
return err; *r_list = parm.kpinfo;
} return err;
*r_list = list;
return 0;
} }
@ -1384,30 +1448,58 @@ agent_scd_readcert (const char *certidstr,
static gpg_error_t static gpg_error_t
readkey_status_cb (void *opaque, const char *line) readkey_status_cb (void *opaque, const char *line)
{ {
u32 *keytimep = opaque; u32 *keytimep = opaque;
gpg_error_t err = 0;
const char *args; 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. */ /* The format of such a line is:
while (*args && !spacep (args)) * KEYPAIRINFO <hexgrip> <keyref> [usage] [keytime]
args++; *
while (spacep (args)) * Note that we use only the first valid KEYPAIRINFO line. More
args++; * lines are possible if a second card carries the same key.
/* We are at the keytime. */ */
*keytimep = strtoul (args, NULL, 10); 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 /* This is a variant of agent_readkey which sends a READKEY command
* directly Scdaemon. On success a new s-expression is stored at * 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 * 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. * 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. */ * In the latter case it is allowed to pass NULL for R_RESULT. */
gpg_error_t 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) gcry_sexp_t *r_result, u32 *r_keytime)
{ {
gpg_error_t err; gpg_error_t err;
@ -1425,7 +1517,7 @@ agent_scd_readkey (const char *keyrefstr,
*r_result = NULL; *r_result = NULL;
if (r_keytime) if (r_keytime)
*r_keytime = 0; *r_keytime = 0;
err = start_agent (NULL, 1); err = start_agent (ctrl, 1);
if (err) if (err)
return err; return err;
@ -1637,6 +1729,7 @@ card_keyinfo_cb (void *opaque, const char *line)
} }
/* Free a keypair info list. */
void void
free_keypair_info (keypair_info_t l) free_keypair_info (keypair_info_t l)
{ {

View File

@ -82,9 +82,12 @@ struct agent_card_info_s
struct keypair_info_s struct keypair_info_s
{ {
struct keypair_info_s *next; struct keypair_info_s *next;
char keygrip[41]; char keygrip[2 * KEYGRIP_LEN + 1]; /* Stored in hex. */
char *serialno; char *serialno; /* NULL or the malloced serialno. */
char *idstr; /* (aka keyref) */ char *idstr; /* Malloced keyref (e.g. "OPENPGP.1") */
unsigned int usage; /* Key usage flags. */
u32 keytime; /* Key creation time from the card's DO. */
int algo; /* Helper to store the pubkey algo. */
}; };
typedef struct keypair_info_s *keypair_info_t; typedef struct keypair_info_s *keypair_info_t;
@ -96,7 +99,7 @@ int agent_scd_learn (struct agent_card_info_s *info, int force);
/* Get the keypariinfo directly from scdaemon. */ /* Get the keypariinfo directly from scdaemon. */
gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref,
strlist_t *r_list); keypair_info_t *r_list);
/* Return list of cards. */ /* Return list of cards. */
int agent_scd_cardlist (strlist_t *result); int agent_scd_cardlist (strlist_t *result);
@ -140,7 +143,7 @@ int agent_scd_readcert (const char *certidstr,
void **r_buf, size_t *r_buflen); void **r_buf, size_t *r_buflen);
/* Send a READKEY command to the SCdaemon. */ /* Send a READKEY command to the SCdaemon. */
gpg_error_t agent_scd_readkey (const char *keyrefstr, gpg_error_t agent_scd_readkey (ctrl_t ctrl, const char *keyrefstr,
gcry_sexp_t *r_result, u32 *r_keytime); gcry_sexp_t *r_result, u32 *r_keytime);
/* Change the PIN of an OpenPGP card or reset the retry counter. */ /* Change the PIN of an OpenPGP card or reset the retry counter. */

View File

@ -1,6 +1,7 @@
/* keygen.c - Generate a key pair /* keygen.c - Generate a key pair
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch * Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch
* Copyright (C) 2020 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -84,7 +85,9 @@ enum para_name {
pKEYCREATIONDATE, /* Same in seconds since epoch. */ pKEYCREATIONDATE, /* Same in seconds since epoch. */
pEXPIREDATE, pEXPIREDATE,
pKEYEXPIRE, /* in n seconds */ pKEYEXPIRE, /* in n seconds */
pSUBKEYCREATIONDATE,
pSUBKEYEXPIRE, /* in n seconds */ pSUBKEYEXPIRE, /* in n seconds */
pAUTHKEYCREATIONDATE, /* Not yet used. */
pPASSPHRASE, pPASSPHRASE,
pSERIALNO, pSERIALNO,
pCARDBACKUPKEY, pCARDBACKUPKEY,
@ -154,7 +157,7 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
int *r_algo, unsigned int *r_usage, int *r_algo, unsigned int *r_usage,
u32 *r_expire, unsigned int *r_nbits, u32 *r_expire, unsigned int *r_nbits,
const char **r_curve, int *r_version, const char **r_curve, int *r_version,
char **r_keygrip); char **r_keygrip, u32 *r_keytime);
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
struct output_control_s *outctrl, int card ); struct output_control_s *outctrl, int card );
static int write_keyblock (iobuf_t out, kbnode_t node); static int write_keyblock (iobuf_t out, kbnode_t node);
@ -1419,7 +1422,8 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
/* Create a keyblock using the given KEYGRIP. ALGO is the OpenPGP /* Create a keyblock using the given KEYGRIP. ALGO is the OpenPGP
algorithm of that keygrip. */ * algorithm of that keygrip. If CARDKEY is true the key is expected
* to already live on the active card. */
static int static int
do_create_from_keygrip (ctrl_t ctrl, int algo, do_create_from_keygrip (ctrl_t ctrl, int algo,
const char *hexkeygrip, int cardkey, const char *hexkeygrip, int cardkey,
@ -1448,18 +1452,25 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
/* Ask the agent for the public key matching HEXKEYGRIP. */ /* Ask the agent for the public key matching HEXKEYGRIP. */
{ if (cardkey)
unsigned char *public; {
err = agent_scd_readkey (ctrl, hexkeygrip, &s_key, NULL);
if (err)
return err;
}
else
{
unsigned char *public;
err = agent_readkey (ctrl, cardkey? 1:0, hexkeygrip, &public); err = agent_readkey (ctrl, 0, hexkeygrip, &public);
if (err) if (err)
return err; return err;
err = gcry_sexp_sscan (&s_key, NULL, err = gcry_sexp_sscan (&s_key, NULL, public,
public, gcry_sexp_canon_len (public, 0, NULL, NULL)); gcry_sexp_canon_len (public, 0, NULL, NULL));
xfree (public); xfree (public);
if (err) if (err)
return err; return err;
} }
/* Build a public key packet. */ /* Build a public key packet. */
pk = xtrycalloc (1, sizeof *pk); pk = xtrycalloc (1, sizeof *pk);
@ -2077,7 +2088,6 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
int cardkey = 0; int cardkey = 0;
int algo; int algo;
int dummy_algo; int dummy_algo;
char *p;
if (!r_subkey_algo) if (!r_subkey_algo)
r_subkey_algo = &dummy_algo; r_subkey_algo = &dummy_algo;
@ -2253,7 +2263,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip) else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip)
{ {
char *serialno; char *serialno;
strlist_t keypairlist, sl; keypair_info_t keypairlist, kpi;
int count, selection; int count, selection;
err = agent_scd_serialno (&serialno, NULL); err = agent_scd_serialno (&serialno, NULL);
@ -2283,62 +2293,58 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
agent_scd_getattr_one ("$SIGNKEYID", &signkeyref); agent_scd_getattr_one ("$SIGNKEYID", &signkeyref);
tty_printf (_("Available keys:\n")); tty_printf (_("Available keys:\n"));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++) for (count=1, kpi=keypairlist; kpi; kpi = kpi->next, count++)
{ {
gcry_sexp_t s_pkey; gcry_sexp_t s_pkey;
char *algostr = NULL; char *algostr = NULL;
enum gcry_pk_algos algoid = 0; enum gcry_pk_algos algoid = 0;
const char *keyref; const char *keyref = kpi->idstr;
int any = 0; int any = 0;
keyref = strchr (sl->d, ' '); if (keyref
if (keyref) && !agent_scd_readkey (ctrl, keyref, &s_pkey, NULL))
{ {
keyref++; algostr = pubkey_algo_string (s_pkey, &algoid);
if (!agent_scd_readkey (keyref, &s_pkey, NULL)) gcry_sexp_release (s_pkey);
{
algostr = pubkey_algo_string (s_pkey, &algoid);
gcry_sexp_release (s_pkey);
}
} }
/* We use the flags also encode the algo for use
* below. We need to tweak the algo in case /* We need to tweak the algo in case
* GCRY_PK_ECC is returned because pubkey_algo_string * GCRY_PK_ECC is returned because pubkey_algo_string
* is not aware of the OpenPGP algo mapping. * is not aware of the OpenPGP algo mapping.
* FIXME: This is an ugly hack. */ * FIXME: This is an ugly hack. */
sl->flags &= 0xff;
if (algoid == GCRY_PK_ECC if (algoid == GCRY_PK_ECC
&& algostr && !strncmp (algostr, "nistp", 5) && algostr && !strncmp (algostr, "nistp", 5)
&& !(sl->flags & GCRY_PK_USAGE_ENCR)) && !(kpi->usage & GCRY_PK_USAGE_ENCR))
sl->flags |= (PUBKEY_ALGO_ECDSA << 8); kpi->algo = PUBKEY_ALGO_ECDSA;
else if (algoid == GCRY_PK_ECC else if (algoid == GCRY_PK_ECC
&& algostr && !strcmp (algostr, "ed25519") && algostr && !strcmp (algostr, "ed25519")
&& !(sl->flags & GCRY_PK_USAGE_ENCR)) && !(kpi->usage & GCRY_PK_USAGE_ENCR))
sl->flags = (PUBKEY_ALGO_EDDSA << 8); kpi->algo = PUBKEY_ALGO_EDDSA;
else else
sl->flags |= (map_gcry_pk_to_openpgp (algoid) << 8); kpi->algo = map_gcry_pk_to_openpgp (algoid);
tty_printf (" (%d) %s %s", count, sl->d, algostr); tty_printf (" (%d) %s %s %s",
if ((sl->flags & GCRY_PK_USAGE_CERT)) count, kpi->keygrip, keyref, algostr);
if ((kpi->usage & GCRY_PK_USAGE_CERT))
{ {
tty_printf ("%scert", any?",":" ("); tty_printf ("%scert", any?",":" (");
any = 1; any = 1;
} }
if ((sl->flags & GCRY_PK_USAGE_SIGN)) if ((kpi->usage & GCRY_PK_USAGE_SIGN))
{ {
tty_printf ("%ssign%s", any?",":" (", tty_printf ("%ssign%s", any?",":" (",
(signkeyref && keyref (signkeyref && keyref
&& !strcmp (signkeyref, keyref))? "*":""); && !strcmp (signkeyref, keyref))? "*":"");
any = 1; any = 1;
} }
if ((sl->flags & GCRY_PK_USAGE_AUTH)) if ((kpi->usage & GCRY_PK_USAGE_AUTH))
{ {
tty_printf ("%sauth%s", any?",":" (", tty_printf ("%sauth%s", any?",":" (",
(authkeyref && keyref (authkeyref && keyref
&& !strcmp (authkeyref, keyref))? "*":""); && !strcmp (authkeyref, keyref))? "*":"");
any = 1; any = 1;
} }
if ((sl->flags & GCRY_PK_USAGE_ENCR)) if ((kpi->usage & GCRY_PK_USAGE_ENCR))
{ {
tty_printf ("%sencr%s", any?",":" (", tty_printf ("%sencr%s", any?",":" (",
(encrkeyref && keyref (encrkeyref && keyref
@ -2357,49 +2363,36 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
xfree (authkeyref); xfree (authkeyref);
xfree (encrkeyref); xfree (encrkeyref);
xfree (signkeyref); xfree (signkeyref);
} }
while (!(selection > 0 && selection < count)); while (!(selection > 0 && selection < count));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++) for (count=1,kpi=keypairlist; kpi; kpi = kpi->next, count++)
if (count == selection) if (count == selection)
break; break;
if (!sl) if (!kpi)
{ {
/* Just in case COUNT is zero (no keys). */ /* Just in case COUNT is zero (no keys). */
free_strlist (keypairlist); free_keypair_info (keypairlist);
goto ask_again; goto ask_again;
} }
xfree (keygrip); xfree (keygrip);
keygrip = xstrdup (sl->d); keygrip = xstrdup (kpi->keygrip);
cardkey = 1; cardkey = 1;
if ((p = strchr (keygrip, ' '))) algo = kpi->algo;
*p = 0; keytime = kpi->keytime;
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;
}
/* In expert mode allow to change the usage flags. */
if (opt.expert) if (opt.expert)
*r_usage = ask_key_flags_with_mask (algo, addmode, *r_usage = ask_key_flags_with_mask (algo, addmode,
(sl->flags & 0xff), kpi->usage, kpi->usage);
(sl->flags & 0xff));
else else
{ {
*r_usage = (sl->flags & 0xff); *r_usage = kpi->usage;
if (addmode) if (addmode)
*r_usage &= ~GCRY_PK_USAGE_CERT; *r_usage &= ~GCRY_PK_USAGE_CERT;
} }
free_strlist (keypairlist); free_keypair_info (keypairlist);
break; break;
} }
else else
@ -3244,7 +3237,7 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
} }
/* Helper for parse_key_parameter_string for one part of the /* Helper for parse_key_parameter_part_parameter_string for one part of the
* specification string; i.e. ALGO/FLAGS. If STRING is NULL or empty * specification string; i.e. ALGO/FLAGS. If STRING is NULL or empty
* success is returned. On error an error code is returned. Note * success is returned. On error an error code is returned. Note
* that STRING may be modified by this function. NULL may be passed * that STRING may be modified by this function. NULL may be passed
@ -3253,14 +3246,16 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
* this is useful if for example the default algorithm is used for a * this is useful if for example the default algorithm is used for a
* subkey. If R_KEYVERSION is not NULL it will receive the version of * subkey. If R_KEYVERSION is not NULL it will receive the version of
* the key; this is currently 4 but can be changed with the flag "v5" * the key; this is currently 4 but can be changed with the flag "v5"
* to create a v5 key. */ * to create a v5 key. If R_KEYTIME is not NULL and the key has been
* taken fron active OpenPGP card, its creation time is stored
* there. */
static gpg_error_t static gpg_error_t
parse_key_parameter_part (ctrl_t ctrl, parse_key_parameter_part (ctrl_t ctrl,
char *string, int for_subkey, int clear_cert, char *string, int for_subkey, int clear_cert,
int *r_algo, unsigned int *r_size, int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse, unsigned int *r_keyuse,
char const **r_curve, int *r_keyversion, char const **r_curve, int *r_keyversion,
char **r_keygrip) char **r_keygrip, u32 *r_keytime)
{ {
gpg_error_t err; gpg_error_t err;
char *flags; char *flags;
@ -3275,6 +3270,7 @@ parse_key_parameter_part (ctrl_t ctrl,
const char *s; const char *s;
int from_card = 0; int from_card = 0;
char *keygrip = NULL; char *keygrip = NULL;
u32 keytime = 0;
if (!string || !*string) if (!string || !*string)
return 0; /* Success. */ return 0; /* Success. */
@ -3397,7 +3393,7 @@ parse_key_parameter_part (ctrl_t ctrl,
* to read the algo from the current card. */ * to read the algo from the current card. */
if (from_card) if (from_card)
{ {
strlist_t keypairlist, sl; keypair_info_t keypairlist, kpi;
char *reqkeyref; char *reqkeyref;
if (!keyuse) if (!keyuse)
@ -3429,70 +3425,66 @@ parse_key_parameter_part (ctrl_t ctrl,
? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref); ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref);
algo = 0; /* Should already be the case. */ algo = 0; /* Should already be the case. */
for (sl=keypairlist; sl && !algo; sl = sl->next) for (kpi=keypairlist; kpi && !algo; kpi = kpi->next)
{ {
gcry_sexp_t s_pkey; gcry_sexp_t s_pkey;
char *algostr = NULL; char *algostr = NULL;
enum gcry_pk_algos algoid = 0; enum gcry_pk_algos algoid = 0;
const char *keyref; const char *keyref = kpi->idstr;
if (!reqkeyref) if (!reqkeyref)
continue; /* Card does not provide the info (skip all). */ continue; /* Card does not provide the info (skip all). */
keyref = strchr (sl->d, ' ');
if (!keyref) if (!keyref)
continue; /* Ooops. */ continue; /* Ooops. */
keyref++;
if (strcmp (reqkeyref, keyref)) if (strcmp (reqkeyref, keyref))
continue; /* This is not the requested keyref. */ continue; /* This is not the requested keyref. */
if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT))
&& (sl->flags & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT))) && (kpi->usage & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT)))
; /* Okay */ ; /* Okay */
else if ((keyuse & PUBKEY_USAGE_ENC) else if ((keyuse & PUBKEY_USAGE_ENC)
&& (sl->flags & GCRY_PK_USAGE_ENCR)) && (kpi->usage & GCRY_PK_USAGE_ENCR))
; /* Okay */ ; /* Okay */
else else
continue; /* Not usable for us. */ continue; /* Not usable for us. */
if (agent_scd_readkey (keyref, &s_pkey, NULL)) if (agent_scd_readkey (ctrl, keyref, &s_pkey, NULL))
continue; /* Could not read the key. */ continue; /* Could not read the key. */
algostr = pubkey_algo_string (s_pkey, &algoid); algostr = pubkey_algo_string (s_pkey, &algoid);
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
/* Map to OpenPGP algo number. /* Map to OpenPGP algo number.
* We need to tweak the algo in case GCRY_PK_ECC is returned * We need to tweak the algo in case GCRY_PK_ECC is returned
* because pubkey_algo_string is not aware of the OpenPGP * because pubkey_algo_string is not aware of the OpenPGP
* algo mapping. FIXME: This is an ugly hack. */ * algo mapping. FIXME: This is an ugly hack. */
if (algoid == GCRY_PK_ECC if (algoid == GCRY_PK_ECC
&& algostr && !strncmp (algostr, "nistp", 5) && algostr && !strncmp (algostr, "nistp", 5)
&& !(sl->flags & GCRY_PK_USAGE_ENCR)) && !(kpi->usage & GCRY_PK_USAGE_ENCR))
algo = PUBKEY_ALGO_ECDSA; algo = PUBKEY_ALGO_ECDSA;
else if (algoid == GCRY_PK_ECC else if (algoid == GCRY_PK_ECC
&& algostr && !strcmp (algostr, "ed25519") && algostr && !strcmp (algostr, "ed25519")
&& !(sl->flags & GCRY_PK_USAGE_ENCR)) && !(kpi->usage & GCRY_PK_USAGE_ENCR))
algo = PUBKEY_ALGO_EDDSA; algo = PUBKEY_ALGO_EDDSA;
else else
algo = map_gcry_pk_to_openpgp (algoid); algo = map_gcry_pk_to_openpgp (algoid);
xfree (algostr); xfree (algostr);
xfree (keygrip); xfree (keygrip);
keygrip = xtrystrdup (sl->d); keygrip = xtrystrdup (kpi->keygrip);
if (!keygrip) if (!keygrip)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
xfree (reqkeyref); xfree (reqkeyref);
free_strlist (keypairlist); free_keypair_info (keypairlist);
return err; return err;
} }
if ((endp = strchr (keygrip, ' '))) keytime = kpi->keytime;
*endp = 0;
} }
xfree (reqkeyref); xfree (reqkeyref);
free_strlist (keypairlist); free_keypair_info (keypairlist);
if (!algo || !keygrip) if (!algo || !keygrip)
{ {
err = gpg_error (GPG_ERR_PUBKEY_ALGO); err = gpg_error (GPG_ERR_PUBKEY_ALGO);
@ -3577,6 +3569,9 @@ parse_key_parameter_part (ctrl_t ctrl,
else else
xfree (keygrip); xfree (keygrip);
if (r_keytime)
*r_keytime = keytime;
return 0; return 0;
} }
@ -3633,11 +3628,13 @@ parse_key_parameter_string (ctrl_t ctrl,
char const **r_curve, char const **r_curve,
int *r_version, int *r_version,
char **r_keygrip, char **r_keygrip,
u32 *r_keytime,
int *r_subalgo, unsigned int *r_subsize, int *r_subalgo, unsigned int *r_subsize,
unsigned int *r_subkeyuse, unsigned int *r_subkeyuse,
char const **r_subcurve, char const **r_subcurve,
int *r_subversion, int *r_subversion,
char **r_subkeygrip) char **r_subkeygrip,
u32 *r_subkeytime)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
char *primary, *secondary; char *primary, *secondary;
@ -3654,6 +3651,8 @@ parse_key_parameter_string (ctrl_t ctrl,
*r_version = 4; *r_version = 4;
if (r_keygrip) if (r_keygrip)
*r_keygrip = NULL; *r_keygrip = NULL;
if (r_keytime)
*r_keytime = 0;
if (r_subalgo) if (r_subalgo)
*r_subalgo = 0; *r_subalgo = 0;
if (r_subsize) if (r_subsize)
@ -3666,6 +3665,8 @@ parse_key_parameter_string (ctrl_t ctrl,
*r_subversion = 4; *r_subversion = 4;
if (r_subkeygrip) if (r_subkeygrip)
*r_subkeygrip = NULL; *r_subkeygrip = NULL;
if (r_subkeytime)
*r_subkeytime = 0;
if (!string || !*string if (!string || !*string
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) || !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
@ -3684,12 +3685,13 @@ parse_key_parameter_string (ctrl_t ctrl,
{ {
err = parse_key_parameter_part (ctrl, primary, err = parse_key_parameter_part (ctrl, primary,
0, 0, r_algo, r_size, 0, 0, r_algo, r_size,
r_keyuse, r_curve, r_version, r_keygrip); r_keyuse, r_curve, r_version,
r_keygrip, r_keytime);
if (!err && part == -1) if (!err && part == -1)
err = parse_key_parameter_part (ctrl, secondary, err = parse_key_parameter_part (ctrl, secondary,
1, 0, r_subalgo, r_subsize, 1, 0, r_subalgo, r_subsize,
r_subkeyuse, r_subcurve, r_subversion, r_subkeyuse, r_subcurve, r_subversion,
r_subkeygrip); r_subkeygrip, r_subkeytime);
} }
else if (part == 1) else if (part == 1)
{ {
@ -3704,18 +3706,18 @@ parse_key_parameter_string (ctrl_t ctrl,
err = parse_key_parameter_part (ctrl, secondary, err = parse_key_parameter_part (ctrl, secondary,
1, 0, 1, 0,
r_algo, r_size, r_keyuse, r_curve, r_algo, r_size, r_keyuse, r_curve,
r_version, r_keygrip); r_version, r_keygrip, r_keytime);
if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
err = parse_key_parameter_part (ctrl, primary, err = parse_key_parameter_part (ctrl, primary,
1, 1 /*(clear cert)*/, 1, 1 /*(clear cert)*/,
r_algo, r_size, r_keyuse, r_curve, r_algo, r_size, r_keyuse, r_curve,
r_version, r_keygrip); r_version, r_keygrip, r_keytime);
} }
else else
err = parse_key_parameter_part (ctrl, primary, err = parse_key_parameter_part (ctrl, primary,
1, 0, 1, 0,
r_algo, r_size, r_keyuse, r_curve, r_algo, r_size, r_keyuse, r_curve,
r_version, r_keygrip); r_version, r_keygrip, r_keytime);
} }
xfree (primary); xfree (primary);
@ -3803,8 +3805,8 @@ get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key,
* compatibility with the batch key generation. It would be * compatibility with the batch key generation. It would be
* better to make full use of parse_key_parameter_string. */ * better to make full use of parse_key_parameter_string. */
parse_key_parameter_string (ctrl, NULL, 0, 0, parse_key_parameter_string (ctrl, NULL, 0, 0,
&i, NULL, NULL, NULL, NULL, NULL, &i, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (r_default) if (r_default)
*r_default = 1; *r_default = 1;
} }
@ -3962,7 +3964,8 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
if( !r ) if( !r )
return 0; return 0;
if( r->key == pKEYCREATIONDATE ) if (r->key == pKEYCREATIONDATE || r->key == pSUBKEYCREATIONDATE
|| r->key == pAUTHKEYCREATIONDATE)
return r->u.creation; return r->u.creation;
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE ) if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
return r->u.expire; return r->u.expire;
@ -4151,9 +4154,13 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
return -1; return -1;
/* Make KEYCREATIONDATE from Creation-Date. */ /* Make KEYCREATIONDATE from Creation-Date. We ignore this if the
* key has been taken from a card and a keycreationtime has already
* been set. This is so that we don't generate a key with a
* fingerprint different from the one stored on the OpenPGP card. */
r = get_parameter (para, pCREATIONDATE); r = get_parameter (para, pCREATIONDATE);
if (r && *r->u.value) if (r && *r->u.value && !(get_parameter_bool (para, pCARDKEY)
&& get_parameter_u32 (para, pKEYCREATIONDATE)))
{ {
u32 seconds; u32 seconds;
@ -4419,7 +4426,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
static struct para_data_s * static struct para_data_s *
quickgen_set_para (struct para_data_s *para, int for_subkey, quickgen_set_para (struct para_data_s *para, int for_subkey,
int algo, int nbits, const char *curve, unsigned int use, int algo, int nbits, const char *curve, unsigned int use,
int version, const char *keygrip) int version, const char *keygrip, u32 keytime)
{ {
struct para_data_s *r; struct para_data_s *r;
@ -4475,6 +4482,16 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
para = r; para = r;
} }
if (keytime)
{
r = xmalloc_clear (sizeof *r);
r->key = for_subkey? pSUBKEYCREATIONDATE : pKEYCREATIONDATE;
r->u.creation = keytime;
r->next = para;
para = r;
}
return para; return para;
} }
@ -4491,6 +4508,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
struct para_data_s *r; struct para_data_s *r;
struct output_control_s outctrl; struct output_control_s outctrl;
int use_tty; int use_tty;
u32 keytime = 0;
memset (&outctrl, 0, sizeof outctrl); memset (&outctrl, 0, sizeof outctrl);
@ -4573,12 +4591,14 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
unsigned int keyuse, subkeyuse; unsigned int keyuse, subkeyuse;
const char *curve, *subcurve; const char *curve, *subcurve;
char *keygrip, *subkeygrip; char *keygrip, *subkeygrip;
u32 subkeytime;
err = parse_key_parameter_string (ctrl, algostr, -1, 0, err = parse_key_parameter_string (ctrl, algostr, -1, 0,
&algo, &size, &keyuse, &curve, &version, &algo, &size, &keyuse, &curve, &version,
&keygrip, &keygrip, &keytime,
&subalgo, &subsize, &subkeyuse, &subalgo, &subsize, &subkeyuse,
&subcurve, &subversion, &subkeygrip); &subcurve, &subversion,
&subkeygrip, &subkeytime);
if (err) if (err)
{ {
log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
@ -4586,11 +4606,11 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
} }
para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version,
keygrip); keygrip, keytime);
if (subalgo) if (subalgo)
para = quickgen_set_para (para, 1, para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse, subalgo, subsize, subcurve, subkeyuse,
subversion, subkeygrip); subversion, subkeygrip, subkeytime);
if (*expirestr) if (*expirestr)
{ {
u32 expire; u32 expire;
@ -4624,7 +4644,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve, &algo, &use, &expire, &nbits, &curve,
&version, &keygrip); &version, &keygrip, &keytime);
if (err) if (err)
{ {
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
@ -4632,7 +4652,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
} }
para = quickgen_set_para (para, 0, algo, nbits, curve, use, version, para = quickgen_set_para (para, 0, algo, nbits, curve, use, version,
keygrip); keygrip, keytime);
r = xmalloc_clear (sizeof *r + 20); r = xmalloc_clear (sizeof *r + 20);
r->key = pKEYEXPIRE; r->key = pKEYEXPIRE;
r->u.expire = expire; r->u.expire = expire;
@ -4657,6 +4677,18 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
para = r; para = r;
} }
/* If KEYTIME is set we know that the key has been taken from the
* card. Store that flag in the parameters. */
if (keytime)
{
r = xmalloc_clear (sizeof *r);
r->key = pCARDKEY;
r->u.abool = 1;
r->next = para;
para = r;
}
proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0); proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0);
leave: leave:
@ -4971,6 +5003,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
unsigned int keyuse, subkeyuse; unsigned int keyuse, subkeyuse;
const char *curve, *subcurve; const char *curve, *subcurve;
char *keygrip, *subkeygrip; char *keygrip, *subkeygrip;
u32 keytime, subkeytime;
tty_printf ( _("Note: Use \"%s %s\"" tty_printf ( _("Note: Use \"%s %s\""
" for a full featured key generation dialog.\n"), " for a full featured key generation dialog.\n"),
@ -4983,10 +5016,10 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
err = parse_key_parameter_string (ctrl, NULL, -1, 0, err = parse_key_parameter_string (ctrl, NULL, -1, 0,
&algo, &size, &keyuse, &curve, &version, &algo, &size, &keyuse, &curve, &version,
&keygrip, &keygrip, &keytime,
&subalgo, &subsize, &subalgo, &subsize,
&subkeyuse, &subcurve, &subversion, &subkeyuse, &subcurve, &subversion,
&subkeygrip); &subkeygrip, &subkeytime);
if (err) if (err)
{ {
log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
@ -4994,11 +5027,11 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
} }
para = quickgen_set_para (para, 0, para = quickgen_set_para (para, 0,
algo, size, curve, keyuse, algo, size, curve, keyuse,
version, keygrip); version, keygrip, keytime);
if (subalgo) if (subalgo)
para = quickgen_set_para (para, 1, para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse, subalgo, subsize, subcurve, subkeyuse,
subversion, subkeygrip); subversion, subkeygrip, subkeytime);
xfree (keygrip); xfree (keygrip);
xfree (subkeygrip); xfree (subkeygrip);
@ -5214,7 +5247,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
PKT_public_key *sub_psk = NULL; PKT_public_key *sub_psk = NULL;
struct revocation_key *revkey; struct revocation_key *revkey;
int did_sub = 0; int did_sub = 0;
u32 timestamp; u32 keytimestamp, subkeytimestamp, authkeytimestamp, signtimestamp;
char *cache_nonce = NULL; char *cache_nonce = NULL;
int algo; int algo;
u32 expire; u32 expire;
@ -5273,11 +5306,35 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
start_tree (&pub_root); start_tree (&pub_root);
timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); cardkey = get_parameter_bool (para, pCARDKEY);
if (!timestamp)
timestamp = make_timestamp ();
/* Note that, depending on the backend (i.e. the used scdaemon /* In the case that the keys are created from the card we need to
* take the timestamps from the card. Only in this case a
* pSUBKEYCREATIONDATE or pAUTHKEYCREATIONDATE might be defined and
* then we need to use that so that the fingerprint of the subkey
* also matches the pre-computed and stored one on the card. In
* this case we also use the current time to create the
* self-signatures. */
keytimestamp = get_parameter_u32 (para, pKEYCREATIONDATE);
if (!keytimestamp)
keytimestamp = make_timestamp ();
subkeytimestamp = cardkey? get_parameter_u32 (para, pSUBKEYCREATIONDATE) : 0;
if (!subkeytimestamp)
subkeytimestamp = keytimestamp;
authkeytimestamp = cardkey? get_parameter_u32 (para, pAUTHKEYCREATIONDATE): 0;
if (!authkeytimestamp)
authkeytimestamp = keytimestamp;
signtimestamp = cardkey? make_timestamp () : keytimestamp;
/* log_debug ("XXX: cardkey ..: %d\n", cardkey); */
/* log_debug ("XXX: keytime ..: %s\n", isotimestamp (keytimestamp)); */
/* log_debug ("XXX: subkeytime: %s\n", isotimestamp (subkeytimestamp)); */
/* log_debug ("XXX: authkeytim: %s\n", isotimestamp (authkeytimestamp)); */
/* log_debug ("XXX: signtime .: %s\n", isotimestamp (signtimestamp)); */
/* Fixme: Check that this comment is still valid:
Note that, depending on the backend (i.e. the used scdaemon
version), the card key generation may update TIMESTAMP for each version), the card key generation may update TIMESTAMP for each
key. Thus we need to pass TIMESTAMP to all signing function to key. Thus we need to pass TIMESTAMP to all signing function to
make sure that the binding signature is done using the timestamp make sure that the binding signature is done using the timestamp
@ -5289,7 +5346,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL );
expire = get_parameter_u32( para, pKEYEXPIRE ); expire = get_parameter_u32( para, pKEYEXPIRE );
key_from_hexgrip = get_parameter_value (para, pKEYGRIP); key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
cardkey = get_parameter_bool (para, pCARDKEY); if (cardkey && !key_from_hexgrip)
BUG ();
keygen_flags = outctrl->keygen_flags; keygen_flags = outctrl->keygen_flags;
if (get_parameter_uint (para, pVERSION) == 5) if (get_parameter_uint (para, pVERSION) == 5)
@ -5297,20 +5355,22 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (key_from_hexgrip) if (key_from_hexgrip)
err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey,
pub_root, timestamp, expire, 0, keygen_flags); pub_root,
keytimestamp,
expire, 0, keygen_flags);
else if (!card) else if (!card)
err = do_create (algo, err = do_create (algo,
get_parameter_uint( para, pKEYLENGTH ), get_parameter_uint( para, pKEYLENGTH ),
get_parameter_value (para, pKEYCURVE), get_parameter_value (para, pKEYCURVE),
pub_root, pub_root,
timestamp, keytimestamp,
expire, 0, expire, 0,
keygen_flags, keygen_flags,
get_parameter_passphrase (para), get_parameter_passphrase (para),
&cache_nonce, NULL); &cache_nonce, NULL);
else else
err = gen_card_key (1, algo, err = gen_card_key (1, algo,
1, pub_root, &timestamp, 1, pub_root, &keytimestamp,
expire, keygen_flags); expire, keygen_flags);
/* Get the pointer to the generated public key packet. */ /* Get the pointer to the generated public key packet. */
@ -5330,15 +5390,15 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
err = write_direct_sig (ctrl, pub_root, pri_psk, err = write_direct_sig (ctrl, pub_root, pri_psk,
revkey, timestamp, cache_nonce); revkey, signtimestamp, cache_nonce);
if (!err && (s = get_parameter_value (para, pUSERID))) if (!err && (s = get_parameter_value (para, pUSERID)))
{ {
err = write_uid (pub_root, s ); err = write_uid (pub_root, s );
if (!err) if (!err)
err = write_selfsigs (ctrl, pub_root, pri_psk, err = write_selfsigs (ctrl, pub_root, pri_psk,
get_parameter_uint (para, pKEYUSAGE), timestamp, get_parameter_uint (para, pKEYUSAGE),
cache_nonce); signtimestamp, cache_nonce);
} }
/* Write the auth key to the card before the encryption key. This /* Write the auth key to the card before the encryption key. This
@ -5352,10 +5412,10 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
{ {
err = gen_card_key (3, get_parameter_algo (ctrl, para, err = gen_card_key (3, get_parameter_algo (ctrl, para,
pAUTHKEYTYPE, NULL ), pAUTHKEYTYPE, NULL ),
0, pub_root, &timestamp, expire, keygen_flags); 0, pub_root, &authkeytimestamp, expire, keygen_flags);
if (!err) if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, NULL, err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
PUBKEY_USAGE_AUTH, timestamp, cache_nonce); PUBKEY_USAGE_AUTH, signtimestamp, cache_nonce);
} }
if (!err && get_parameter (para, pSUBKEYTYPE)) if (!err && get_parameter (para, pSUBKEYTYPE))
@ -5372,7 +5432,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (key_from_hexgrip) if (key_from_hexgrip)
err = do_create_from_keygrip (ctrl, subkey_algo, err = do_create_from_keygrip (ctrl, subkey_algo,
key_from_hexgrip, cardkey, key_from_hexgrip, cardkey,
pub_root, timestamp, pub_root, subkeytimestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), get_parameter_u32 (para, pSUBKEYEXPIRE),
1, keygen_flags); 1, keygen_flags);
else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY))) else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
@ -5381,7 +5441,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_uint (para, pSUBKEYLENGTH),
get_parameter_value (para, pSUBKEYCURVE), get_parameter_value (para, pSUBKEYCURVE),
pub_root, pub_root,
timestamp, subkeytimestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), 1, get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags, s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags,
get_parameter_passphrase (para), get_parameter_passphrase (para),
@ -5403,14 +5463,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
} }
else else
{ {
err = gen_card_key (2, subkey_algo, 0, pub_root, &timestamp, expire, err = gen_card_key (2, subkey_algo, 0, pub_root,
keygen_flags); &subkeytimestamp, expire, keygen_flags);
} }
if (!err) if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk, err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk,
get_parameter_uint (para, pSUBKEYUSAGE), get_parameter_uint (para, pSUBKEYUSAGE),
timestamp, cache_nonce); signtimestamp, cache_nonce);
did_sub = 1; did_sub = 1;
} }
@ -5530,7 +5590,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr, const char *expirestr,
int *r_algo, unsigned int *r_usage, u32 *r_expire, int *r_algo, unsigned int *r_usage, u32 *r_expire,
unsigned int *r_nbits, const char **r_curve, unsigned int *r_nbits, const char **r_curve,
int *r_version, char **r_keygrip) int *r_version, char **r_keygrip, u32 *r_keytime)
{ {
gpg_error_t err; gpg_error_t err;
int algo; int algo;
@ -5543,6 +5603,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
*r_curve = NULL; *r_curve = NULL;
if (r_keygrip) if (r_keygrip)
*r_keygrip = NULL; *r_keygrip = NULL;
if (r_keytime)
*r_keytime = 0;
nbits = 0; nbits = 0;
@ -5558,8 +5620,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0, err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0,
usagestr? parse_usagestr (usagestr):0, usagestr? parse_usagestr (usagestr):0,
&algo, &nbits, &use, &curve, &version, &algo, &nbits, &use, &curve, &version,
r_keygrip, r_keygrip, r_keytime,
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (err) if (err)
{ {
if (r_keygrip) if (r_keygrip)
@ -5649,6 +5711,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
const char *curve = NULL; const char *curve = NULL;
u32 cur_time; u32 cur_time;
char *key_from_hexgrip = NULL; char *key_from_hexgrip = NULL;
u32 keytime = 0;
int cardkey = 0; int cardkey = 0;
char *hexgrip = NULL; char *hexgrip = NULL;
char *serialno = NULL; char *serialno = NULL;
@ -5740,7 +5803,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve, &algo, &use, &expire, &nbits, &curve,
&version, &key_from_hexgrip); &version, &key_from_hexgrip, &keytime);
if (err) if (err)
goto leave; goto leave;
@ -5768,7 +5831,9 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
if (key_from_hexgrip) if (key_from_hexgrip)
{ {
err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey,
keyblock, cur_time, expire, 1, keyblock,
keytime? keytime : cur_time,
expire, 1,
keygen_flags); keygen_flags);
} }
else else