summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2019-04-03 15:30:10 +0200
committerWerner Koch <wk@gnupg.org>2019-04-03 15:30:10 +0200
commitec6a6779236a89d4784a6bb7de0def9cc0f9e8a4 (patch)
tree69e7cc27c2e651f5b76dc20b97d90632d050897a
parentscd: New standard attributes $ENCRKEYID and $SIGNKEYID. (diff)
downloadgnupg2-ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4.tar.xz
gnupg2-ec6a6779236a89d4784a6bb7de0def9cc0f9e8a4.zip
gpg: Allow decryption using PIV cards.
* g10/call-agent.c (struct getattr_one_parm_s): New. (getattr_one_status_cb): New. (agent_scd_getattr_one): New. * g10/pubkey-enc.c (get_it): Allow the standard leading zero byte from pkcs#1. * g10/skclist.c (enum_secret_keys): Handle non-OpenPGP cards. Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r--g10/call-agent.c80
-rw-r--r--g10/call-agent.h3
-rw-r--r--g10/pubkey-enc.c10
-rw-r--r--g10/skclist.c61
4 files changed, 146 insertions, 8 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 3b4882b53..f603d491a 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -948,6 +948,86 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
+/* Object used with the agent_scd_getattr_one. */
+struct getattr_one_parm_s {
+ const char *keyword; /* Keyword to look for. */
+ char *data; /* Malloced and unescaped data. */
+ gpg_error_t err; /* Error code or 0 on success. */
+};
+
+
+/* Callback for agent_scd_getattr_one. */
+static gpg_error_t
+getattr_one_status_cb (void *opaque, const char *line)
+{
+ struct getattr_one_parm_s *parm = opaque;
+ const char *s;
+
+ if (parm->data)
+ return 0; /* We want only the first occurrence. */
+
+ if ((s=has_leading_keyword (line, parm->keyword)))
+ {
+ parm->data = percent_plus_unescape (s, 0xff);
+ if (!parm->data)
+ parm->err = gpg_error_from_syserror ();
+ }
+
+ return 0;
+}
+
+
+/* Simplified version of agent_scd_getattr. This function returns
+ * only the first occurance of the attribute NAME and stores it at
+ * R_VALUE. A nul in the result is silennly replaced by 0xff. On
+ * error NULL is stored at R_VALUE. */
+gpg_error_t
+agent_scd_getattr_one (const char *name, char **r_value)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inqparm;
+ struct getattr_one_parm_s parm;
+
+ *r_value = NULL;
+
+ if (!*name)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ memset (&inqparm, 0, sizeof inqparm);
+ inqparm.ctx = agent_ctx;
+
+ memset (&parm, 0, sizeof parm);
+ parm.keyword = name;
+
+ /* We assume that NAME does not need escaping. */
+ if (12 + strlen (name) > DIM(line)-1)
+ return gpg_error (GPG_ERR_TOO_LARGE);
+ stpcpy (stpcpy (line, "SCD GETATTR "), name);
+
+ err = start_agent (NULL, 1);
+ if (err)
+ return err;
+
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL,
+ default_inq_cb, &inqparm,
+ getattr_one_status_cb, &parm);
+ if (!err && parm.err)
+ err = parm.err;
+ else if (!err && !parm.data)
+ err = gpg_error (GPG_ERR_NO_DATA);
+
+ if (!err)
+ *r_value = parm.data;
+ else
+ xfree (parm.data);
+
+ return err;
+}
+
+
+
/* Call the agent to retrieve a data object. This function returns
* the data in the same structure as used by the learn command. It is
* allowed to update such a structure using this command.
diff --git a/g10/call-agent.h b/g10/call-agent.h
index cb874fdad..c0018a595 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -96,6 +96,9 @@ int agent_scd_serialno (char **r_serialno, const char *demand);
/* Send an APDU to the card. */
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
+/* Get attribute NAME from the card and store at R_VALUE. */
+gpg_error_t agent_scd_getattr_one (const char *name, char **r_value);
+
/* Update INFO with the attribute NAME. */
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 055c39b8f..f61fa7abe 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -319,6 +319,16 @@ get_it (ctrl_t ctrl,
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
+
+ /* FIXME: Actually the leading zero is required but due to
+ * the way we encode the output in libgcrypt as an MPI we
+ * are not able to encode that leading zero. However, when
+ * using a Smartcard we are doing it the right way and
+ * therefore we have to skip the zero. This should be fixed
+ * in gpg-agent of course. */
+ if (!frame[n])
+ n++;
+
if (frame[n] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
diff --git a/g10/skclist.c b/g10/skclist.c
index ebbaba254..b4f83ea1a 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -340,6 +340,10 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
SK_LIST results;
} *c = *context;
+#if MAX_FINGERPRINT_LEN < KEYGRIP_LEN
+# error buffer too short for this configuration
+#endif
+
if (!c)
{
/* Make a new context. */
@@ -430,17 +434,58 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
xfree (serialno);
c->info.fpr2len = 0;
err = agent_scd_getattr ("KEY-FPR", &c->info);
+ if (!err)
+ {
+ if (c->info.fpr2len)
+ {
+ c->fpr2[0] = '0';
+ c->fpr2[1] = 'x';
+ bin2hex (c->info.fpr2, sizeof c->info.fpr2,
+ c->fpr2 + 2);
+ name = c->fpr2;
+ }
+ }
+ else if (gpg_err_code (err) == GPG_ERR_INV_NAME)
+ {
+ /* KEY-FPR not supported by the card - get
+ * the key using the keygrip. */
+ char *keyref;
+ strlist_t kplist, sl;
+ const char *s;
+ int i;
+
+ err = agent_scd_getattr_one ("$ENCRKEYID", &keyref);
+ if (!err)
+ {
+ err = agent_scd_keypairinfo (ctrl, &kplist);
+ if (!err)
+ {
+ for (sl = kplist; sl; sl = sl->next)
+ if ((s = strchr (sl->d, ' '))
+ && !strcmp (s+1, keyref))
+ break;
+ if (sl)
+ {
+ c->fpr2[0] = '&';
+ for (i=1, s=sl->d;
+ (*s && *s != ' '
+ && i < sizeof c->fpr2 - 3);
+ s++, i++)
+ c->fpr2[i] = *s;
+ c->fpr2[i] = 0;
+ name = c->fpr2;
+ }
+ else /* Restore error. */
+ err = gpg_error (GPG_ERR_INV_NAME);
+ free_strlist (kplist);
+ }
+ }
+ xfree (keyref);
+ }
if (err)
- log_error ("error retrieving key fingerprint from card: %s\n",
+ log_error ("error retrieving key from card: %s\n",
gpg_strerror (err));
- if (c->info.fpr2len)
- {
- c->fpr2[0] = '0';
- c->fpr2[1] = 'x';
- bin2hex (c->info.fpr2, sizeof c->info.fpr2,c->fpr2+2);
- name = c->fpr2;
- }
c->sl = c->sl->next;
}
else