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 <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2019-05-15 15:53:35 +09:00
parent 01730529f2
commit 1091f22511
5 changed files with 215 additions and 34 deletions

View File

@ -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 --*/

View File

@ -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)

View File

@ -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;

View File

@ -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));

View File

@ -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);