aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2019-05-15 06:53:35 +0000
committerNIIBE Yutaka <[email protected]>2019-05-15 08:13:32 +0000
commit1091f22511e1a8259eb5c998f5c207ee95723a4a (patch)
treed95561f015aae5be609189ab24f4f1ef6b920a7b
parentscd: Don't put newline at the end of status. (diff)
downloadgnupg-1091f22511e1a8259eb5c998f5c207ee95723a4a.tar.gz
gnupg-1091f22511e1a8259eb5c998f5c207ee95723a4a.zip
agent: Support scdaemon operation using KEYGRIP.
* agent/agent.h (struct card_key_info_s): New. (divert_pksign, divert_pkdecrypt): New API. * agent/call-scd.c (card_keyinfo_cb): New. (agent_card_free_keyinfo, agent_card_keyinfo): New. * agent/divert-scd.c (ask_for_card): Having GRIP argument, ask scdaemon with agent_card_keyinfo. (divert_pksign, divert_pkdecrypt): Ditto. * agent/pkdecrypt.c (agent_pkdecrypt): Supply GRIP. * agent/pksign.c (agent_pksign_do): Ditto. -- We are going to relax the requirment for SERIALNO of card. It's OK, when a card doesn't have recorded SERIALNO. If a card has a key with GRIP, it can be used. GnuPG-bug-id: 2291, 4301 Signed-off-by: NIIBE Yutaka <[email protected]>
-rw-r--r--agent/agent.h14
-rw-r--r--agent/call-scd.c164
-rw-r--r--agent/divert-scd.c66
-rw-r--r--agent/pkdecrypt.c4
-rw-r--r--agent/pksign.c1
5 files changed, 215 insertions, 34 deletions
diff --git a/agent/agent.h b/agent/agent.h
index b7eacf471..77672bd50 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -361,6 +361,15 @@ typedef int (*lookup_ttl_t)(const char *hexgrip);
#endif
+/* Information from scdaemon for card keys. */
+struct card_key_info_s
+{
+ struct card_key_info_s *next;
+ char keygrip[40];
+ char *serialno;
+ char *idstr;
+};
+
/*-- gpg-agent.c --*/
void agent_exit (int rc)
GPGRT_ATTR_NORETURN; /* Also implemented in other tools */
@@ -544,10 +553,12 @@ void agent_reload_trustlist (void);
/*-- divert-scd.c --*/
int divert_pksign (ctrl_t ctrl, const char *desc_text,
+ const unsigned char *grip,
const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig,
size_t *r_siglen);
int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
+ const unsigned char *grip,
const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len, int *r_padding);
@@ -604,6 +615,9 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *,
const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context);
+void agent_card_free_keyinfo (struct card_key_info_s *l);
+gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
+ struct card_key_info_s **result);
/*-- learncard.c --*/
diff --git a/agent/call-scd.c b/agent/call-scd.c
index b52c6c8eb..5b53b0223 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -329,13 +329,13 @@ start_scd (ctrl_t ctrl)
{
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
if (!ctrl->scd_local)
- {
- err = gpg_error_from_syserror ();
- rc = npth_mutex_unlock (&start_scd_lock);
- if (rc)
- log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
- return err;
- }
+ {
+ err = gpg_error_from_syserror ();
+ rc = npth_mutex_unlock (&start_scd_lock);
+ if (rc)
+ log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
+ return err;
+ }
ctrl->scd_local->next_local = scd_local_list;
scd_local_list = ctrl->scd_local;
}
@@ -1281,6 +1281,156 @@ agent_card_cardlist (ctrl_t ctrl, strlist_t *result)
}
+struct card_keyinfo_parm_s {
+ int error;
+ struct card_key_info_s *list;
+};
+
+/* Callback function for agent_card_keylist. */
+static gpg_error_t
+card_keyinfo_cb (void *opaque, const char *line)
+{
+ struct card_keyinfo_parm_s *parm = opaque;
+ const char *keyword = line;
+ int keywordlen;
+
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 7 && !memcmp (keyword, "KEYINFO", keywordlen))
+ {
+ const char *s;
+ int n;
+ struct card_key_info_s *keyinfo;
+ struct card_key_info_s **l_p = &parm->list;
+
+ while ((*l_p))
+ l_p = &(*l_p)->next;
+
+ keyinfo = xtrycalloc (1, sizeof *keyinfo);
+ if (!keyinfo)
+ {
+ alloc_error:
+ if (!parm->error)
+ parm->error = gpg_error_from_syserror ();
+ return 0;
+ }
+
+ for (n=0,s=line; hexdigitp (s); s++, n++)
+ ;
+
+ if (n != 40)
+ {
+ parm_error:
+ if (!parm->error)
+ parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
+ return 0;
+ }
+
+ memcpy (keyinfo->keygrip, line, 40);
+
+ line = s;
+
+ if (!*line)
+ goto parm_error;
+
+ while (spacep (line))
+ line++;
+
+ if (*line++ != 'T')
+ goto parm_error;
+
+ if (!*line)
+ goto parm_error;
+
+ while (spacep (line))
+ line++;
+
+ for (n=0,s=line; hexdigitp (s); s++, n++)
+ ;
+
+ if (!n)
+ goto parm_error;
+
+ keyinfo->serialno = xtrymalloc (n+1);
+ if (!keyinfo->serialno)
+ goto alloc_error;
+
+ memcpy (keyinfo->serialno, line, n);
+ keyinfo->serialno[n] = 0;
+
+ line = s;
+
+ if (!*line)
+ goto parm_error;
+
+ while (spacep (line))
+ line++;
+
+ if (!*line)
+ goto parm_error;
+
+ keyinfo->idstr = xtrystrdup (line);
+ if (!keyinfo->idstr)
+ goto alloc_error;
+
+ *l_p = keyinfo;
+ }
+
+ return 0;
+}
+
+
+void
+agent_card_free_keyinfo (struct card_key_info_s *l)
+{
+ struct card_key_info_s *l_next;
+
+ for (; l; l = l_next)
+ {
+ l_next = l->next;
+ free (l->serialno);
+ free (l->idstr);
+ free (l);
+ }
+}
+
+/* Call the scdaemon to check if a key of KEYGRIP is available, or
+ retrieve list of available keys on cards. On success the allocated
+ structure is stored at RESULT. On error an error code is returned
+ and NULL is stored at RESULT. */
+gpg_error_t
+agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
+ struct card_key_info_s **result)
+{
+ int err;
+ struct card_keyinfo_parm_s parm;
+ char line[ASSUAN_LINELENGTH];
+
+ *result = NULL;
+
+ memset (&parm, 0, sizeof parm);
+ snprintf (line, sizeof line, "KEYINFO %s", keygrip ? keygrip : "--list");
+
+ err = start_scd (ctrl);
+ if (err)
+ return err;
+
+ err = assuan_transact (ctrl->scd_local->ctx, line,
+ NULL, NULL, NULL, NULL,
+ card_keyinfo_cb, &parm);
+ if (!err && parm.error)
+ err = parm.error;
+
+ if (!err)
+ *result = parm.list;
+ else
+ agent_card_free_keyinfo (parm.list);
+
+ return unlock_scd (ctrl, err);
+}
static gpg_error_t
pass_status_thru (void *opaque, const char *line)
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index e89c74a19..a6ffba75f 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -32,28 +32,43 @@
#include "../common/sexp-parse.h"
-static int
-ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
+static gpg_error_t
+ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info,
+ const unsigned char *grip, char **r_kid)
{
- int rc, i;
+ int i;
char *serialno;
int no_card = 0;
char *desc;
char *want_sn, *want_kid, *want_sn_disp;
int len;
+ struct card_key_info_s *keyinfo;
+ gpg_error_t err;
+ char hexgrip[41];
*r_kid = NULL;
- rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
- if (rc)
- return rc;
+ bin2hex (grip, 20, hexgrip);
+ err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo);
+ if (!err)
+ {
+ agent_card_free_keyinfo (keyinfo);
+ if ((*r_kid = xtrystrdup (hexgrip)))
+ return 0;
+ else
+ return gpg_error_from_syserror ();
+ }
+
+ err = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
+ if (err)
+ return err;
want_sn_disp = xtrystrdup (want_sn);
if (!want_sn_disp)
{
- rc = gpg_error_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (want_sn);
xfree (want_kid);
- return rc;
+ return err;
}
len = strlen (want_sn_disp);
@@ -76,8 +91,8 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
for (;;)
{
- rc = agent_card_serialno (ctrl, &serialno, want_sn);
- if (!rc)
+ err = agent_card_serialno (ctrl, &serialno, want_sn);
+ if (!err)
{
log_debug ("detected card with S/N %s\n", serialno);
i = strcmp (serialno, want_sn);
@@ -91,24 +106,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
return 0; /* yes, we have the correct card */
}
}
- else if (gpg_err_code (rc) == GPG_ERR_ENODEV)
+ else if (gpg_err_code (err) == GPG_ERR_ENODEV)
{
log_debug ("no device present\n");
- rc = 0;
+ err = 0;
no_card = 1;
}
- else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
+ else if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
{
log_debug ("no card present\n");
- rc = 0;
+ err = 0;
no_card = 2;
}
else
{
- log_error ("error accessing card: %s\n", gpg_strerror (rc));
+ log_error ("error accessing card: %s\n", gpg_strerror (err));
}
- if (!rc)
+ if (!err)
{
if (asprintf (&desc,
"%s:%%0A%%0A"
@@ -119,24 +134,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
"insert the one with serial number"),
want_sn_disp) < 0)
{
- rc = out_of_core ();
+ err = out_of_core ();
}
else
{
- rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
+ err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
- gpg_err_code (rc) == GPG_ERR_NO_PIN_ENTRY)
- rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
+ gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY)
+ err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
xfree (desc);
}
}
- if (rc)
+ if (err)
{
xfree (want_sn_disp);
xfree (want_sn);
xfree (want_kid);
- return rc;
+ return err;
}
}
}
@@ -434,7 +449,7 @@ getpin_cb (void *opaque, const char *desc_text, const char *info,
*
* FIXME: Explain the other args. */
int
-divert_pksign (ctrl_t ctrl, const char *desc_text,
+divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip,
const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig,
size_t *r_siglen)
@@ -446,7 +461,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
(void)desc_text;
- rc = ask_for_card (ctrl, shadow_info, &kid);
+ rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc)
return rc;
@@ -490,6 +505,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
R_PADDING with -1 for not known. */
int
divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
+ const unsigned char *grip,
const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len, int *r_padding)
@@ -581,7 +597,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
ciphertext = s;
ciphertextlen = n;
- rc = ask_for_card (ctrl, shadow_info, &kid);
+ rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc)
return rc;
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index a0ced2f55..ec23daf83 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -85,8 +85,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
}
- rc = divert_pkdecrypt (ctrl, desc_text, ciphertext, shadow_info,
- &buf, &len, r_padding);
+ rc = divert_pkdecrypt (ctrl, desc_text, ctrl->keygrip, ciphertext,
+ shadow_info, &buf, &len, r_padding);
if (rc)
{
log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc));
diff --git a/agent/pksign.c b/agent/pksign.c
index bc8d7336a..d9519d1bd 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -352,6 +352,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
agent_modify_description (desc_text, NULL, s_skey, &desc2);
err = divert_pksign (ctrl, desc2? desc2 : desc_text,
+ ctrl->keygrip,
data, datalen,
ctrl->digest.algo,
shadow_info, &buf, &len);