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:
parent
5a11d0e2fd
commit
2897e6fb5c
|
@ -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, 256, flags, ext_flags, NULL);
|
||||||
_sc_card_add_ec_alg(card, 384, 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
|
* 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,
|
static int piv_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
|
||||||
int *tries_left)
|
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.restore_security_env = piv_restore_security_env;
|
||||||
piv_ops.compute_signature = piv_compute_signature;
|
piv_ops.compute_signature = piv_compute_signature;
|
||||||
piv_ops.decipher = piv_decipher;
|
piv_ops.decipher = piv_decipher;
|
||||||
|
piv_ops.check_sw = piv_check_sw;
|
||||||
piv_ops.card_ctl = piv_card_ctl;
|
piv_ops.card_ctl = piv_card_ctl;
|
||||||
piv_ops.pin_cmd = piv_pin_cmd;
|
piv_ops.pin_cmd = piv_pin_cmd;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue