mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd: First changes to implement a PIN cache.
* scd/command.c (pincache_put): New. Uses a dummy key for now. (pincache_get): New. * scd/app.c (select_application): Flush the PIN cache. (scd_update_reader_status_file): Ditto. (maybe_switch_app): Call the new prep_reselect function. (app_write_learn_status): Ditto. * scd/app-openpgp.c (cache_pin): New helper to cache a PIN. (verify_chv2): Call it. (verify_chv3): Call it. (clear_chv_status): Call it. (do_change_pin): Call it. * scd/app-common.h (struct app_ctx_s): Add function 'prep_select'. * scd/app-openpgp.c (do_prep_reselect): New stub function. (app_select_openpgp): Set new stub function. * scd/app-piv.c (do_prep_reselect): New stub function. (app_select_piv): Set new stub function. * scd/app-common.h (struct app_ctx_s): Add parameter ctrl to setattr, sign, auth, decipher, and check_pin. Change all implementations and callers to pass such a parameter. -- This is work in progress. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
d5c00354bb
commit
fbf97a7856
@ -136,6 +136,7 @@ struct app_ctx_s {
|
||||
struct app_local_s *app_local; /* Local to the application. */
|
||||
struct {
|
||||
void (*deinit) (app_t app);
|
||||
gpg_error_t (*prep_reselect) (app_t app, ctrl_t ctrl);
|
||||
gpg_error_t (*reselect) (app_t app, ctrl_t ctrl);
|
||||
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags);
|
||||
gpg_error_t (*readcert) (app_t app, const char *certid,
|
||||
@ -144,22 +145,22 @@ struct app_ctx_s {
|
||||
const char *certid, unsigned int flags,
|
||||
unsigned char **pk, size_t *pklen);
|
||||
gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name);
|
||||
gpg_error_t (*setattr) (app_t app, const char *name,
|
||||
gpg_error_t (*setattr) (app_t app, ctrl_t ctrl, const char *name,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen);
|
||||
gpg_error_t (*sign) (app_t app,
|
||||
gpg_error_t (*sign) (app_t app, ctrl_t ctrl,
|
||||
const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen );
|
||||
gpg_error_t (*auth) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*auth) (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
gpg_error_t (*decipher) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*decipher) (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -184,7 +185,7 @@ struct app_ctx_s {
|
||||
const char *chvnostr, unsigned int flags,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
|
||||
gpg_error_t (*check_pin) (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg);
|
||||
gpg_error_t (*with_keygrip) (app_t app, ctrl_t ctrl, int action,
|
||||
|
@ -389,7 +389,7 @@ verify_pin (app_t app,
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
store that in the 3rd argument. */
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -411,6 +411,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
+ the largest OID _prefix above. */
|
||||
int datalen;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20 && indatalen != 16 && indatalen != 32
|
||||
@ -557,6 +559,7 @@ app_select_dinsig (app_t app)
|
||||
{
|
||||
app->apptype = APPTYPE_DINSIG;
|
||||
|
||||
app->fnc.prep_reselect = NULL;
|
||||
app->fnc.reselect = NULL;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
@ -313,6 +313,7 @@ app_select_geldkarte (app_t app)
|
||||
|
||||
app->apptype = APPTYPE_GELDKARTE;
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = NULL;
|
||||
app->fnc.reselect = NULL;
|
||||
|
||||
/* If we don't have a serialno yet construct it from the EF_ID. */
|
||||
|
@ -887,7 +887,7 @@ verify_pin (app_t app, int pwid, const char *desc,
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
store that in the 3rd argument. */
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -907,6 +907,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
+ the largest OID prefix. */
|
||||
size_t datalen;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
switch (indatalen)
|
||||
@ -1022,7 +1024,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
If a PIN is required the PINCB will be used to ask for the PIN; it
|
||||
should return the PIN in an allocated buffer and put it into PIN. */
|
||||
static gpg_error_t
|
||||
do_decipher (app_t app, const char *keyidstr,
|
||||
do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -1034,6 +1036,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
int fid;
|
||||
int kid;
|
||||
|
||||
(void)ctrl;
|
||||
(void)r_info;
|
||||
|
||||
if (!keyidstr || !*keyidstr || !indatalen)
|
||||
@ -1310,7 +1313,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||
|
||||
/* Perform a simple verify operation. KEYIDSTR should be NULL or empty. */
|
||||
static gpg_error_t
|
||||
do_check_pin (app_t app, const char *pwidstr,
|
||||
do_check_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -1319,6 +1322,8 @@ do_check_pin (app_t app, const char *pwidstr,
|
||||
int is_sigg;
|
||||
const char *desc;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
desc = parse_pwidstr (pwidstr, 0, &is_sigg, &pwid);
|
||||
if (!desc)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
@ -1451,6 +1456,7 @@ app_select_nks (app_t app)
|
||||
log_info ("Detected NKS version: %d\n", app->app_local->nks_version);
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = NULL;
|
||||
app->fnc.reselect = NULL;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
@ -249,14 +249,14 @@ struct app_local_s {
|
||||
static unsigned long convert_sig_counter_value (const unsigned char *value,
|
||||
size_t valuelen);
|
||||
static unsigned long get_sig_counter (app_t app);
|
||||
static gpg_error_t do_auth (app_t app, const char *keyidstr,
|
||||
static gpg_error_t do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen);
|
||||
static void parse_algorithm_attribute (app_t app, int keyno);
|
||||
static gpg_error_t change_keyattr_from_string
|
||||
(app_t app,
|
||||
(app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *value, size_t valuelen);
|
||||
@ -2128,6 +2128,25 @@ pin2hash_if_kdf (app_t app, int chvno, char *pinvalue, int *r_pinlen)
|
||||
}
|
||||
|
||||
|
||||
/* Helper to cache a PIN. If PIN is NULL the cache is cleared. */
|
||||
static void
|
||||
cache_pin (app_t app, ctrl_t ctrl, int chvno, const char *pin)
|
||||
{
|
||||
const char *keyref;
|
||||
|
||||
switch (chvno)
|
||||
{
|
||||
case 1: keyref = "1"; break;
|
||||
case 2: keyref = "2"; break;
|
||||
case 3: keyref = "3"; break;
|
||||
default: keyref = NULL; break;
|
||||
}
|
||||
|
||||
if (app->card->cardtype == CARDTYPE_YUBIKEY && keyref)
|
||||
pincache_put (ctrl, app_get_slot (app), "openpgp", keyref, pin);
|
||||
}
|
||||
|
||||
|
||||
/* Verify a CHV either using the pinentry or if possible by
|
||||
using a pinpad. PINCB and PINCB_ARG describe the usual callback
|
||||
for the pinentry. CHVNO must be either 1 or 2. SIGCOUNT is only
|
||||
@ -2264,7 +2283,7 @@ verify_a_chv (app_t app,
|
||||
/* Verify CHV2 if required. Depending on the configuration of the
|
||||
card CHV1 will also be verified. */
|
||||
static gpg_error_t
|
||||
verify_chv2 (app_t app,
|
||||
verify_chv2 (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -2279,6 +2298,7 @@ verify_chv2 (app_t app,
|
||||
if (rc)
|
||||
return rc;
|
||||
app->did_chv2 = 1;
|
||||
cache_pin (app, ctrl, 2, pinvalue);
|
||||
|
||||
if (!app->did_chv1 && !app->force_chv1 && pinvalue)
|
||||
{
|
||||
@ -2295,7 +2315,10 @@ verify_chv2 (app_t app,
|
||||
flush_cache_after_error (app);
|
||||
}
|
||||
else
|
||||
app->did_chv1 = 1;
|
||||
{
|
||||
app->did_chv1 = 1;
|
||||
cache_pin (app, ctrl, 1, pinvalue);
|
||||
}
|
||||
}
|
||||
|
||||
xfree (pinvalue);
|
||||
@ -2347,7 +2370,7 @@ build_enter_admin_pin_prompt (app_t app, char **r_prompt)
|
||||
|
||||
/* Verify CHV3 if required. */
|
||||
static gpg_error_t
|
||||
verify_chv3 (app_t app,
|
||||
verify_chv3 (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -2418,6 +2441,8 @@ verify_chv3 (app_t app,
|
||||
rc = pin2hash_if_kdf (app, 3, pinvalue, &pinlen);
|
||||
if (!rc)
|
||||
rc = iso7816_verify (app_get_slot (app), 0x83, pinvalue, pinlen);
|
||||
if (!rc)
|
||||
cache_pin (app, ctrl, 3, pinvalue);
|
||||
xfree (pinvalue);
|
||||
}
|
||||
|
||||
@ -2429,6 +2454,7 @@ verify_chv3 (app_t app,
|
||||
}
|
||||
app->did_chv3 = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2436,7 +2462,7 @@ verify_chv3 (app_t app,
|
||||
/* Handle the SETATTR operation. All arguments are already basically
|
||||
checked. */
|
||||
static gpg_error_t
|
||||
do_setattr (app_t app, const char *name,
|
||||
do_setattr (app_t app, ctrl_t ctrl, const char *name,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen)
|
||||
@ -2488,15 +2514,16 @@ do_setattr (app_t app, const char *name,
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
|
||||
if (table[idx].special == 3)
|
||||
return change_keyattr_from_string (app, pincb, pincb_arg, value, valuelen);
|
||||
return change_keyattr_from_string (app, ctrl, pincb, pincb_arg,
|
||||
value, valuelen);
|
||||
|
||||
switch (table[idx].need_chv)
|
||||
{
|
||||
case 2:
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
rc = verify_chv2 (app, ctrl, pincb, pincb_arg);
|
||||
break;
|
||||
case 3:
|
||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||
rc = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
break;
|
||||
default:
|
||||
rc = 0;
|
||||
@ -2547,7 +2574,6 @@ do_writecert (app_t app, ctrl_t ctrl,
|
||||
void *pincb_arg,
|
||||
const unsigned char *certdata, size_t certdatalen)
|
||||
{
|
||||
(void)ctrl;
|
||||
if (strcmp (certidstr, "OPENPGP.3"))
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
if (!certdata || !certdatalen)
|
||||
@ -2556,16 +2582,19 @@ do_writecert (app_t app, ctrl_t ctrl,
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
if (certdatalen > app->app_local->extcap.max_certlen_3)
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata, certdatalen);
|
||||
return do_setattr (app, ctrl, "CERT-3", pincb, pincb_arg,
|
||||
certdata, certdatalen);
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
clear_chv_status (app_t app, int chvno)
|
||||
clear_chv_status (app_t app, ctrl_t ctrl, int chvno)
|
||||
{
|
||||
unsigned char apdu[4];
|
||||
gpg_error_t err;
|
||||
|
||||
cache_pin (app, ctrl, chvno, NULL);
|
||||
|
||||
if (!app->app_local->extcap.is_v2)
|
||||
return GPG_ERR_UNSUPPORTED_OPERATION;
|
||||
|
||||
@ -2634,8 +2663,6 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
int pinlen0 = 0;
|
||||
int pinlen = 0;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (digitp (chvnostr))
|
||||
chvno = atoi (chvnostr);
|
||||
else if (!ascii_strcasecmp (chvnostr, "OPENPGP.1"))
|
||||
@ -2652,7 +2679,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
pininfo.minlen = minlen;
|
||||
|
||||
if ((flags & APP_CHANGE_FLAG_CLEAR))
|
||||
return clear_chv_status (app, chvno);
|
||||
return clear_chv_status (app, ctrl, chvno);
|
||||
|
||||
if (reset_mode && chvno == 3)
|
||||
{
|
||||
@ -2667,8 +2694,9 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
if (reset_mode || chvno == 3)
|
||||
{
|
||||
/* We always require that the PIN is entered. */
|
||||
cache_pin (app, ctrl, 3, NULL);
|
||||
app->did_chv3 = 0;
|
||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||
rc = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (rc)
|
||||
goto leave;
|
||||
}
|
||||
@ -2678,10 +2706,12 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
value, thus we enforce it here. */
|
||||
int save_force = app->force_chv1;
|
||||
|
||||
cache_pin (app, ctrl, 1, NULL);
|
||||
cache_pin (app, ctrl, 2, NULL);
|
||||
app->force_chv1 = 0;
|
||||
app->did_chv1 = 0;
|
||||
app->did_chv2 = 0;
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
rc = verify_chv2 (app, ctrl, pincb, pincb_arg);
|
||||
app->force_chv1 = save_force;
|
||||
if (rc)
|
||||
goto leave;
|
||||
@ -2707,7 +2737,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
/* To reset a PIN the Admin PIN is required. */
|
||||
use_pinpad = 0;
|
||||
app->did_chv3 = 0;
|
||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||
rc = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
@ -3263,7 +3293,8 @@ build_ecc_privkey_template (app_t app, int keyno,
|
||||
/* Helper for do_writekley to change the size of a key. Not ethat
|
||||
this deletes the entire key without asking. */
|
||||
static gpg_error_t
|
||||
change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
|
||||
change_keyattr (app_t app, ctrl_t ctrl,
|
||||
int keyno, const unsigned char *buf, size_t buflen,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -3272,7 +3303,7 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
|
||||
assert (keyno >=0 && keyno <= 2);
|
||||
|
||||
/* Prepare for storing the key. */
|
||||
err = verify_chv3 (app, pincb, pincb_arg);
|
||||
err = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -3292,7 +3323,7 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
|
||||
change_rsa_keyattr (app_t app, ctrl_t ctrl, int keyno, unsigned int nbits,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -3332,7 +3363,7 @@ change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
|
||||
buflen = 6;
|
||||
}
|
||||
|
||||
err = change_keyattr (app, keyno, buf, buflen, pincb, pincb_arg);
|
||||
err = change_keyattr (app, ctrl, keyno, buf, buflen, pincb, pincb_arg);
|
||||
xfree (relptr);
|
||||
}
|
||||
|
||||
@ -3346,7 +3377,7 @@ change_rsa_keyattr (app_t app, int keyno, unsigned int nbits,
|
||||
ECC: "--force <key> <algo> <curvename>"
|
||||
*/
|
||||
static gpg_error_t
|
||||
change_keyattr_from_string (app_t app,
|
||||
change_keyattr_from_string (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *value, size_t valuelen)
|
||||
@ -3390,7 +3421,7 @@ change_keyattr_from_string (app_t app,
|
||||
else if (nbits > 4096)
|
||||
err = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
else
|
||||
err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
|
||||
err = change_rsa_keyattr (app, ctrl, keyno, nbits, pincb, pincb_arg);
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA)
|
||||
@ -3417,7 +3448,7 @@ change_keyattr_from_string (app_t app,
|
||||
/* We have enough room at STRING. */
|
||||
string[0] = algo;
|
||||
memcpy (string+1, oidbuf+1, oid_len-1);
|
||||
err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
|
||||
err = change_keyattr (app, ctrl,keyno, string, oid_len, pincb, pincb_arg);
|
||||
gcry_mpi_release (oid);
|
||||
}
|
||||
else
|
||||
@ -3430,7 +3461,8 @@ change_keyattr_from_string (app_t app,
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
rsa_writekey (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg, int keyno,
|
||||
const unsigned char *buf, size_t buflen, int depth)
|
||||
{
|
||||
@ -3556,7 +3588,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
&& app->app_local->extcap.algo_attr_change)
|
||||
{
|
||||
/* Try to switch the key to a new length. */
|
||||
err = change_rsa_keyattr (app, keyno, nbits, pincb, pincb_arg);
|
||||
err = change_rsa_keyattr (app, ctrl, keyno, nbits, pincb, pincb_arg);
|
||||
if (!err)
|
||||
maxbits = app->app_local->keyattr[keyno].rsa.n_bits;
|
||||
}
|
||||
@ -3658,7 +3690,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
goto leave;
|
||||
|
||||
/* Prepare for storing the key. */
|
||||
err = verify_chv3 (app, pincb, pincb_arg);
|
||||
err = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -3714,7 +3746,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
assert (tp - template == template_len);
|
||||
|
||||
/* Prepare for storing the key. */
|
||||
err = verify_chv3 (app, pincb, pincb_arg);
|
||||
err = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -3742,7 +3774,8 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
ecc_writekey (app_t app, ctrl_t ctrl,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg, int keyno,
|
||||
const unsigned char *buf, size_t buflen, int depth)
|
||||
{
|
||||
@ -3939,7 +3972,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
}
|
||||
keyattr[0] = algo;
|
||||
memcpy (keyattr+1, oidbuf+1, oid_len-1);
|
||||
err = change_keyattr (app, keyno, keyattr, oid_len, pincb, pincb_arg);
|
||||
err = change_keyattr (app, ctrl, keyno,
|
||||
keyattr, oid_len, pincb, pincb_arg);
|
||||
xfree (keyattr);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -3977,7 +4011,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
goto leave;
|
||||
|
||||
/* Prepare for storing the key. */
|
||||
err = verify_chv3 (app, pincb, pincb_arg);
|
||||
err = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (err)
|
||||
{
|
||||
xfree (template);
|
||||
@ -4012,6 +4046,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the WRITEKEY command for OpenPGP. This function expects a
|
||||
canonical encoded S-expression with the secret key in KEYDATA and
|
||||
its length (for assertions) in KEYDATALEN. KEYID needs to be the
|
||||
@ -4075,9 +4110,9 @@ do_writekey (app_t app, ctrl_t ctrl,
|
||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||
goto leave;
|
||||
if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
|
||||
err = rsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0)
|
||||
err = ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
else
|
||||
{
|
||||
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||
@ -4152,7 +4187,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, const char *keytype,
|
||||
}
|
||||
|
||||
/* Prepare for key generation by verifying the Admin PIN. */
|
||||
err = verify_chv3 (app, pincb, pincb_arg);
|
||||
err = verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -4371,7 +4406,7 @@ check_keyidstr (app_t app, const char *keyidstr, int keyno)
|
||||
operation to the auth command.
|
||||
*/
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -4485,7 +4520,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
/* Redirect to the AUTH command if asked to. */
|
||||
if (use_auth)
|
||||
{
|
||||
return do_auth (app, "OPENPGP.3", pincb, pincb_arg,
|
||||
return do_auth (app, ctrl, "OPENPGP.3", pincb, pincb_arg,
|
||||
data, datalen,
|
||||
outdata, outdatalen);
|
||||
}
|
||||
@ -4506,6 +4541,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
return rc;
|
||||
|
||||
app->did_chv1 = 1;
|
||||
if (!app->force_chv1)
|
||||
cache_pin (app, ctrl, 1, pinvalue);
|
||||
|
||||
/* For cards with versions < 2 we want to keep CHV1 and CHV2 in
|
||||
sync, thus we verify CHV2 here using the given PIN. Cards
|
||||
@ -4525,6 +4562,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
return rc;
|
||||
}
|
||||
app->did_chv2 = 1;
|
||||
cache_pin (app, ctrl, 2, pinvalue);
|
||||
}
|
||||
xfree (pinvalue);
|
||||
}
|
||||
@ -4545,9 +4583,12 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
rc = iso7816_compute_ds (app_get_slot (app), exmode, data, datalen, le_value,
|
||||
outdata, outdatalen);
|
||||
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
|
||||
clear_chv_status (app, 1);
|
||||
clear_chv_status (app, ctrl, 1);
|
||||
else if (!rc && app->force_chv1)
|
||||
app->did_chv1 = 0;
|
||||
{
|
||||
app->did_chv1 = 0;
|
||||
cache_pin (app, ctrl, 1, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -4563,7 +4604,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
not match the one required for the requested action (e.g. the
|
||||
serial number does not match). */
|
||||
static gpg_error_t
|
||||
do_auth (app_t app, const char *keyidstr,
|
||||
do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -4604,7 +4645,7 @@ do_auth (app_t app, const char *keyidstr,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
rc = verify_chv2 (app, ctrl, pincb, pincb_arg);
|
||||
if (!rc)
|
||||
{
|
||||
int exmode, le_value;
|
||||
@ -4625,14 +4666,14 @@ do_auth (app_t app, const char *keyidstr,
|
||||
indata, indatalen, le_value,
|
||||
outdata, outdatalen);
|
||||
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
|
||||
clear_chv_status (app, 1);
|
||||
clear_chv_status (app, ctrl, 1);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
do_decipher (app_t app, const char *keyidstr,
|
||||
do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -4659,7 +4700,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = verify_chv2 (app, pincb, pincb_arg);
|
||||
rc = verify_chv2 (app, ctrl, pincb, pincb_arg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -4845,7 +4886,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
}
|
||||
}
|
||||
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
|
||||
clear_chv_status (app, 1);
|
||||
clear_chv_status (app, ctrl, 1);
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_CARD /* actual SW is 0x640a */
|
||||
&& app->app_local->manufacturer == 5
|
||||
@ -4870,7 +4911,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
the "[CHV3]" being a literal string: The Admin Pin is checked if
|
||||
and only if the retry counter is still at 3. */
|
||||
static gpg_error_t
|
||||
do_check_pin (app_t app, const char *keyidstr,
|
||||
do_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
@ -4923,12 +4964,13 @@ do_check_pin (app_t app, const char *keyidstr,
|
||||
}
|
||||
|
||||
app->did_chv3 = 0; /* Force verification. */
|
||||
return verify_chv3 (app, pincb, pincb_arg);
|
||||
return verify_chv3 (app, ctrl, pincb, pincb_arg);
|
||||
}
|
||||
else
|
||||
return verify_chv2 (app, pincb, pincb_arg);
|
||||
return verify_chv2 (app, ctrl, pincb, pincb_arg);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
send_keyinfo_if_available (app_t app, ctrl_t ctrl, char *serial,
|
||||
int data, int i)
|
||||
@ -5225,6 +5267,23 @@ parse_algorithm_attribute (app_t app, int keyno)
|
||||
}
|
||||
|
||||
|
||||
/* Prepare a reselect of another application. This is used by cards
|
||||
* which support on-the-fly switching between applications. The
|
||||
* function is called to give us a chance to save state for a future
|
||||
* reselect of us again. */
|
||||
static gpg_error_t
|
||||
do_prep_reselect (app_t app, ctrl_t ctrl)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
(void)app;
|
||||
(void)ctrl;
|
||||
|
||||
err = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Reselect the application. This is used by cards which support
|
||||
* on-the-fly switching between applications. */
|
||||
static gpg_error_t
|
||||
@ -5236,7 +5295,7 @@ do_reselect (app_t app, ctrl_t ctrl)
|
||||
|
||||
/* An extra check which should not be necessary because the caller
|
||||
* should have made sure that a re-select is only called for
|
||||
* approriate cards. */
|
||||
* appropriate cards. */
|
||||
if (app->card->cardtype != CARDTYPE_YUBIKEY)
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
@ -5403,6 +5462,7 @@ app_select_openpgp (app_t app)
|
||||
dump_all_do (slot);
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = do_prep_reselect;
|
||||
app->fnc.reselect = do_reselect;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
@ -2853,7 +2853,7 @@ micardo_mse (app_t app, unsigned short fid)
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
store that as the 3rd argument. */
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -2876,6 +2876,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
int no_data_padding = 0; /* True if the card want the data without padding.*/
|
||||
int mse_done = 0; /* Set to true if the MSE has been done. */
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20 && indatalen != 16 && indatalen != 35 && indatalen != 36)
|
||||
@ -3208,7 +3210,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
must match the criteria used for the attribute $AUTHKEYID. See
|
||||
do_sign for calling conventions; there is no HASHALGO, though. */
|
||||
static gpg_error_t
|
||||
do_auth (app_t app, const char *keyidstr,
|
||||
do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -3231,7 +3233,7 @@ do_auth (app_t app, const char *keyidstr,
|
||||
}
|
||||
|
||||
algo = indatalen == 36? MD_USER_TLS_MD5SHA1 : GCRY_MD_SHA1;
|
||||
return do_sign (app, keyidstr, algo, pincb, pincb_arg,
|
||||
return do_sign (app, ctrl, keyidstr, algo, pincb, pincb_arg,
|
||||
indata, indatalen, outdata, outdatalen);
|
||||
}
|
||||
|
||||
@ -3415,6 +3417,7 @@ app_select_p15 (app_t app)
|
||||
}
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = NULL;
|
||||
app->fnc.reselect = NULL;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
@ -1068,7 +1068,7 @@ set_adm_key (app_t app, const unsigned char *value, size_t valuelen)
|
||||
/* Handle the SETATTR operation. All arguments are already basically
|
||||
* checked. */
|
||||
static gpg_error_t
|
||||
do_setattr (app_t app, const char *name,
|
||||
do_setattr (app_t app, ctrl_t ctrl, const char *name,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const unsigned char *value, size_t valuelen)
|
||||
@ -1089,6 +1089,7 @@ do_setattr (app_t app, const char *name,
|
||||
};
|
||||
int idx;
|
||||
|
||||
(void)ctrl;
|
||||
(void)pincb;
|
||||
(void)pincb_arg;
|
||||
|
||||
@ -2075,12 +2076,14 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||
/* Perform a simple verify operation for the PIN specified by PWIDSTR.
|
||||
* For valid values see do_change_chv. */
|
||||
static gpg_error_t
|
||||
do_check_chv (app_t app, const char *pwidstr,
|
||||
do_check_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg)
|
||||
{
|
||||
int keyref;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
keyref = parse_chv_keyref (pwidstr);
|
||||
if (keyref == -1)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
@ -2100,7 +2103,7 @@ do_check_chv (app_t app, const char *pwidstr,
|
||||
* OID to the indata or checks that it is consistent.
|
||||
*/
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata_arg, size_t indatalen,
|
||||
@ -2121,6 +2124,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
size_t apdudatalen;
|
||||
int force_verify;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -2384,13 +2389,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
* whereas SIGN may accept a plain digest and does the padding if
|
||||
* needed. This is also the reason why SIGN takes a hashalgo. */
|
||||
static gpg_error_t
|
||||
do_auth (app_t app, const char *keyidstr,
|
||||
do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **r_outdata, size_t *r_outdatalen)
|
||||
{
|
||||
return do_sign (app, keyidstr, 0, pincb, pincb_arg, indata, indatalen,
|
||||
return do_sign (app, ctrl, keyidstr, 0, pincb, pincb_arg, indata, indatalen,
|
||||
r_outdata, r_outdatalen);
|
||||
}
|
||||
|
||||
@ -2398,7 +2403,7 @@ do_auth (app_t app, const char *keyidstr,
|
||||
/* Decrypt the data in (INDATA,INDATALEN) and on success store the
|
||||
* mallocated result at (R_OUTDATA,R_OUTDATALEN). */
|
||||
static gpg_error_t
|
||||
do_decipher (app_t app, const char *keyidstr,
|
||||
do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata_arg, size_t indatalen,
|
||||
@ -2418,6 +2423,8 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
unsigned char *apdudata = NULL;
|
||||
size_t apdudatalen;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -3431,6 +3438,23 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action,
|
||||
}
|
||||
|
||||
|
||||
/* Prepare a reselect of another application. This is used by cards
|
||||
* which support on-the-fly switching between applications. The
|
||||
* function is called to give us a chance to save state for a future
|
||||
* reselect of us again. */
|
||||
static gpg_error_t
|
||||
do_prep_reselect (app_t app, ctrl_t ctrl)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
(void)app;
|
||||
(void)ctrl;
|
||||
|
||||
err = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Reselect the application. This is used by cards which support
|
||||
* on-the-fly switching between applications. */
|
||||
static gpg_error_t
|
||||
@ -3442,7 +3466,7 @@ do_reselect (app_t app, ctrl_t ctrl)
|
||||
|
||||
/* An extra check which should not be necessary because the caller
|
||||
* should have made sure that a re-select is only called for
|
||||
* approriate cards. */
|
||||
* appropriate cards. */
|
||||
if (!app->app_local->flags.yubikey)
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
@ -3535,6 +3559,7 @@ app_select_piv (app_t app)
|
||||
dump_all_do (slot);
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = do_prep_reselect;
|
||||
app->fnc.reselect = do_reselect;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
@ -1773,7 +1773,7 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
the ECDSA signature in X9.62 format (SEQ/INT(r)/INT(s))
|
||||
*/
|
||||
static gpg_error_t
|
||||
do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -1810,6 +1810,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
unsigned char algoid;
|
||||
int sw;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
@ -1901,7 +1903,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
must match the criteria used for the attribute $AUTHKEYID. See
|
||||
do_sign for calling conventions; there is no HASHALGO, though. */
|
||||
static gpg_error_t
|
||||
do_auth (app_t app, const char *keyidstr,
|
||||
do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -1924,7 +1926,7 @@ do_auth (app_t app, const char *keyidstr,
|
||||
}
|
||||
|
||||
algo = indatalen == 36? MD_USER_TLS_MD5SHA1 : GCRY_MD_SHA1;
|
||||
return do_sign (app, keyidstr, algo, pincb, pincb_arg,
|
||||
return do_sign (app, ctrl, keyidstr, algo, pincb, pincb_arg,
|
||||
indata, indatalen, outdata, outdatalen);
|
||||
}
|
||||
|
||||
@ -1973,7 +1975,7 @@ strip_PKCS15_padding(unsigned char *src, int srclen, unsigned char **dst,
|
||||
/* Decrypt a PKCS#1 V1.5 formatted cryptogram using the referenced
|
||||
key. */
|
||||
static gpg_error_t
|
||||
do_decipher (app_t app, const char *keyidstr,
|
||||
do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
@ -1988,6 +1990,8 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
size_t p1blklen;
|
||||
int sw;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
if (!keyidstr || !*keyidstr || !indatalen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
@ -2069,6 +2073,7 @@ app_select_sc_hsm (app_t app)
|
||||
goto leave;
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.prep_reselect = NULL;
|
||||
app->fnc.reselect = NULL;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
|
60
scd/app.c
60
scd/app.c
@ -663,7 +663,10 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
|
||||
}
|
||||
|
||||
if (err)
|
||||
apdu_close_reader (slot);
|
||||
{
|
||||
pincache_put (ctrl, slot, NULL, NULL, NULL);
|
||||
apdu_close_reader (slot);
|
||||
}
|
||||
}
|
||||
|
||||
apdu_dev_list_finish (l);
|
||||
@ -1094,7 +1097,7 @@ app_get_serialno (app_t app)
|
||||
/* Check that the card has been initialized and whether we need to
|
||||
* switch to another application on the same card. Switching means
|
||||
* that the new active app will be moved to the head of the list at
|
||||
* CARD->app. Thus function must be called with the card lock held. */
|
||||
* CARD->app. This function must be called with the card lock held. */
|
||||
static gpg_error_t
|
||||
maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
|
||||
{
|
||||
@ -1165,6 +1168,20 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
|
||||
strapptype (app->apptype));
|
||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
/* Give the current app a chance to save some state before another
|
||||
* app is selected. We ignore errors here because that state saving
|
||||
* (e.g. putting PINs into a cache) is a convenience feature and not
|
||||
* required to always work. */
|
||||
if (app_prev && app_prev->fnc.prep_reselect)
|
||||
{
|
||||
err = app_prev->fnc.prep_reselect (app_prev, ctrl);
|
||||
if (err)
|
||||
log_info ("card %d: preparing re-select failed for '%s': %s\n",
|
||||
card->slot, xstrapptype (app_prev), gpg_strerror (err));
|
||||
err = 0;
|
||||
}
|
||||
|
||||
err = app->fnc.reselect (app, ctrl);
|
||||
if (err)
|
||||
{
|
||||
@ -1220,8 +1237,8 @@ write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
|
||||
gpg_error_t
|
||||
app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
|
||||
{
|
||||
gpg_error_t err, err2;
|
||||
app_t app;
|
||||
gpg_error_t err, err2, tmperr;
|
||||
app_t app, last_app;
|
||||
int any_reselect = 0;
|
||||
|
||||
if (!card)
|
||||
@ -1246,18 +1263,37 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
|
||||
* loop over all other apps which are capable of a reselect
|
||||
* and finally reselect the first app again. Note that we
|
||||
* did the learn for the currently selected card above. */
|
||||
app = card->app;
|
||||
app = last_app = card->app;
|
||||
for (app = app->next; app && !err; app = app->next)
|
||||
if (app->fnc.reselect)
|
||||
{
|
||||
if (last_app && last_app->fnc.prep_reselect)
|
||||
{
|
||||
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
||||
if (tmperr)
|
||||
log_info ("card %d: preparing re-select failed for '%s'"
|
||||
": %s\n", card->slot, xstrapptype (last_app),
|
||||
gpg_strerror (tmperr));
|
||||
}
|
||||
any_reselect = 1;
|
||||
err = app->fnc.reselect (app, ctrl);
|
||||
if (!err)
|
||||
err = write_learn_status_core (NULL, app, ctrl, flags);
|
||||
{
|
||||
last_app = app;
|
||||
err = write_learn_status_core (NULL, app, ctrl, flags);
|
||||
}
|
||||
}
|
||||
app = card->app;
|
||||
if (any_reselect)
|
||||
{
|
||||
if (last_app && last_app->fnc.prep_reselect)
|
||||
{
|
||||
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
||||
if (tmperr)
|
||||
log_info ("card %d: preparing re-select failed for '%s'"
|
||||
": %s\n", card->slot, xstrapptype (last_app),
|
||||
gpg_strerror (tmperr));
|
||||
}
|
||||
err2 = app->fnc.reselect (app, ctrl);
|
||||
if (err2)
|
||||
{
|
||||
@ -1424,7 +1460,7 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
|
||||
if (DBG_APP)
|
||||
log_debug ("slot %d app %s: calling setattr(%s)\n",
|
||||
card->slot, xstrapptype (card->app), name);
|
||||
err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
|
||||
err = card->app->fnc.setattr (card->app, ctrl, name, pincb, pincb_arg,
|
||||
value, valuelen);
|
||||
}
|
||||
|
||||
@ -1460,7 +1496,7 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
if (DBG_APP)
|
||||
log_debug ("slot %d app %s: calling sign(%s)\n",
|
||||
card->slot, xstrapptype (card->app), keyidstr);
|
||||
err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
|
||||
err = card->app->fnc.sign (card->app, ctrl, keyidstr, hashalgo,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
@ -1501,7 +1537,7 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
|
||||
if (DBG_APP)
|
||||
log_debug ("slot %d app %s: calling auth(%s)\n",
|
||||
card->slot, xstrapptype (card->app), keyidstr);
|
||||
err = card->app->fnc.auth (card->app, keyidstr,
|
||||
err = card->app->fnc.auth (card->app, ctrl, keyidstr,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
@ -1544,7 +1580,7 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
|
||||
if (DBG_APP)
|
||||
log_debug ("slot %d app %s: calling decipher(%s)\n",
|
||||
card->slot, xstrapptype (card->app), keyidstr);
|
||||
err = card->app->fnc.decipher (card->app, keyidstr,
|
||||
err = card->app->fnc.decipher (card->app, ctrl, keyidstr,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen,
|
||||
@ -1750,7 +1786,8 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
|
||||
if (DBG_APP)
|
||||
log_debug ("slot %d app %s: calling check_pin(%s)\n",
|
||||
card->slot, xstrapptype (card->app), keyidstr);
|
||||
err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
|
||||
err = card->app->fnc.check_pin (card->app, ctrl, keyidstr,
|
||||
pincb, pincb_arg);
|
||||
}
|
||||
|
||||
unlock_card (card);
|
||||
@ -1863,6 +1900,7 @@ scd_update_reader_status_file (void)
|
||||
if (status == 0)
|
||||
{
|
||||
log_debug ("Removal of a card: %d\n", card->slot);
|
||||
pincache_put (NULL, card->slot, NULL, NULL, NULL);
|
||||
apdu_close_reader (card->slot);
|
||||
deallocate_card (card);
|
||||
}
|
||||
|
190
scd/command.c
190
scd/command.c
@ -42,7 +42,8 @@
|
||||
#include "../common/asshelp.h"
|
||||
#include "../common/server-help.h"
|
||||
|
||||
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
|
||||
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN. That
|
||||
* length needs to small compared to the maximum Assuan line length. */
|
||||
#define MAXLEN_PIN 100
|
||||
|
||||
/* Maximum allowed size of key data as used in inquiries. */
|
||||
@ -281,7 +282,7 @@ static const char hlp_serialno[] =
|
||||
"selected and an error is returned if no such card available.\n"
|
||||
"\n"
|
||||
"If --all is given, all possible other applications of the card are\n"
|
||||
"will also be selected for on-the-fly swicthing.\n"
|
||||
"also selected to prepare for \"LEARN --force --multi\".\n"
|
||||
"\n"
|
||||
"If APPTYPE is given, an application of that type is selected and an\n"
|
||||
"error is returned if the application is not supported or available.\n"
|
||||
@ -2241,6 +2242,191 @@ send_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
|
||||
}
|
||||
|
||||
|
||||
/* Store the PIN in the PIN cache. The key to identify the PIN
|
||||
* consists of (SLOT,APPNAME,PINREF). If PIN is NULL the PIN stored
|
||||
* under the given key is cleared. If APPNAME and PINREF are NULL the
|
||||
* entire PIN cache for SLOT is cleared. If SLOT is -1 the entire PIN
|
||||
* cache is cleared. We do no use an scdaemon internal cache but let
|
||||
* gpg-agent cache because it is better suited for this. */
|
||||
void
|
||||
pincache_put (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
||||
const char *pin)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
char line[950];
|
||||
gcry_cipher_hd_t cipherhd = NULL;
|
||||
char *pinbuf = NULL;
|
||||
unsigned char *wrappedkey = NULL;
|
||||
size_t pinlen, pinbuflen, wrappedkeylen;
|
||||
|
||||
if (!ctrl)
|
||||
{
|
||||
/* No CTRL object provided. We could pick an arbitrary
|
||||
* connection and send the status to that one. However, such a
|
||||
* connection is inlikley to wait for a respinse from use and
|
||||
* thus it would at best be read as a response to the next
|
||||
* command send to us. That is not good because it may clog up
|
||||
* our connection. Thus we better don't do that. A better will
|
||||
* be to queue this up and let the agent poll for general status
|
||||
* messages. */
|
||||
/* struct server_local_s *sl; */
|
||||
/* for (sl=session_list; sl; sl = sl->next_session) */
|
||||
/* if (sl->ctrl_backlink && sl->ctrl_backlink->server_local */
|
||||
/* && sl->ctrl_backlink->server_local->assuan_ctx) */
|
||||
/* { */
|
||||
/* ctrl = sl->ctrl_backlink; */
|
||||
/* break; */
|
||||
/* } */
|
||||
}
|
||||
|
||||
if (!ctrl || !ctrl->server_local || !(ctx=ctrl->server_local->assuan_ctx))
|
||||
return;
|
||||
if (pin && !*pin)
|
||||
return; /* Ignore an empty PIN. */
|
||||
|
||||
snprintf (line, sizeof line, "%d/%s/%s ",
|
||||
slot, appname? appname:"-", pinref? pinref:"-");
|
||||
|
||||
/* Without an APPNAME etc or without a PIN we clear the cache and
|
||||
* thus there is no need to send the pin - even if the caller
|
||||
* accidentially passed a pin. */
|
||||
if (pin && slot != -1 && appname && pinref)
|
||||
{
|
||||
pinlen = strlen (pin);
|
||||
if ((pinlen % 8))
|
||||
{
|
||||
/* Pad with zeroes (AESWRAP requires multiples of 64 bit but
|
||||
* at least 128 bit data). */
|
||||
pinbuflen = pinlen + 8 - (pinlen % 8);
|
||||
if (pinbuflen < 16)
|
||||
pinbuflen = 16;
|
||||
pinbuf = xtrycalloc_secure (1, pinbuflen);
|
||||
if (!pinbuf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
memcpy (pinbuf, pin, pinlen);
|
||||
pinlen = pinbuflen;
|
||||
pin = pinbuf;
|
||||
}
|
||||
|
||||
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
|
||||
GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (cipherhd, "1234567890123456", 16);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
wrappedkeylen = pinlen + 8;
|
||||
wrappedkey = xtrymalloc (wrappedkeylen);
|
||||
if (!wrappedkey)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen,
|
||||
pin, pinlen);
|
||||
if (err)
|
||||
goto leave;
|
||||
gcry_cipher_close (cipherhd);
|
||||
cipherhd = NULL;
|
||||
if (strlen (line) + 2*wrappedkeylen + 1 >= sizeof line)
|
||||
{
|
||||
log_error ("%s: PIN or pinref string too long - ignored", __func__);
|
||||
goto leave;
|
||||
}
|
||||
bin2hex (wrappedkey, wrappedkeylen, line + strlen (line));
|
||||
}
|
||||
|
||||
send_status_direct (ctrl, "PINCACHE_PUT", line);
|
||||
|
||||
leave:
|
||||
xfree (pinbuf);
|
||||
xfree (wrappedkey);
|
||||
gcry_cipher_close (cipherhd);
|
||||
if (err)
|
||||
log_error ("%s: error caching PIN: %s\n", __func__, gpg_strerror (err));
|
||||
}
|
||||
|
||||
|
||||
/* Ask the agent for a cached PIN for the tuple (SLOT,APPNAME,PINREF).
|
||||
* Returns on success and stores the PIN at R_PIN; the caller needs to
|
||||
* wipe(!) and then free that value. On error NULL is stored at
|
||||
* R_PIN and an error code returned. Common error codes are:
|
||||
* GPG_ERR_NOT_SUPPORTED - Client does not support the PIN cache
|
||||
* GPG_ERR_NO_DATA - No PIN cached for the given key tuple
|
||||
*/
|
||||
gpg_error_t
|
||||
pincache_get (ctrl_t ctrl, int slot, const char *appname, const char *pinref,
|
||||
char **r_pin)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
char command[512];
|
||||
unsigned char *value = NULL;
|
||||
size_t valuelen;
|
||||
unsigned char *wrappedkey = NULL;
|
||||
size_t wrappedkeylen;
|
||||
gcry_cipher_hd_t cipherhd = NULL;
|
||||
|
||||
if (slot == -1 || !appname || !pinref || !r_pin)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
goto leave;
|
||||
}
|
||||
if (!ctrl || !ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
|
||||
{
|
||||
err = set_error (GPG_ERR_USE_CONDITIONS, "called w/o assuan context");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
snprintf (command, sizeof command, "PINCACHE_GET %d/%s/%s",
|
||||
slot, appname? appname:"-", pinref? pinref:"-");
|
||||
|
||||
err = assuan_inquire (ctx, command, &wrappedkey, &wrappedkeylen,
|
||||
MAXLEN_PIN+24);
|
||||
if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
|
||||
err = set_error (GPG_ERR_NOT_SUPPORTED,
|
||||
"client does not feature a PIN cache");
|
||||
else if (!err && (!wrappedkey || wrappedkeylen < 24))
|
||||
err = set_error (GPG_ERR_INV_LENGTH, "received too short cryptogram");
|
||||
else if (!err)
|
||||
{
|
||||
valuelen = wrappedkeylen - 8;
|
||||
value = xtrymalloc_secure (valuelen);
|
||||
if (!value)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
|
||||
GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||
if (!err)
|
||||
err = gcry_cipher_setkey (cipherhd, "1234567890123456", 16);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
err = gcry_cipher_decrypt (cipherhd, value, valuelen,
|
||||
wrappedkey, wrappedkeylen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
*r_pin = value;
|
||||
value = NULL;
|
||||
}
|
||||
|
||||
leave:
|
||||
gcry_cipher_close (cipherhd);
|
||||
xfree (wrappedkey);
|
||||
xfree (value);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
popup_prompt (void *opaque, int on)
|
||||
{
|
||||
|
@ -137,6 +137,11 @@ gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword,
|
||||
void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
|
||||
const char *serialno, const char *idstr);
|
||||
|
||||
void pincache_put (ctrl_t ctrl, int slot, const char *appname,
|
||||
const char *pinref, const char *pin);
|
||||
gpg_error_t pincache_get (ctrl_t ctrl, int slot, const char *appname,
|
||||
const char *pinref, char **r_pin);
|
||||
|
||||
void popup_prompt (void *opaque, int on);
|
||||
|
||||
/* Take care: this function assumes that CARD is locked. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user