mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-30 16:17:02 +01:00
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:
parent
01730529f2
commit
1091f22511
@ -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 --*/
|
||||
|
164
agent/call-scd.c
164
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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user