mirror of
git://git.gnupg.org/gnupg.git
synced 2025-03-28 22:49:59 +01:00
gpg: Allow direct key generation from card with --full-gen-key.
* g10/call-agent.c (agent_scd_readkey): New. * g10/keygen.c (ask_key_flags): Factor code out to .. (ask_key_flags_with_mask): new. (ask_algo): New mode 14. -- Note that this new menu 14 is always displayed. The usage flags can be changed only in --expert mode, though. Creating and using signing keys works but decryption does not yet work; we will need to tweak a couple of other places for that. Tested with a Yubikey's PIV app. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
f952226043
commit
a480182f9d
@ -1572,6 +1572,7 @@ Description of some debug flags:
|
|||||||
| ecc/* | 11 | ECC (set your own capabilities) |
|
| ecc/* | 11 | ECC (set your own capabilities) |
|
||||||
| ecc/e | 12 | ECC (encrypt only) |
|
| ecc/e | 12 | ECC (encrypt only) |
|
||||||
| keygrip | 13 | Existing key |
|
| keygrip | 13 | Existing key |
|
||||||
|
| cardkey | 14 | Existing key from card |
|
||||||
|
|
||||||
If one of the "foo/*" names are used a "keygen.flags" prompt needs
|
If one of the "foo/*" names are used a "keygen.flags" prompt needs
|
||||||
to be answered as well. Instead of toggling the predefined flags,
|
to be answered as well. Instead of toggling the predefined flags,
|
||||||
|
@ -210,7 +210,7 @@ Key management ...: [none]
|
|||||||
keyref .....: PIV.9D
|
keyref .....: PIV.9D
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Note that the ``Displayed s/sn'' is printed on the token and also
|
Note that the ``Displayed s/n'' is printed on the token and also
|
||||||
shown in Pinentry prompts asking for the PIN. The four standard key
|
shown in Pinentry prompts asking for the PIN. The four standard key
|
||||||
slots are always shown, if other key slots are initialized they are
|
slots are always shown, if other key slots are initialized they are
|
||||||
shown as well. The @emph{PIV authentication} key (internal reference
|
shown as well. The @emph{PIV authentication} key (internal reference
|
||||||
@ -231,11 +231,11 @@ which needs to be provided only once so that decryption operations can
|
|||||||
then be done until the card is reset or removed from the reader or USB
|
then be done until the card is reset or removed from the reader or USB
|
||||||
port.
|
port.
|
||||||
|
|
||||||
We now generate tree of the four keys. Note that GnuPG does currently
|
We now generate three of the four keys. Note that GnuPG does
|
||||||
not use the the @emph{Card authentication} key but because it is
|
currently not use the the @emph{Card authentication} key; however,
|
||||||
mandatory by the specs we create it anyway. Key generation requires
|
that key is mandatory by the PIV standard and thus we create it too.
|
||||||
that we authenticate to the card. This can be done either on the
|
Key generation requires that we authenticate to the card. This can be
|
||||||
command line (which would reveal the key):
|
done either on the command line (which would reveal the key):
|
||||||
|
|
||||||
@example
|
@example
|
||||||
gpg/card> auth 010203040506070801020304050607080102030405060708
|
gpg/card> auth 010203040506070801020304050607080102030405060708
|
||||||
@ -360,7 +360,7 @@ gpgsm: total number processed: 1
|
|||||||
gpgsm: imported: 1
|
gpgsm: imported: 1
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Note the last steps which imported the created certificate. If you
|
Note the last step which imported the created certificate. If you
|
||||||
you instead created a certificate signing request (CSR) instead of a
|
you instead created a certificate signing request (CSR) instead of a
|
||||||
self-signed certificate and sent this off to a CA you would do the
|
self-signed certificate and sent this off to a CA you would do the
|
||||||
same import step with the certificate received from the CA. Take note
|
same import step with the certificate received from the CA. Take note
|
||||||
|
@ -1251,6 +1251,49 @@ agent_scd_readcert (const char *certidstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
gpg_error_t
|
||||||
|
agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
membuf_t data;
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t len, buflen;
|
||||||
|
struct default_inq_parm_s dfltparm;
|
||||||
|
|
||||||
|
memset (&dfltparm, 0, sizeof dfltparm);
|
||||||
|
dfltparm.ctx = agent_ctx;
|
||||||
|
|
||||||
|
*r_result = NULL;
|
||||||
|
err = start_agent (NULL, 1);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
init_membuf (&data, 1024);
|
||||||
|
snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
|
||||||
|
err = assuan_transact (agent_ctx, line,
|
||||||
|
put_membuf_cb, &data,
|
||||||
|
default_inq_cb, &dfltparm,
|
||||||
|
NULL, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (get_membuf (&data, &len));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
buf = get_membuf (&data, &buflen);
|
||||||
|
if (!buf)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
err = gcry_sexp_new (r_result, buf, buflen, 0);
|
||||||
|
xfree (buf);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct card_cardlist_parm_s {
|
struct card_cardlist_parm_s {
|
||||||
int error;
|
int error;
|
||||||
|
@ -114,10 +114,13 @@ int agent_scd_writecert (const char *certidstr,
|
|||||||
/* Send a GENKEY command to the SCdaemon. */
|
/* Send a GENKEY command to the SCdaemon. */
|
||||||
int agent_scd_genkey (int keyno, int force, u32 *createtime);
|
int agent_scd_genkey (int keyno, int force, u32 *createtime);
|
||||||
|
|
||||||
/* Send a READKEY command to the SCdaemon. */
|
/* Send a READCERT command to the SCdaemon. */
|
||||||
int agent_scd_readcert (const char *certidstr,
|
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. */
|
||||||
|
gpg_error_t agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
|
||||||
|
|
||||||
/* Change the PIN of an OpenPGP card or reset the retry counter. */
|
/* Change the PIN of an OpenPGP card or reset the retry counter. */
|
||||||
int agent_scd_change_pin (int chvno, const char *serialno);
|
int agent_scd_change_pin (int chvno, const char *serialno);
|
||||||
|
|
||||||
|
178
g10/keygen.c
178
g10/keygen.c
@ -1881,24 +1881,26 @@ print_key_flags(int flags)
|
|||||||
|
|
||||||
|
|
||||||
/* Ask for the key flags and return them. CURRENT gives the current
|
/* Ask for the key flags and return them. CURRENT gives the current
|
||||||
* usage which should normally be given as 0. */
|
* usage which should normally be given as 0. MASK gives the allowed
|
||||||
|
* flags. */
|
||||||
unsigned int
|
unsigned int
|
||||||
ask_key_flags (int algo, int subkey, unsigned int current)
|
ask_key_flags_with_mask (int algo, int subkey, unsigned int current,
|
||||||
|
unsigned int mask)
|
||||||
{
|
{
|
||||||
/* TRANSLATORS: Please use only plain ASCII characters for the
|
/* TRANSLATORS: Please use only plain ASCII characters for the
|
||||||
translation. If this is not possible use single digits. The
|
* translation. If this is not possible use single digits. The
|
||||||
string needs to 8 bytes long. Here is a description of the
|
* string needs to 8 bytes long. Here is a description of the
|
||||||
functions:
|
* functions:
|
||||||
|
*
|
||||||
s = Toggle signing capability
|
* s = Toggle signing capability
|
||||||
e = Toggle encryption capability
|
* e = Toggle encryption capability
|
||||||
a = Toggle authentication capability
|
* a = Toggle authentication capability
|
||||||
q = Finish
|
* q = Finish
|
||||||
*/
|
*/
|
||||||
const char *togglers = _("SsEeAaQq");
|
const char *togglers = _("SsEeAaQq");
|
||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
const char *s;
|
const char *s;
|
||||||
unsigned int possible = openpgp_pk_algo_usage(algo);
|
unsigned int possible;
|
||||||
|
|
||||||
if ( strlen(togglers) != 8 )
|
if ( strlen(togglers) != 8 )
|
||||||
{
|
{
|
||||||
@ -1907,22 +1909,26 @@ ask_key_flags (int algo, int subkey, unsigned int current)
|
|||||||
togglers = "11223300";
|
togglers = "11223300";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only primary keys may certify. */
|
/* Mask the possible usage flags. This is for example used for a
|
||||||
if(subkey)
|
* card based key. */
|
||||||
possible&=~PUBKEY_USAGE_CERT;
|
possible = (openpgp_pk_algo_usage (algo) & mask);
|
||||||
|
|
||||||
/* Preload the current set with the possible set, minus
|
/* However, only primary keys may certify. */
|
||||||
authentication if CURRENT has been given as 0. If CURRENT has
|
if (subkey)
|
||||||
been has non-zero we mask with all possible usages. */
|
possible &= ~PUBKEY_USAGE_CERT;
|
||||||
|
|
||||||
|
/* Preload the current set with the possible set, without
|
||||||
|
* authentication if CURRENT is 0. If CURRENT is non-zero we mask
|
||||||
|
* with all possible usages. */
|
||||||
if (current)
|
if (current)
|
||||||
current &= possible;
|
current &= possible;
|
||||||
else
|
else
|
||||||
current = (possible&~PUBKEY_USAGE_AUTH);
|
current = (possible&~PUBKEY_USAGE_AUTH);
|
||||||
|
|
||||||
for(;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
tty_printf("\n");
|
tty_printf("\n");
|
||||||
tty_printf(_("Possible actions for a %s key: "),
|
tty_printf(_("Possible actions for this %s key: "),
|
||||||
(algo == PUBKEY_ALGO_ECDSA
|
(algo == PUBKEY_ALGO_ECDSA
|
||||||
|| algo == PUBKEY_ALGO_EDDSA)
|
|| algo == PUBKEY_ALGO_EDDSA)
|
||||||
? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
|
? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
|
||||||
@ -2009,6 +2015,13 @@ ask_key_flags (int algo, int subkey, unsigned int current)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
ask_key_flags (int algo, int subkey, unsigned int current)
|
||||||
|
{
|
||||||
|
return ask_key_flags_with_mask (algo, subkey, current, ~0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check whether we have a key for the key with HEXGRIP. Returns 0 if
|
/* Check whether we have a key for the key with HEXGRIP. Returns 0 if
|
||||||
there is no such key or the OpenPGP algo number for the key. */
|
there is no such key or the OpenPGP algo number for the key. */
|
||||||
static int
|
static int
|
||||||
@ -2047,10 +2060,12 @@ static int
|
|||||||
ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
|
ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
|
||||||
char **r_keygrip)
|
char **r_keygrip)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
char *keygrip = NULL;
|
char *keygrip = NULL;
|
||||||
char *answer = NULL;
|
char *answer = NULL;
|
||||||
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;
|
||||||
@ -2101,6 +2116,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
|
|||||||
|
|
||||||
if (opt.expert && r_keygrip)
|
if (opt.expert && r_keygrip)
|
||||||
tty_printf (_(" (%d) Existing key\n"), 13 );
|
tty_printf (_(" (%d) Existing key\n"), 13 );
|
||||||
|
if (r_keygrip)
|
||||||
|
tty_printf (_(" (%d) Existing key from card\n"), 14 );
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -2221,9 +2238,130 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
|
|||||||
*r_usage = ask_key_flags (algo, addmode, 0);
|
*r_usage = ask_key_flags (algo, addmode, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip)
|
||||||
|
{
|
||||||
|
char *serialno;
|
||||||
|
strlist_t keypairlist, sl;
|
||||||
|
int count, selection;
|
||||||
|
|
||||||
|
err = agent_scd_serialno (&serialno, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
tty_printf (_("error reading the card: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto ask_again;
|
||||||
|
}
|
||||||
|
tty_printf (_("Serial number of the card: %s\n"), serialno);
|
||||||
|
xfree (serialno);
|
||||||
|
|
||||||
|
err = agent_scd_keypairinfo (ctrl, &keypairlist);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
tty_printf (_("error reading the card: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto ask_again;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tty_printf (_("Available keys:\n"));
|
||||||
|
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
|
||||||
|
{
|
||||||
|
gcry_sexp_t s_pkey;
|
||||||
|
char *algostr = NULL;
|
||||||
|
enum gcry_pk_algos algoid = 0;
|
||||||
|
const char *keyref;
|
||||||
|
int any = 0;
|
||||||
|
|
||||||
|
keyref = strchr (sl->d, ' ');
|
||||||
|
if (keyref)
|
||||||
|
{
|
||||||
|
keyref++;
|
||||||
|
if (!agent_scd_readkey (keyref, &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
|
||||||
|
* GCRY_PK_ECC is returned becuase pubkey_algo_string
|
||||||
|
* is not aware of the OpenPGP algo mapping.
|
||||||
|
* FIXME: This is an ugly hack. */
|
||||||
|
sl->flags &= 0xff;
|
||||||
|
if (algoid == GCRY_PK_ECC
|
||||||
|
&& algostr && !strncmp (algostr, "nistp", 5)
|
||||||
|
&& !(sl->flags & GCRY_PK_USAGE_ENCR))
|
||||||
|
sl->flags |= (PUBKEY_ALGO_ECDSA << 8);
|
||||||
|
else
|
||||||
|
sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8);
|
||||||
|
|
||||||
|
tty_printf (" (%d) %s %s", count, sl->d, algostr);
|
||||||
|
if ((sl->flags & GCRY_PK_USAGE_CERT))
|
||||||
|
{
|
||||||
|
tty_printf ("%scert", any?",":" (");
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
if ((sl->flags & GCRY_PK_USAGE_SIGN))
|
||||||
|
{
|
||||||
|
tty_printf ("%ssign", any?",":" (");
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
if ((sl->flags & GCRY_PK_USAGE_AUTH))
|
||||||
|
{
|
||||||
|
tty_printf ("%sauth", any?",":" (");
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
if ((sl->flags & GCRY_PK_USAGE_ENCR))
|
||||||
|
{
|
||||||
|
tty_printf ("%sencr", any?",":" (");
|
||||||
|
any = 1;
|
||||||
|
}
|
||||||
|
tty_printf ("%s\n", any?")":"");
|
||||||
|
xfree (algostr);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (answer);
|
||||||
|
answer = cpr_get ("keygen.cardkey", _("Your selection? "));
|
||||||
|
cpr_kill_prompt ();
|
||||||
|
trim_spaces (answer);
|
||||||
|
selection = atoi (answer);
|
||||||
|
}
|
||||||
|
while (!(selection > 0 && selection < count));
|
||||||
|
|
||||||
|
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
|
||||||
|
if (count == selection)
|
||||||
|
break;
|
||||||
|
if (!sl)
|
||||||
|
{
|
||||||
|
/* Just in case COUNT is zero (no keys). */
|
||||||
|
free_strlist (keypairlist);
|
||||||
|
goto ask_again;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (keygrip);
|
||||||
|
keygrip = xstrdup (sl->d);
|
||||||
|
if ((p = strchr (keygrip, ' ')))
|
||||||
|
*p = 0;
|
||||||
|
algo = (sl->flags >>8);
|
||||||
|
if (opt.expert)
|
||||||
|
*r_usage = ask_key_flags_with_mask (algo, addmode,
|
||||||
|
(sl->flags & 0xff),
|
||||||
|
(sl->flags & 0xff));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*r_usage = (sl->flags & 0xff);
|
||||||
|
if (addmode)
|
||||||
|
*r_usage &= ~GCRY_PK_USAGE_CERT;
|
||||||
|
}
|
||||||
|
free_strlist (keypairlist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
tty_printf (_("Invalid selection.\n"));
|
tty_printf (_("Invalid selection.\n"));
|
||||||
|
|
||||||
|
ask_again:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
xfree(answer);
|
xfree(answer);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user