Leniently interpret the ISO7816 return codes in card-piv.c

This adds support for the Yubikey NEO. I'm not sure whether it breaks
the specification, or follows some other version of the spec, but in my
testing it returns SW1=0x63, SW2=0x0N for N PIN tries remaining.
Ignoring the top nibble seems a harmless change to the behaviour to
support this device.
This commit is contained in:
Nicholas Wilson 2015-08-23 22:33:50 +01:00 committed by Nicholas Wilson
parent 5a11d0e2fd
commit 2897e6fb5c
1 changed files with 23 additions and 1 deletions

View File

@ -2895,7 +2895,7 @@ static int piv_init(sc_card_t *card)
_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
card->caps |= SC_CARD_CAP_RNG;
card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
/*
* 800-73-3 cards may have a history object and/or a discovery object
@ -2912,6 +2912,27 @@ static int piv_init(sc_card_t *card)
}
static int piv_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2)
{
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
const u8 *yubikey_neo_atr =
(const u8*)"\x3B\xFC\x13\x00\x00\x81\x31\xFE\x15\x59\x75\x62\x69\x6B\x65\x79\x4E\x45\x4F\x72\x33\xE1";
if (card->atr.len != 22 || memcmp(card->atr.value, yubikey_neo_atr, 22) != 0)
return iso_drv->ops->check_sw(card, sw1, sw2);
/* Handle here the Yubikey NEO, which returns 0x0X rather than 0xCX to
* indicate the number of remaining PIN retries. Perhaps they misread the
* spec and thought 0xCX meant "clear" or "don't care", not a literal 0xC! */
if (sw1 == 0x63U && (sw2 & ~0x0fU) == 0x00U && sw2 != 0) {
sc_log(card->ctx, "Verification failed (remaining tries: %d)", (sw2 & 0x0f));
return SC_ERROR_PIN_CODE_INCORRECT;
}
return iso_drv->ops->check_sw(card, sw1, sw2);
}
static int piv_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
@ -2952,6 +2973,7 @@ static struct sc_card_driver * sc_get_driver(void)
piv_ops.restore_security_env = piv_restore_security_env;
piv_ops.compute_signature = piv_compute_signature;
piv_ops.decipher = piv_decipher;
piv_ops.check_sw = piv_check_sw;
piv_ops.card_ctl = piv_card_ctl;
piv_ops.pin_cmd = piv_pin_cmd;