diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 7cdb93ff..63d80cca 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -213,6 +213,7 @@ static struct piv_aid piv_aids[] = { /* will also test after first PIN verify if protected object can be used instead */ #define CI_CANT_USE_GETDATA_FOR_STATE 0x00000008U /* No object to test verification inplace of VERIFY Lc=0 */ #define CI_LEAKS_FILE_NOT_FOUND 0x00000010U /* GET DATA of empty object returns 6A 82 even if PIN not verified */ +#define CI_DISCOVERY_USELESS 0x00000020U /* Discovery can not be used to query active AID */ #define CI_OTHER_AID_LOSE_STATE 0x00000100U /* Other drivers match routines may reset our security state and lose AID!!! */ #define CI_NFC_EXPOSE_TOO_MUCH 0x00000200U /* PIN, crypto and objects exposed over NFS in violation of 800-73-3 */ @@ -2662,7 +2663,6 @@ err: } -/* Do not use the cache value but read every time */ static int piv_find_discovery(sc_card_t *card) { int r = 0; @@ -2957,7 +2957,7 @@ piv_finish(sc_card_t *card) static int piv_match_card(sc_card_t *card) { - int i, k; + int i, i7e, k; size_t j; u8 *p, *pe; sc_file_t aidfile; @@ -3058,7 +3058,7 @@ static int piv_match_card(sc_card_t *card) * We may get interference on some cards by other drivers trying SELECT_AID before * we get to see if PIV application is still active. * putting PIV driver first might help. - * TODO could be cached too + * This may fail if the wrong AID is active */ i = piv_find_discovery(card); @@ -3067,6 +3067,22 @@ static int piv_match_card(sc_card_t *card) i = piv_find_aid(card, &aidfile); } + if (i >= 0) { + /* + * We now know PIV AID is active, test DISCOVERY object + * Some CAC cards with PIV don't support DISCOVERY and return + * SC_ERROR_INCORRECT_PARAMETERS. Any error other then + * SC_ERROR_FILE_NOT_FOUND means we cannot use discovery + * to test for active AID. + */ + i7e = piv_find_discovery(card); + if (i7e != 0 && i7e != SC_ERROR_FILE_NOT_FOUND) { + priv->card_issues |= CI_DISCOVERY_USELESS; + priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; + } + } + + if (i < 0) { piv_finish(card); /* don't match. Does not have a PIV applet. */ @@ -3083,7 +3099,7 @@ static int piv_match_card(sc_card_t *card) static int piv_init(sc_card_t *card) { - int r; + int r = 0; piv_private_data_t * priv = PIV_DATA(card); sc_apdu_t apdu; unsigned long flags; @@ -3136,7 +3152,7 @@ static int piv_init(sc_card_t *card) switch(card->type) { case SC_CARD_TYPE_PIV_II_NEO: - priv->card_issues = CI_NO_EC384 + priv->card_issues |= CI_NO_EC384 | CI_VERIFY_630X | CI_OTHER_AID_LOSE_STATE | CI_LEAKS_FILE_NOT_FOUND @@ -3146,18 +3162,18 @@ static int piv_init(sc_card_t *card) break; case SC_CARD_TYPE_PIV_II_YUBIKEY4: - priv->card_issues = CI_OTHER_AID_LOSE_STATE + priv->card_issues |= CI_OTHER_AID_LOSE_STATE | CI_LEAKS_FILE_NOT_FOUND; if (priv->neo_version < 0x00040302) priv->card_issues |= CI_VERIFY_LC0_FAIL; break; case SC_CARD_TYPE_PIV_II_HIST: - priv->card_issues = 0; + priv->card_issues |= 0; break; case SC_CARD_TYPE_PIV_II_GENERIC: - priv->card_issues = CI_VERIFY_LC0_FAIL + priv->card_issues |= CI_VERIFY_LC0_FAIL | CI_OTHER_AID_LOSE_STATE; /* TODO may need more research */ break; @@ -3196,12 +3212,13 @@ static int piv_init(sc_card_t *card) * 800-73-3 cards may have a history object and/or a discovery object * We want to process them now as this has information on what * keys and certs the card has and how the pin might be used. + * If they fail, ignore it there are optional and introdced in + * NIST 800-73-3 and NIST 800-73-2 so some older cards may + * not handle the requets. */ piv_process_history(card); - r = piv_process_discovery(card); - if (r > 0) - r = 0; + piv_process_discovery(card); priv->pstate=PIV_STATE_NORMAL; sc_unlock(card) ; /* obtained in piv_match */ @@ -3477,7 +3494,6 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) int r = 0; u8 temp[256]; size_t templen = sizeof(temp); - struct sc_pin_cmd_data data; piv_private_data_t * priv = PIV_DATA(card); /* may be null */ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); @@ -3494,7 +3510,14 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) /* first see if AID is active AID by reading discovery object '7E' */ /* If not try selecting AID */ - r = piv_find_discovery(card); + + /* but if x card does not support DISCOVERY object we can not use it */ + if (priv->card_issues & CI_DISCOVERY_USELESS) { + r = SC_ERROR_NO_CARD_SUPPORT; + } else { + r = piv_find_discovery(card); + } + if (r < 0) r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); @@ -3504,15 +3527,7 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) if (was_reset > 0) priv->logged_in = SC_PIN_STATE_UNKNOWN; - /* See if VERIFY Lc=empty will tell us the state */ - memset(&data, 0, sizeof(data)); - data.cmd = SC_PIN_CMD_GET_INFO; - data.pin_type = SC_AC_CHV; - data.pin_reference = priv->pin_preference; - /* will try our best to see if logged_in or not */ - r = piv_pin_cmd(card, &data, NULL); - - r = 0; /* ignore return from piv_pin_cmd */ + r = 0; err: LOG_FUNC_RETURN(card->ctx, r);