Add support for C_GetTokenInfo pin status flags for ISO7816 cards

This is already supported for a couple of the card drivers, but
since it's a general feature of ISO7816 it should go in iso7816.c,
rather than the current situation where identical code for this is
copy and pasted in each driver.

However, some cards apparently don't support this feature and count
it as a failed PIN attempt, so I've added a flag for now to indicate
whether the card supports this feature. It future, it could be moved
to blacklist cards rather than whitelist them, subject to more testing.
This commit is contained in:
Nicholas Wilson 2015-08-21 18:51:30 +01:00
parent 27b64c5999
commit 5a11d0e2fd
4 changed files with 39 additions and 84 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

@ -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

@ -987,6 +987,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:
@ -1052,11 +1053,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;
@ -1076,6 +1082,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
@ -1089,7 +1105,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);
@ -1119,12 +1135,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