diff --git a/opensc-0.19.0-piv_card_matching.patch b/opensc-0.19.0-piv_card_matching.patch new file mode 100644 index 0000000..91451a5 --- /dev/null +++ b/opensc-0.19.0-piv_card_matching.patch @@ -0,0 +1,644 @@ +From 4ad599bf6c966310819fe3f8114f769d8f180947 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Wed, 5 Dec 2018 14:12:07 -0600 +Subject: [PATCH 1/5] PIV - Improved Card Matching for Dual CAC/PIV and PIVKEY + cards. + +Not all PIV applets are the same. Different versions of NIST 800-73 and improperly implemented +or not implemented required features of NIST 800-73 cases problems. Have a look at the card_issues +listed in card-piv.c. The PIV driver has tried to detect the differences based on clues found in +the ATR historical bytes and vendor version numbers for some cards. + +At the same time it has tried to support the possibility there are multiple applets +on a card that the user may want to use at the same time from different applications. +This has lead to some detection problems with Dual CAC/PIV cards. The same cards +sold by the vendor may have only a PIV applet that may not be the same PIV applet that +is on the Dual PIV/CAC cards. + +http://www.cac.mil/Portals/53/Documents/CAC-utilziation-and-variation-matrix-v2.03-20May2016.doc +defines a number of official CAC cards in active service. A table of the ATRs for these is now used +to detect these cards. The PIV version of the CCC is also read to see if any CAC PKI objects +are defined in the CCC, indicating it is a Dual CAC/PIV, even if the ATR is not listed. + +A more conservative approach to try and handle multiple applets on a card is used. Based +on issues with the implementation of the PIV applet this may not be possible to do. +So for many cards no additional detection will be done at the start of every transaction, +and the login state can not be detected correctly. + +ATRs for PIVKEY are also in the match table, as these cards have a log of issues. + +Other PIV cards in the future or not yet tested may not be covered properly by this patch. +Extra debugging was added with "PIV_MATCH" to help with these other cards. +With "debug = 7;", `grep PIV_MATCH opensc-debug.log` can be used to see how a card +type and card_issues are derived. + +________________________________ + +From 974ffd8166f961c9def8ececa6087dfaf73c866b Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Sat, 8 Dec 2018 18:16:40 -0600 +Subject: [PATCH 2/5] PIV - Improved error handling of get_challenge + +Random data from PIV card is obtained using GENERAL AUTHENTICATE command +for a request of a Challenge from the card. "00 87 00 9B 04 7C 02 81 00" +Usually 8 bytes are returned. + +NIST 800-73-3_PART2, "A.1 Authentication of the PIV Card Application Administrator" +"Table 11. Authentication of PIV Card Application Administrator" shows an example of +how to do this. + +Some cards (one I have: 3b:7d:96:00:00:80:31:80:65:b0:83:11:17:d6:83:00:90:00) +will not allow 2 of these commands in a row. (Maybe assuming command is only +used as in Table 11 and is expecting the second command.) + +Code was added to card-piv.c so if "6A 80" is returned, try the command one more time. +For any other GENERAL AUTHENTICATE failure, SC_ERROR_NOT_SUPPORTED is returned. +piv_get_challenge may be called within a loop from sc_get_challenge if more random +data is needed thus causing the the 2 commands to sent in a row. + +Index: opensc-0.19.0/src/libopensc/card-piv.c +=================================================================== +--- opensc-0.19.0.orig/src/libopensc/card-piv.c ++++ opensc-0.19.0/src/libopensc/card-piv.c +@@ -3,7 +3,7 @@ + * card-default.c: Support for cards with no driver + * + * Copyright (C) 2001, 2002 Juha Yrjölä +- * Copyright (C) 2005-2016 Douglas E. Engert ++ * Copyright (C) 2005-2018 Douglas E. Engert + * Copyright (C) 2006, Identity Alliance, Thomas Harning + * Copyright (C) 2007, EMC, Russell Larner + * +@@ -53,6 +53,7 @@ + #ifdef ENABLE_ZLIB + #include "compression.h" + #endif ++#include "simpletlv.h" + + enum { + PIV_OBJ_CCC = 0, +@@ -146,6 +147,16 @@ enum { + PIV_STATE_INIT + }; + ++/* ccc_flags */ ++#define PIV_CCC_FOUND 0x00000001 ++#define PIV_CCC_F0_PIV 0x00000002 ++#define PIV_CCC_F0_CAC 0x00000004 ++#define PIV_CCC_F0_JAVA 0x00000008 ++#define PIV_CCC_F3_CAC_PKI 0x00000010 ++ ++#define PIV_CCC_TAG_F0 0xF0 ++#define PIV_CCC_TAG_F3 0xF3 ++ + typedef struct piv_private_data { + int enumtag; + int selected_obj; /* The index into the piv_objects last selected */ +@@ -174,6 +185,7 @@ typedef struct piv_private_data { + unsigned int card_issues; /* card_issues flags for this card */ + int object_test_verify; /* Can test this object to set verification state of card */ + int yubico_version; /* 3 byte version number of NEO or Yubikey4 as integer */ ++ unsigned int ccc_flags; /* From CCC indicate if CAC card */ + } piv_private_data_t; + + #define PIV_DATA(card) ((piv_private_data_t*)card->drv_data) +@@ -198,6 +210,39 @@ struct piv_aid { + * These can be discovered by trying GET DATA + */ + ++/* ATRs of cards known to have PIV applet. But must still be tested for a PIV applet */ ++static const struct sc_atr_table piv_atrs[] = { ++ /* CAC cards with PIV from: CAC-utilziation-and-variation-matrix-v2.03-20May2016.doc */ ++ /* Oberthur Card Systems (PIV Endpoint) with PIV endpoint applet and PIV auth cert OBSOLETE */ ++ { "3B:DB:96:00:80:1F:03:00:31:C0:64:77:E3:03:00:82:90.00:C1", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL }, ++ ++ /* Gemalto (PIV Endpoint) with PIV endpoint applet and PIV auth cert OBSOLETE */ ++ { "3B 7D 96 00 00 80 31 80 65 B0 83 11 13 AC 83 00 90 00", NULL, NULL, SC_CARD_TYPE_PIV_II_GEMALTO, 0, NULL }, ++ ++ /* Gemalto (PIV Endpoint) 2 entries */ ++ { "3B:7D:96:00:00:80:31:80:65:B0:83:11:17:D6:83:00:90:00", NULL, NULL, SC_CARD_TYPE_PIV_II_GEMALTO, 0, NULL }, ++ ++ /* Oberthur Card System (PIV Endpoint) 2 entries*/ ++ { "3B:DB:96:00:80:1F:03:00:31:C0:64:B0:F3:10:00:07:90:00:80", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL }, ++ /* Oberthur Card System with LCS 0F - Some VA cards have Terminated state */ ++ { "3B:DB:96:00:80:1F:03:00:31:C0:64:B0:F3:10:00:0F:90:00:88", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL }, ++ ++ /* Giesecke & Devrient (PIV Endpoint) 2 entries */ ++ { "3B:7A:18:00:00:73:66:74:65:20:63:64:31:34:34", NULL, NULL, SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC, 0, NULL }, ++ ++ /* PIVKEY from Taligo */ ++ /* PIVKEY T600 token and T800 on Feitian eJAVA */ ++ { "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:00:64:2D:70:C1:72:FE:E0:FE", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL }, ++ ++ /* PIVKEY C910 */ ++ { "3b:fc:18:00:00:81:31:80:45:90:67:46:4a:00:64:16:06:f2:72:7e:00:e0", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL }, ++ ++ /* PIVKEY C980 */ ++ { "3B:f9:96:00:00:81:31:fe:45:53:50:49:56:4b:45:59:37:30:28", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL }, ++ ++ { NULL, NULL, NULL, 0, 0, NULL } ++}; ++ + /* all have same AID */ + static struct piv_aid piv_aids[] = { + {SC_CARD_TYPE_PIV_II_GENERIC, /* TODO not really card type but what PIV AID is supported */ +@@ -209,9 +254,10 @@ static struct piv_aid piv_aids[] = { + #define CI_VERIFY_630X 0x00000001U /* VERIFY tries left returns 630X rather then 63CX */ + #define CI_VERIFY_LC0_FAIL 0x00000002U /* VERIFY Lc=0 never returns 90 00 if PIN not needed */ + /* will also test after first PIN verify if protected object can be used instead */ ++#define CI_NO_RANDOM 0x00000004U /* can not use Challenge to get random data or no 9B key */ + #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_DISCOVERY_USELESS 0x00000020U /* Discovery can not be used to query active AID invalid or no data returned */ + #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!!! */ +@@ -219,7 +265,7 @@ static struct piv_aid piv_aids[] = { + + #define CI_NO_RSA2048 0x00010000U /* does not have RSA 2048 */ + #define CI_NO_EC384 0x00020000U /* does not have EC 384 */ +- ++#define CI_NO_EC 0x00040000U /* No EC at all */ + + /* + * Flags in the piv_object: +@@ -2233,11 +2279,33 @@ static int piv_get_challenge(sc_card_t * + size_t rbuf_len = 0, out_len = 0; + int r; + unsigned int tag, cla; ++ piv_private_data_t * priv = PIV_DATA(card); + + LOG_FUNC_CALLED(card->ctx); + ++ if (priv->card_issues & CI_NO_RANDOM) { ++ r = SC_ERROR_NOT_SUPPORTED; ++ LOG_TEST_GOTO_ERR(card->ctx, r, "No support for random data"); ++ } ++ + /* NIST 800-73-3 says use 9B, previous verisons used 00 */ + r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); ++ /* ++ * piv_get_challenge is called in a loop. ++ * some cards may allow 1 challenge expecting it to be part of ++ * NIST 800-73-3 part 2 "Authentication of PIV Card Application Administrator" ++ * and return "6A 80" if last command was a get_challenge. ++ * Now that the card returned error, we can try one more time. ++ */ ++ if (r == SC_ERROR_INCORRECT_PARAMETERS) { ++ if (rbuf) ++ free(rbuf); ++ rbuf_len = 0; ++ r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len); ++ if (r == SC_ERROR_INCORRECT_PARAMETERS) { ++ r = SC_ERROR_NOT_SUPPORTED; ++ } ++ } + LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed"); + + p = rbuf; +@@ -2653,6 +2721,89 @@ err: + LOG_FUNC_RETURN(card->ctx, r); + } + ++/* ++ * parse a CCC to test if this is a Dual CAC/PIV ++ * We read teh CCC using the PIV API. ++ * Look for CAC RID=A0 00 00 00 79 ++ */ ++ static int piv_parse_ccc(sc_card_t *card, u8* rbuf, size_t rbuflen) ++{ ++ int r = 0; ++ const u8 * body; ++ size_t bodylen; ++ unsigned int cla_out, tag_out; ++ ++ u8 tag; ++ const u8 * end; ++ size_t len; ++ ++ piv_private_data_t * priv = PIV_DATA(card); ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ if (rbuf == NULL || rbuflen == 0) { ++ r = SC_ERROR_WRONG_LENGTH; ++ goto err; ++ } ++ ++ /* Outer layer is a DER tlv */ ++ body = rbuf; ++ if ((r = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen)) != SC_SUCCESS) { ++ sc_log(card->ctx, "DER problem %d",r); ++ r = SC_ERROR_INVALID_ASN1_OBJECT; ++ goto err; ++ } ++ ++ priv->ccc_flags |= PIV_CCC_FOUND; ++ ++ /* CCC entries are simple tlv */ ++ end = body + bodylen; ++ for(; (body < end); body += len) { ++ r = sc_simpletlv_read_tag((u8**)&body, end - body , &tag, &len); ++ if (r < 0) ++ goto err; ++ switch (tag) { ++ case PIV_CCC_TAG_F0: ++ if (len == 0x15) { ++ if (memcmp(body ,"\xA0\x00\x00\x03\08", 5) == 0) ++ priv->ccc_flags |= PIV_CCC_F0_PIV; ++ else if (memcmp(body ,"\xA0\x00\x00\x00\x79", 5) == 0) ++ priv->ccc_flags |= PIV_CCC_F0_CAC; ++ if (*(body + 6) == 0x02) ++ priv->ccc_flags |= PIV_CCC_F0_JAVA; ++ } ++ break; ++ case PIV_CCC_TAG_F3: ++ if (len == 0x10) { ++ if (memcmp(body ,"\xA0\x00\x00\x00\x79\x04", 6) == 0) ++ priv->ccc_flags |= PIV_CCC_F3_CAC_PKI; ++ } ++ break; ++ } ++ } ++ ++err: ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ ++static int piv_process_ccc(sc_card_t *card) ++{ ++ int r = 0; ++ u8 * rbuf = NULL; ++ size_t rbuflen = 0; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ r = piv_get_cached_data(card, PIV_OBJ_CCC, &rbuf, &rbuflen); ++ ++ if (r < 0) ++ goto err; ++ ++ /* the object is now cached, see what we have */ ++ r = piv_parse_ccc(card, rbuf, rbuflen); ++err: ++ LOG_FUNC_RETURN(card->ctx, r); ++} ++ + + static int piv_find_discovery(sc_card_t *card) + { +@@ -2948,6 +3099,7 @@ static int piv_match_card(sc_card_t *car + { + int r = 0; + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d\n", card->type); + /* 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) { +@@ -2956,7 +3108,13 @@ static int piv_match_card(sc_card_t *car + 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_DUAL_CAC: + case SC_CARD_TYPE_PIV_II_GI_DE: ++ case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_GEMALTO: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR: ++ case SC_CARD_TYPE_PIV_II_PIVKEY: + break; + default: + return 0; /* can not handle the card */ +@@ -2975,6 +3133,7 @@ static int piv_match_card(sc_card_t *car + piv_finish(card); + } + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d r:%d\n", card->type,r); + return r; + } + +@@ -2998,12 +3157,19 @@ static int piv_match_card_continued(sc_c + 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_DUAL_CAC: + case SC_CARD_TYPE_PIV_II_GI_DE: ++ case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_GEMALTO: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR: ++ case SC_CARD_TYPE_PIV_II_PIVKEY: + type = card->type; + break; + default: + return 0; /* can not handle the card */ + } ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d\n", card->type, type); + if (type == -1) { + + /* +@@ -3022,18 +3188,6 @@ static int piv_match_card_continued(sc_c + !(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_len > 0 + && card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */ + size_t datalen; +@@ -3054,10 +3208,17 @@ static int piv_match_card_continued(sc_c + } + } + } +- if (type == -1) +- type = SC_CARD_TYPE_PIV_II_GENERIC; ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d\n", card->type, type); ++ ++ if (type == -1) { ++ /* use known ATRs */ ++ i = _sc_match_atr(card, piv_atrs, &type); ++ if (i < 0) ++ type = SC_CARD_TYPE_PIV_II_GENERIC; /* may still be CAC with PIV Endpoint */ ++ } + } + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d\n", card->type, type); + /* allocate and init basic fields */ + + priv = calloc(1, sizeof(piv_private_data_t)); +@@ -3083,38 +3244,104 @@ static int piv_match_card_continued(sc_c + sc_lock(card); + + /* +- * detect if active AID is PIV. NIST 800-73 says Only one PIV application per card +- * and PIV must be the default application +- * This can avoid doing doing a select_aid and losing the login state on some cards ++ * Detect if active AID is PIV. NIST 800-73 says only one PIV application per card ++ * and PIV must be the default application. ++ * Try to avoid doing a select_aid and losing the login state on some cards. + * We may get interference on some cards by other drivers trying SELECT_AID before +- * we get to see if PIV application is still active. ++ * we get to see if PIV application is still active + * putting PIV driver first might help. +- * This may fail if the wrong AID is active ++ * This may fail if the wrong AID is active. ++ * Discovery Object introduced in 800-73-3 so will return 0 if found and PIV applet active. ++ * Will fail with SC_ERROR_FILE_NOT_FOUND if 800-73-3 and no Discovery object. ++ * But some other card could also return SC_ERROR_FILE_NOT_FOUND. ++ * Will fail for other reasons if wrong applet is selected, or bad PIV implimentation. + */ +- i = piv_find_discovery(card); + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x\n", card->type, priv->card_issues); ++ if (priv->card_issues & CI_DISCOVERY_USELESS) /* TODO may be in wrong place */ ++ i = -1; ++ else ++ i = piv_find_discovery(card); ++ ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x\n", card->type, i, priv->card_issues); + if (i < 0) { + /* Detect by selecting applet */ + i = piv_find_aid(card); + } + + if (i >= 0) { ++ int iccc = 0; ++ /* We now know PIV AID is active, test CCC object 800-73-* say CCC is required */ ++ switch (card->type) { ++ /* ++ * For cards that may also be CAC, try and read the CCC ++ * CCC is required and all Dual PIV/CAC will have a CCC ++ * Currently Dual PIV/CAC are based on NIST 800-73-1 which does not have Discovery or History ++ */ ++ case SC_CARD_TYPE_PIV_II_GENERIC: /* i.e. really dont know what this is */ ++ case SC_CARD_TYPE_PIV_II_HIST: ++ case SC_CARD_TYPE_PIV_II_GI_DE: ++ case SC_CARD_TYPE_PIV_II_GEMALTO: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR: ++ iccc = piv_process_ccc(card); ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d iccc:%d ccc_flags:%08x CI:%08x\n", ++ card->type, iccc, priv->ccc_flags, priv->card_issues); ++ /* ignore an error? */ ++ /* if CCC says it has CAC with PKI on card set to one of the SC_CARD_TYPE_PIV_II_*_DUAL_CAC */ ++ if (priv->ccc_flags & PIV_CCC_F3_CAC_PKI) { ++ switch (card->type) { ++ case SC_CARD_TYPE_PIV_II_GENERIC: ++ case SC_CARD_TYPE_PIV_II_HIST: ++ case SC_CARD_TYPE_PIV_II_GI_DE: ++ card->type = SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC; ++ priv->card_issues |= CI_DISCOVERY_USELESS; ++ priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; ++ break; ++ case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_GEMALTO: ++ card->type = SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC; ++ priv->card_issues |= CI_DISCOVERY_USELESS; ++ priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; ++ break; ++ case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR: ++ card->type = SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC; ++ priv->card_issues |= CI_DISCOVERY_USELESS; ++ priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; ++ break; ++ } ++ } ++ break; ++ ++ /* if user forced it to be one of the CAC types, assume it is CAC */ ++ case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC: ++ priv->card_issues |= CI_DISCOVERY_USELESS; ++ priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; ++ break; ++ } ++ } ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x\n", card->type, i, priv->card_issues); ++ if (i >= 0 && (priv->card_issues & CI_DISCOVERY_USELESS) == 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 ++ * We now know PIV AID is active, test DISCOVERY object again ++ * Some PIV don't support DISCOVERY and return ++ * SC_ERROR_INCORRECT_PARAMETERS. Any error ++ * including SC_ERROR_FILE_NOT_FOUND means we cannot use discovery + * to test for active AID. + */ + int i7e = piv_find_discovery(card); + +- if (i7e != 0 && i7e != SC_ERROR_FILE_NOT_FOUND) { ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i7e:%d CI:%08x\n", card->type, i7e, priv->card_issues); ++ if (i7e < 0) { + priv->card_issues |= CI_DISCOVERY_USELESS; + priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT; + } + } + + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x\n", card->type, i, priv->card_issues); + if (i < 0) { + /* don't match. Does not have a PIV applet. */ + sc_unlock(card); +@@ -3123,6 +3350,7 @@ static int piv_match_card_continued(sc_c + return 0; + } + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x\n", card->type, i, priv->card_issues); + /* Matched, caller will use or free priv and sc_lock as needed */ + priv->pstate=PIV_STATE_INIT; + return 1; /* match */ +@@ -3143,7 +3371,7 @@ static int piv_init(sc_card_t *card) + /* continue the matching get a lock and the priv */ + r = piv_match_card_continued(card); + if (r != 1) { +- sc_log(card->ctx,"piv_match_card_continued failed"); ++ sc_log(card->ctx,"piv_match_card_continued failed card->type:%d", card->type); + piv_finish(card); + /* tell sc_connect_card to try other drivers */ + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); +@@ -3166,6 +3394,7 @@ static int piv_init(sc_card_t *card) + * Set card_issues based on card type either set by piv_match_card or by opensc.conf + */ + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x\n", card->type, priv->card_issues); + switch(card->type) { + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: +@@ -3197,6 +3426,7 @@ static int piv_init(sc_card_t *card) + * may be set earlier or later then in the following code. + */ + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x\n", card->type, priv->card_issues); + switch(card->type) { + case SC_CARD_TYPE_PIV_II_NEO: + priv->card_issues |= CI_NO_EC384 +@@ -3215,14 +3445,23 @@ static int piv_init(sc_card_t *card) + priv->card_issues |= CI_VERIFY_LC0_FAIL; + break; + ++ case SC_CARD_TYPE_PIV_II_GI_DE: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR: ++ case SC_CARD_TYPE_PIV_II_GEMALTO: ++ priv->card_issues |= 0; /* could add others here */ ++ break; ++ + case SC_CARD_TYPE_PIV_II_HIST: +- priv->card_issues |= 0; ++ priv->card_issues |= 0; /* could add others here */ + break; + +- case SC_CARD_TYPE_PIV_II_GI_DE: ++ case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC: ++ case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC: + priv->card_issues |= CI_VERIFY_LC0_FAIL + | CI_PIV_AID_LOSE_STATE +- | CI_OTHER_AID_LOSE_STATE;; ++ | CI_NO_RANDOM ++ | CI_OTHER_AID_LOSE_STATE; + /* TODO may need more research */ + break; + +@@ -3232,13 +3471,26 @@ static int piv_init(sc_card_t *card) + /* TODO may need more research */ + break; + ++ case SC_CARD_TYPE_PIV_II_PIVKEY: ++ priv->card_issues |= CI_VERIFY_LC0_FAIL ++ | CI_PIV_AID_LOSE_STATE /* be conservative */ ++ | CI_NO_EC384 | CI_NO_EC ++ | CI_NO_RANDOM; /* does not have 9B key */ ++ /* Discovery object returns 6A 82 so is not on card by default */ ++ /* TODO may need more research */ ++ break; ++ + default: +- priv->card_issues = 0; /* opensc.conf may have it wrong, continue anyway */ +- sc_log(card->ctx, "Unknown PIV card->type %d", card->type); +- card->type = SC_CARD_TYPE_PIV_II_BASE; ++ priv->card_issues |= CI_VERIFY_LC0_FAIL ++ | CI_OTHER_AID_LOSE_STATE; ++ /* opensc.conf may have it wrong, continue anyway */ ++ sc_log(card->ctx, "Unknown PIV card->type %d", card->type); ++ card->type = SC_CARD_TYPE_PIV_II_GENERIC; + } + sc_log(card->ctx, "PIV card-type=%d card_issues=0x%08x", card->type, priv->card_issues); + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x\n", card->type, priv->card_issues); ++ + priv->enumtag = piv_aids[0].enumtag; + + /* PKCS#11 may try to generate session keys, and get confused +@@ -3252,15 +3504,20 @@ static int piv_init(sc_card_t *card) + _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ + _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ + +- flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE; +- ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; ++ if (!(priv->card_issues & CI_NO_EC)) { ++ flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE; ++ ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES; ++ ++ _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); ++ if (!(priv->card_issues & CI_NO_EC384)) ++ _sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL); ++ } + +- _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); +- if (!(priv->card_issues & CI_NO_EC384)) +- _sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL); ++ if (!(priv->card_issues & CI_NO_RANDOM)) ++ card->caps |= SC_CARD_CAP_RNG; + +- /* TODO may turn off SC_CARD_CAP_ISO7816_PIN_INFO later */ +- card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO; ++ /* May turn off SC_CARD_CAP_ISO7816_PIN_INFO later */ ++ card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO; + + /* + * 800-73-3 cards may have a history object and/or a discovery object +@@ -3580,11 +3837,13 @@ static int piv_card_reader_lock_obtained + r = SC_ERROR_NO_CARD_SUPPORT; + } else { + r = piv_find_discovery(card); ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH piv_find_discovery card->type:%d r:%d\n", card->type, r); + } + + if (r < 0) { + if (was_reset > 0 || !(priv->card_issues & CI_PIV_AID_LOSE_STATE)) { + r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH piv_select_aid card->type:%d r:%d\n", card->type, r); + } else { + r = 0; /* cant do anything with this card, hope there was no interference */ + } +Index: opensc-0.19.0/src/libopensc/cards.h +=================================================================== +--- opensc-0.19.0.orig/src/libopensc/cards.h ++++ opensc-0.19.0/src/libopensc/cards.h +@@ -138,7 +138,13 @@ 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_DUAL_CAC, + SC_CARD_TYPE_PIV_II_GI_DE, ++ SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC, ++ SC_CARD_TYPE_PIV_II_GEMALTO, ++ SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC, ++ SC_CARD_TYPE_PIV_II_OBERTHUR, ++ SC_CARD_TYPE_PIV_II_PIVKEY, + + /* MuscleApplet */ + SC_CARD_TYPE_MUSCLE_BASE = 15000, diff --git a/opensc.changes b/opensc.changes index ea29509..ce0e3dc 100644 --- a/opensc.changes +++ b/opensc.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Sun Aug 18 01:35:45 UTC 2019 - Jason Sikes + +- added opensc-0.19.0-piv_card_matching.patch + * Improve Card Matching for Dual CAC/PIV and PIVKEY cards. + * sourced from https://github.com/OpenSC/OpenSC/pull/1549 + ------------------------------------------------------------------- Tue Jul 30 03:15:14 UTC 2019 - Jason Sikes diff --git a/opensc.spec b/opensc.spec index af124a5..d0bf3b6 100644 --- a/opensc.spec +++ b/opensc.spec @@ -32,6 +32,7 @@ Source2: %{name}-rpmlintrc Source3: opensc.module Patch1: opensc-0.19.0-rsa-pss.patch Patch2: opensc-0.19.0-redundant_logging.patch +Patch3: opensc-0.19.0-piv_card_matching.patch BuildRequires: docbook-xsl-stylesheets BuildRequires: libtool BuildRequires: libxslt @@ -64,6 +65,7 @@ may require third party proprietary software. %setup -q %patch1 -p1 %patch2 -p1 +%patch3 -p1 %build autoreconf -fvi