Merge pull request #530 from NWilson/yubikey-neo-pin

Yubikey NEO pin functions support
This commit is contained in:
Frank Morgner 2015-09-12 18:51:10 +02:00
commit a906c6d7b8
5 changed files with 62 additions and 85 deletions

View File

@ -170,7 +170,7 @@ static int myeid_init(struct sc_card *card)
#endif
/* State that we have an RNG */
card->caps |= SC_CARD_CAP_RNG;
card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
card->max_recv_size = 255;
card->max_send_size = 255;
@ -524,42 +524,6 @@ static int myeid_delete_file(struct sc_card *card, const struct sc_path *path)
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int myeid_pin_info(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
sc_apdu_t apdu;
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference);
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu.sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
LOG_TEST_RET(card->ctx, r, "Check SW error");
if (r == SC_SUCCESS)
{
data->pin1.pad_length = data->pin2.pad_length = 8;
data->pin1.pad_char = data->pin2.pad_char = 0xFF;
}
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
@ -567,11 +531,6 @@ static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
LOG_FUNC_CALLED(card->ctx);
if (data->cmd == SC_PIN_CMD_GET_INFO)
{
return myeid_pin_info(card, data, tries_left);
}
sc_log(card->ctx, "ref (%d), pin1 len(%d), pin2 len (%d)\n",
data->pin_reference, data->pin1.len, data->pin2.len);

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;

View File

@ -137,37 +137,6 @@ static int sc_hsm_match_card(struct sc_card *card)
static int sc_hsm_pin_info(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
sc_apdu_t apdu;
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference);
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu.sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
LOG_TEST_RET(card->ctx, r, "Check SW error");
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/*
* Encode 16 hexadecimals of SO-PIN into binary form
* Caller must check length of sopin and provide an 8 byte buffer
@ -206,9 +175,6 @@ static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
int r;
if (data->cmd == SC_PIN_CMD_GET_INFO) {
return sc_hsm_pin_info(card, data, tries_left);
}
if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) {
if (data->pin1.len != 16)
return SC_ERROR_INVALID_PIN_LENGTH;
@ -1058,7 +1024,7 @@ static int sc_hsm_init(struct sc_card *card)
_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
_sc_card_add_ec_alg(card, 320, flags, ext_flags, NULL);
card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT;
card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT|SC_CARD_CAP_ISO7816_PIN_INFO;
card->max_send_size = 1431; // 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY
card->max_recv_size = 0; // Card supports sending with extended length APDU and without limit

View File

@ -969,6 +969,7 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu,
struct sc_pin_cmd_data *data, u8 *buf, size_t buf_len)
{
int r, len = 0, pad = 0, use_pin_pad = 0, ins, p1 = 0;
int cse = SC_APDU_CASE_3_SHORT;
switch (data->pin_type) {
case SC_AC_CHV:
@ -1034,11 +1035,16 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu,
p1 |= 0x01;
}
break;
case SC_PIN_CMD_GET_INFO:
ins = 0x20;
/* No data to send or to receive */
cse = SC_APDU_CASE_1;
break;
default:
return SC_ERROR_NOT_SUPPORTED;
}
sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, p1, data->pin_reference);
sc_format_apdu(card, apdu, cse, ins, p1, data->pin_reference);
apdu->lc = len;
apdu->datalen = len;
apdu->data = buf;
@ -1058,6 +1064,16 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
if (tries_left)
*tries_left = -1;
/* Many cards do support PIN status queries, but some cards don't and
* mistakenly count the command as a failed PIN attempt, so for now we
* whitelist cards with this flag. In future this may be reduced to a
* blacklist, subject to testing more cards. */
if (data->cmd == SC_PIN_CMD_GET_INFO &&
!(card->caps & SC_CARD_CAP_ISO7816_PIN_INFO)) {
sc_log(card->ctx, "Card does not support PIN status queries");
return SC_ERROR_NOT_SUPPORTED;
}
/* See if we've been called from another card driver, which is
* passing an APDU to us (this allows to write card drivers
* whose PIN functions behave "mostly like ISO" except in some
@ -1071,7 +1087,7 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
}
apdu = data->apdu;
if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) {
if (!(data->flags & SC_PIN_CMD_USE_PINPAD) || data->cmd == SC_PIN_CMD_GET_INFO) {
/* Transmit the APDU to the card */
r = sc_transmit_apdu(card, apdu);
@ -1101,12 +1117,23 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
data->apdu = NULL;
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu->sw1 == 0x63) {
if ((apdu->sw2 & 0xF0) == 0xC0 && tries_left != NULL)
*tries_left = apdu->sw2 & 0x0F;
return SC_ERROR_PIN_CODE_INCORRECT;
r = sc_check_sw(card, apdu->sw1, apdu->sw2);
if (data->cmd == SC_PIN_CMD_GET_INFO) {
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu->sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
}
return sc_check_sw(card, apdu->sw1, apdu->sw2);
return r;
}

View File

@ -439,6 +439,9 @@ struct sc_reader_operations {
/* Card has on-board random number source. */
#define SC_CARD_CAP_RNG 0x00000004
/* Card supports ISO7816 PIN status queries using an empty VERIFY */
#define SC_CARD_CAP_ISO7816_PIN_INFO 0x00000008
/* Use the card's ACs in sc_pkcs15init_authenticate(),
* instead of relying on the ACL info in the profile files. */
#define SC_CARD_CAP_USE_FCI_AC 0x00000010