aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/call-agent.c43
-rw-r--r--g10/call-agent.h5
-rw-r--r--g10/keygen.c178
3 files changed, 205 insertions, 21 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 83ca921a7..a0c5f811f 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -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 {
int error;
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 0a545b22e..cb874fdad 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -114,10 +114,13 @@ int agent_scd_writecert (const char *certidstr,
/* Send a GENKEY command to the SCdaemon. */
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,
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. */
int agent_scd_change_pin (int chvno, const char *serialno);
diff --git a/g10/keygen.c b/g10/keygen.c
index 943b40110..6ea4e72c6 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1881,24 +1881,26 @@ print_key_flags(int flags)
/* 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
-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
- translation. If this is not possible use single digits. The
- string needs to 8 bytes long. Here is a description of the
- functions:
-
- s = Toggle signing capability
- e = Toggle encryption capability
- a = Toggle authentication capability
- q = Finish
- */
+ * translation. If this is not possible use single digits. The
+ * string needs to 8 bytes long. Here is a description of the
+ * functions:
+ *
+ * s = Toggle signing capability
+ * e = Toggle encryption capability
+ * a = Toggle authentication capability
+ * q = Finish
+ */
const char *togglers = _("SsEeAaQq");
char *answer = NULL;
const char *s;
- unsigned int possible = openpgp_pk_algo_usage(algo);
+ unsigned int possible;
if ( strlen(togglers) != 8 )
{
@@ -1907,22 +1909,26 @@ ask_key_flags (int algo, int subkey, unsigned int current)
togglers = "11223300";
}
- /* Only primary keys may certify. */
- if(subkey)
- possible&=~PUBKEY_USAGE_CERT;
+ /* Mask the possible usage flags. This is for example used for a
+ * card based key. */
+ possible = (openpgp_pk_algo_usage (algo) & mask);
- /* Preload the current set with the possible set, minus
- authentication if CURRENT has been given as 0. If CURRENT has
- been has non-zero we mask with all possible usages. */
+ /* However, only primary keys may certify. */
+ if (subkey)
+ 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)
current &= possible;
else
current = (possible&~PUBKEY_USAGE_AUTH);
- for(;;)
+ for (;;)
{
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_EDDSA)
? "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
there is no such key or the OpenPGP algo number for the key. */
static int
@@ -2047,10 +2060,12 @@ static int
ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
char **r_keygrip)
{
+ gpg_error_t err;
char *keygrip = NULL;
char *answer = NULL;
int algo;
int dummy_algo;
+ char *p;
if (!r_subkey_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)
tty_printf (_(" (%d) Existing key\n"), 13 );
+ if (r_keygrip)
+ tty_printf (_(" (%d) Existing key from card\n"), 14 );
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);
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
tty_printf (_("Invalid selection.\n"));
+ ask_again:
+ ;
}
xfree(answer);