From 0911982bef3aba1da24c2d70b4942d19ceb6ae78 Mon Sep 17 00:00:00 2001 From: Doug Engert Date: Sat, 31 Mar 2018 08:46:29 -0500 Subject: [PATCH] Various PIV changes Some ActivIdentity CAC/PIV cards lose the login state when selecting the PIV AID SC_CARD_TYPE_PIV_II_CAC and CI_PIV_AID_LOSE_STATE were added so piv_card_reader_lock_obtained will try and do a SELECT PIV AID. card->type is reset to its original value if piv_match_card_continued fails to match a card as PIV. pkcs15-piv.c now uses sc_card_ctl which checks card->ops->card_ctl for NULL. closes https://github.com/OpenSC/OpenSC/pull/1307 fixes https://github.com/OpenSC/OpenSC/issues/1297 --- src/libopensc/card-piv.c | 44 ++++++++++++++++++++++++++++++++------ src/libopensc/cards.h | 1 + src/libopensc/pkcs15-piv.c | 6 +++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 70fbd660..ef114db8 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -214,6 +214,7 @@ static struct piv_aid piv_aids[] = { #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_PIV_AID_LOSE_STATE 0x00000040U /* PIV AID can lose the login state run with out it*/ #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 */ @@ -2965,8 +2966,6 @@ static int piv_match_card(sc_card_t *card) { int r = 0; - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); - /* piv_match_card may be called with card->type, set by opensc.conf */ /* user provide card type must be one we know */ switch (card->type) { @@ -2975,6 +2974,7 @@ static int piv_match_card(sc_card_t *card) case SC_CARD_TYPE_PIV_II_HIST: case SC_CARD_TYPE_PIV_II_NEO: case SC_CARD_TYPE_PIV_II_YUBIKEY4: + case SC_CARD_TYPE_PIV_II_GI_DE: break; default: return 0; /* can not handle the card */ @@ -3005,8 +3005,7 @@ static int piv_match_card_continued(sc_card_t *card) sc_file_t aidfile; int type = -1; piv_private_data_t *priv = NULL; - - SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + int saved_type = card->type; /* Since we send an APDU, the card's logout function may be called... * however it may be in dirty memory */ @@ -3020,6 +3019,7 @@ static int piv_match_card_continued(sc_card_t *card) case SC_CARD_TYPE_PIV_II_HIST: case SC_CARD_TYPE_PIV_II_NEO: case SC_CARD_TYPE_PIV_II_YUBIKEY4: + case SC_CARD_TYPE_PIV_II_GI_DE: type = card->type; break; default: @@ -3043,6 +3043,18 @@ static int piv_match_card_continued(sc_card_t *card) !(memcmp(card->reader->atr_info.hist_bytes, "Yubikey", 7))) { type = SC_CARD_TYPE_PIV_II_NEO; } + /* + * https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp1239.pdf + * lists 2 ATRS with historical bytes: + * 73 66 74 65 2D 63 64 30 38 30 + * 73 66 74 65 20 63 64 31 34 34 + * will check for 73 66 74 65 + */ + else if (card->reader->atr_info.hist_bytes_len >= 4 && + !(memcmp(card->reader->atr_info.hist_bytes, "sfte", 4))) { + type = SC_CARD_TYPE_PIV_II_GI_DE; + } + else if (card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */ p = card->reader->atr_info.hist_bytes; pe = p + card->reader->atr_info.hist_bytes_len; @@ -3129,6 +3141,7 @@ static int piv_match_card_continued(sc_card_t *card) /* don't match. Does not have a PIV applet. */ sc_unlock(card); piv_finish(card); + card->type = saved_type; return 0; } @@ -3228,6 +3241,13 @@ static int piv_init(sc_card_t *card) priv->card_issues |= 0; break; + case SC_CARD_TYPE_PIV_II_GI_DE: + priv->card_issues |= CI_VERIFY_LC0_FAIL + | CI_PIV_AID_LOSE_STATE + | CI_OTHER_AID_LOSE_STATE;; + /* TODO may need more research */ + break; + case SC_CARD_TYPE_PIV_II_GENERIC: priv->card_issues |= CI_VERIFY_LC0_FAIL | CI_OTHER_AID_LOSE_STATE; @@ -3564,6 +3584,13 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) goto err; } + /* can we detect and then select the PIV AID without losinig the login state? */ + if ((priv->card_issues & CI_DISCOVERY_USELESS) + && (priv->card_issues & CI_PIV_AID_LOSE_STATE)) { + r = 0; /* do nothing, hope card was not interferred with */ + goto err; + } + /* make sure our application is active */ /* first see if AID is active AID by reading discovery object '7E' */ @@ -3576,8 +3603,13 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) r = piv_find_discovery(card); } - if (r < 0) - r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); + if (r < 0) { + if (!(priv->card_issues & CI_PIV_AID_LOSE_STATE)) { + r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); + } else { + r = 0; /* cant do anything with this card, hope there was no interference */ + } + } if (r < 0) /* bad error return will show up in sc_lock as error*/ goto err; diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index e1a9d446..23e7c5d1 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -138,6 +138,7 @@ enum { SC_CARD_TYPE_PIV_II_HIST, SC_CARD_TYPE_PIV_II_NEO, SC_CARD_TYPE_PIV_II_YUBIKEY4, + SC_CARD_TYPE_PIV_II_GI_DE, /* MuscleApplet */ SC_CARD_TYPE_MUSCLE_BASE = 15000, diff --git a/src/libopensc/pkcs15-piv.c b/src/libopensc/pkcs15-piv.c index 26701431..e6b4e31a 100644 --- a/src/libopensc/pkcs15-piv.c +++ b/src/libopensc/pkcs15-piv.c @@ -658,7 +658,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) sc_format_path(objects[i].path, &obj_info.path); /* See if the object can not be present on the card */ - r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path); + r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path); if (r == 1) continue; /* Not on card, do not define the object */ @@ -734,7 +734,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) cert_obj.flags = certs[i].obj_flags; /* See if the cert might be present or not. */ - r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path); + r = sc_card_ctl(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path); if (r == 1) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cert can not be present,i=%d", i); continue; @@ -948,7 +948,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) label = pins[i].label; if (i == 0 && - (card->ops->card_ctl)(card, SC_CARDCTL_PIV_PIN_PREFERENCE, + sc_card_ctl(card, SC_CARDCTL_PIV_PIN_PREFERENCE, &pin_ref) == 0 && pin_ref == 0x00) { /* must be 80 for PIV pin, or 00 for Global PIN */ pin_info.attrs.pin.reference = pin_ref;