mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd:piv: Implement PIN cache.
* scd/command.c (pincache_put): Add arg pinlen and change all callers to provide it. * scd/app-piv.c (cache_pin): New. (pin_from_cache): New. (ask_and_prepare_chv): Add args no_cache and r_unpaddedpinlen. Take PIN from the cache. Return the unpadded length. (verify_chv): Add arg ctrl. Cache the PIN. (do_change_chv): Clear PIN cache. -- The PIV pins are padded but we want to store the unpadded PIN. Thus the changes to the function. Code has has been tested by commenting the no_cache parameter because we the current test certificate was created for PIV.9C which requires a verification for each use. More testing is required. GnuPG-bug-id: 4791 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
2e86cca7f4
commit
60502c3606
@ -2225,7 +2225,8 @@ cache_pin (app_t app, ctrl_t ctrl, int chvno, const char *pin)
|
|||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pincache_put (ctrl, app_get_slot (app), "openpgp", keyref, pin);
|
pincache_put (ctrl, app_get_slot (app), "openpgp", keyref,
|
||||||
|
pin, pin? strlen (pin):0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
113
scd/app-piv.c
113
scd/app-piv.c
@ -1,5 +1,5 @@
|
|||||||
/* app-piv.c - The OpenPGP card application.
|
/* app-piv.c - The OpenPGP card application.
|
||||||
* Copyright (C) 2019 g10 Code GmbH
|
* Copyright (C) 2019, 2020 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -1711,6 +1711,52 @@ get_key_algorithm_by_dobj (app_t app, data_object_t dobj, int *r_mechanism)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper to cache the pin PINNO. If PIN is NULL the cache is cleared. */
|
||||||
|
static void
|
||||||
|
cache_pin (app_t app, ctrl_t ctrl, int pinno,
|
||||||
|
const char *pin, unsigned int pinlen)
|
||||||
|
{
|
||||||
|
char pinref[20];
|
||||||
|
|
||||||
|
if (pinno < 0)
|
||||||
|
return;
|
||||||
|
switch (app->card->cardtype)
|
||||||
|
{
|
||||||
|
case CARDTYPE_YUBIKEY: break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf (pinref, sizeof pinref, "%02x", pinno);
|
||||||
|
pincache_put (ctrl, app_get_slot (app), "piv", pinref, pin, pinlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If the PIN cache is available and really has a valid PIN return
|
||||||
|
* that pin at R_PIN. Returns true if that is the case; otherwise
|
||||||
|
* false. */
|
||||||
|
static int
|
||||||
|
pin_from_cache (app_t app, ctrl_t ctrl, int pinno, char **r_pin)
|
||||||
|
{
|
||||||
|
char pinref[20];
|
||||||
|
|
||||||
|
*r_pin = NULL;
|
||||||
|
|
||||||
|
if (pinno < 0)
|
||||||
|
return 0;
|
||||||
|
switch (app->card->cardtype)
|
||||||
|
{
|
||||||
|
case CARDTYPE_YUBIKEY: break;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf (pinref, sizeof pinref, "%02x", pinno);
|
||||||
|
if (pincache_get (ctrl, app_get_slot (app), "piv", pinref, r_pin))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return an allocated string to be used as prompt. Returns NULL on
|
/* Return an allocated string to be used as prompt. Returns NULL on
|
||||||
* malloc error. */
|
* malloc error. */
|
||||||
static char *
|
static char *
|
||||||
@ -1768,9 +1814,11 @@ make_prompt (app_t app, int remaining, const char *firstline)
|
|||||||
/* Helper for verify_chv to ask for the PIN and to prepare/pad it. On
|
/* Helper for verify_chv to ask for the PIN and to prepare/pad it. On
|
||||||
* success the result is stored at (R_PIN,R_PINLEN). */
|
* success the result is stored at (R_PIN,R_PINLEN). */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
ask_and_prepare_chv (app_t app, ctrl_t ctrl,
|
||||||
|
int keyref, int ask_new, int remaining, int no_cache,
|
||||||
gpg_error_t (*pincb)(void*,const char *,char **),
|
gpg_error_t (*pincb)(void*,const char *,char **),
|
||||||
void *pincb_arg, char **r_pin, unsigned int *r_pinlen)
|
void *pincb_arg, char **r_pin, unsigned int *r_pinlen,
|
||||||
|
unsigned int *r_unpaddedpinlen)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
const char *label;
|
const char *label;
|
||||||
@ -1782,6 +1830,8 @@ ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
|||||||
|
|
||||||
*r_pin = NULL;
|
*r_pin = NULL;
|
||||||
*r_pinlen = 0;
|
*r_pinlen = 0;
|
||||||
|
if (r_unpaddedpinlen)
|
||||||
|
*r_unpaddedpinlen = 0;
|
||||||
|
|
||||||
if (ask_new)
|
if (ask_new)
|
||||||
remaining = -1;
|
remaining = -1;
|
||||||
@ -1827,10 +1877,16 @@ ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ask for the PIN. */
|
/* Ask for the PIN. */
|
||||||
prompt = make_prompt (app, remaining, label);
|
if (!no_cache && remaining >= 3
|
||||||
err = pincb (pincb_arg, prompt, &pinvalue);
|
&& pin_from_cache (app, ctrl, keyref, &pinvalue))
|
||||||
xfree (prompt);
|
err = 0;
|
||||||
prompt = NULL;
|
else
|
||||||
|
{
|
||||||
|
prompt = make_prompt (app, remaining, label);
|
||||||
|
err = pincb (pincb_arg, prompt, &pinvalue);
|
||||||
|
xfree (prompt);
|
||||||
|
prompt = NULL;
|
||||||
|
}
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_info (_("PIN callback returned error: %s\n"), gpg_strerror (err));
|
log_info (_("PIN callback returned error: %s\n"), gpg_strerror (err));
|
||||||
@ -1873,6 +1929,10 @@ ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
|||||||
memcpy (pinbuffer, pinvalue, pinlen);
|
memcpy (pinbuffer, pinvalue, pinlen);
|
||||||
wipememory (pinvalue, pinlen);
|
wipememory (pinvalue, pinlen);
|
||||||
xfree (pinvalue);
|
xfree (pinvalue);
|
||||||
|
|
||||||
|
if (r_unpaddedpinlen)
|
||||||
|
*r_unpaddedpinlen = pinlen;
|
||||||
|
|
||||||
if (padding)
|
if (padding)
|
||||||
{
|
{
|
||||||
memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
|
memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
|
||||||
@ -1890,7 +1950,7 @@ ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
|
|||||||
* either the Appication PIN or the Global PIN. If FORCE is true a
|
* either the Appication PIN or the Global PIN. If FORCE is true a
|
||||||
* verification is always done. */
|
* verification is always done. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
verify_chv (app_t app, int keyref, int force,
|
verify_chv (app_t app, ctrl_t ctrl, int keyref, int force,
|
||||||
gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
|
gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
@ -1898,7 +1958,7 @@ verify_chv (app_t app, int keyref, int force,
|
|||||||
unsigned int sw;
|
unsigned int sw;
|
||||||
int remaining;
|
int remaining;
|
||||||
char *pin = NULL;
|
char *pin = NULL;
|
||||||
unsigned int pinlen;
|
unsigned int pinlen, unpaddedpinlen;
|
||||||
|
|
||||||
/* First check whether a verify is at all needed. This is done with
|
/* First check whether a verify is at all needed. This is done with
|
||||||
* P1 being 0 and no Lc and command data send. */
|
* P1 being 0 and no Lc and command data send. */
|
||||||
@ -1917,17 +1977,24 @@ verify_chv (app_t app, int keyref, int force,
|
|||||||
else
|
else
|
||||||
remaining = -1;
|
remaining = -1;
|
||||||
|
|
||||||
err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
|
err = ask_and_prepare_chv (app, ctrl, keyref, 0, remaining, force,
|
||||||
&pin, &pinlen);
|
pincb, pincb_arg,
|
||||||
|
&pin, &pinlen, &unpaddedpinlen);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = iso7816_verify (app_get_slot (app), keyref, pin, pinlen);
|
err = iso7816_verify (app_get_slot (app), keyref, pin, pinlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("CHV %02X verification failed: %s\n",
|
||||||
|
keyref, gpg_strerror (err));
|
||||||
|
cache_pin (app, ctrl, keyref, NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cache_pin (app, ctrl, keyref, pin, unpaddedpinlen);
|
||||||
|
|
||||||
wipememory (pin, pinlen);
|
wipememory (pin, pinlen);
|
||||||
xfree (pin);
|
xfree (pin);
|
||||||
if (err)
|
|
||||||
log_error ("CHV %02X verification failed: %s\n",
|
|
||||||
keyref, gpg_strerror (err));
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1976,6 +2043,8 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache_pin (app, ctrl, keyref, NULL, 0);
|
||||||
|
|
||||||
/* First see whether the special --clear mode has been requested. */
|
/* First see whether the special --clear mode has been requested. */
|
||||||
if ((flags & APP_CHANGE_FLAG_CLEAR))
|
if ((flags & APP_CHANGE_FLAG_CLEAR))
|
||||||
{
|
{
|
||||||
@ -2014,8 +2083,9 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
remaining = -1;
|
remaining = -1;
|
||||||
|
|
||||||
/* Ask for the old pin or puk. */
|
/* Ask for the old pin or puk. */
|
||||||
err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
|
err = ask_and_prepare_chv (app, ctrl, keyref, 0, remaining, 0,
|
||||||
&oldpin, &oldpinlen);
|
pincb, pincb_arg,
|
||||||
|
&oldpin, &oldpinlen, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2033,8 +2103,9 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ask for the new pin. */
|
/* Ask for the new pin. */
|
||||||
err = ask_and_prepare_chv (app, targetkeyref, 1, -1, pincb, pincb_arg,
|
err = ask_and_prepare_chv (app, ctrl, targetkeyref, 1, -1, 0,
|
||||||
&newpin, &newpinlen);
|
pincb, pincb_arg,
|
||||||
|
&newpin, &newpinlen, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2088,7 +2159,7 @@ do_check_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
|||||||
if (keyref == -1)
|
if (keyref == -1)
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
|
|
||||||
return verify_chv (app, keyref, 0, pincb, pincb_arg);
|
return verify_chv (app, ctrl, keyref, 0, pincb, pincb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2287,7 +2358,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now verify the Application PIN. */
|
/* Now verify the Application PIN. */
|
||||||
err = verify_chv (app, 0x80, force_verify, pincb, pincb_arg);
|
err = verify_chv (app, ctrl, 0x80, force_verify, pincb, pincb_arg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2511,7 +2582,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now verify the Application PIN. */
|
/* Now verify the Application PIN. */
|
||||||
err = verify_chv (app, 0x80, 0, pincb, pincb_arg);
|
err = verify_chv (app, ctrl, 0x80, 0, pincb, pincb_arg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -664,7 +664,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
|
|||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
pincache_put (ctrl, slot, NULL, NULL, NULL);
|
pincache_put (ctrl, slot, NULL, NULL, NULL, 0);
|
||||||
apdu_close_reader (slot);
|
apdu_close_reader (slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1919,7 +1919,7 @@ scd_update_reader_status_file (void)
|
|||||||
if (status == 0)
|
if (status == 0)
|
||||||
{
|
{
|
||||||
log_debug ("Removal of a card: %d\n", card->slot);
|
log_debug ("Removal of a card: %d\n", card->slot);
|
||||||
pincache_put (NULL, card->slot, NULL, NULL, NULL);
|
pincache_put (NULL, card->slot, NULL, NULL, NULL, 0);
|
||||||
apdu_close_reader (card->slot);
|
apdu_close_reader (card->slot);
|
||||||
deallocate_card (card);
|
deallocate_card (card);
|
||||||
}
|
}
|
||||||
|
@ -2333,7 +2333,7 @@ set_key_for_pincache (gcry_cipher_hd_t hd)
|
|||||||
* gpg-agent cache it because it is better suited for this. */
|
* gpg-agent cache it because it is better suited for this. */
|
||||||
void
|
void
|
||||||
pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
||||||
const char *pin)
|
const char *pin, unsigned int pinlen)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
assuan_context_t ctx;
|
assuan_context_t ctx;
|
||||||
@ -2341,7 +2341,7 @@ pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
|||||||
gcry_cipher_hd_t cipherhd = NULL;
|
gcry_cipher_hd_t cipherhd = NULL;
|
||||||
char *pinbuf = NULL;
|
char *pinbuf = NULL;
|
||||||
unsigned char *wrappedkey = NULL;
|
unsigned char *wrappedkey = NULL;
|
||||||
size_t pinlen, pinbuflen, wrappedkeylen;
|
size_t pinbuflen, wrappedkeylen;
|
||||||
|
|
||||||
if (!ctrl)
|
if (!ctrl)
|
||||||
{
|
{
|
||||||
@ -2365,7 +2365,7 @@ pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
|||||||
|
|
||||||
if (!ctrl || !ctrl->server_local || !(ctx=ctrl->server_local->assuan_ctx))
|
if (!ctrl || !ctrl->server_local || !(ctx=ctrl->server_local->assuan_ctx))
|
||||||
return;
|
return;
|
||||||
if (pin && !*pin)
|
if (pin && !pinlen)
|
||||||
return; /* Ignore an empty PIN. */
|
return; /* Ignore an empty PIN. */
|
||||||
|
|
||||||
snprintf (line, sizeof line, "%d/%s/%s ",
|
snprintf (line, sizeof line, "%d/%s/%s ",
|
||||||
@ -2378,7 +2378,6 @@ pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
|||||||
{
|
{
|
||||||
/* FIXME: Replace this by OCB mode and use the cache key as
|
/* FIXME: Replace this by OCB mode and use the cache key as
|
||||||
* additional data. */
|
* additional data. */
|
||||||
pinlen = strlen (pin);
|
|
||||||
/* Pad with zeroes (AESWRAP requires multiples of 64 bit but
|
/* Pad with zeroes (AESWRAP requires multiples of 64 bit but
|
||||||
* at least 128 bit data). */
|
* at least 128 bit data). */
|
||||||
pinbuflen = pinlen + 8 - (pinlen % 8);
|
pinbuflen = pinlen + 8 - (pinlen % 8);
|
||||||
|
@ -138,7 +138,7 @@ void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
|
|||||||
const char *serialno, const char *idstr);
|
const char *serialno, const char *idstr);
|
||||||
|
|
||||||
void pincache_put (ctrl_t ctrl, int slot, const char *appname,
|
void pincache_put (ctrl_t ctrl, int slot, const char *appname,
|
||||||
const char *pinref, const char *pin);
|
const char *pinref, const char *pin, unsigned int pinlen);
|
||||||
gpg_error_t pincache_get (ctrl_t ctrl, int slot, const char *appname,
|
gpg_error_t pincache_get (ctrl_t ctrl, int slot, const char *appname,
|
||||||
const char *pinref, char **r_pin);
|
const char *pinref, char **r_pin);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user