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>
This commit is contained in:
Werner Koch 2019-04-03 15:30:10 +02:00
parent 2b1135cf92
commit ec6a677923
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 146 additions and 8 deletions

View File

@ -947,6 +947,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

View File

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

View File

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

View File

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