Blame SOURCES/opensc-0.19.0-dual.patch

62d44b
diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c
62d44b
index 03c83868f1..794472134c 100644
62d44b
--- a/src/libopensc/card-piv.c
62d44b
+++ b/src/libopensc/card-piv.c
62d44b
@@ -3,7 +3,7 @@
62d44b
  * card-default.c: Support for cards with no driver
62d44b
  *
62d44b
  * Copyright (C) 2001, 2002  Juha Yrjölä <juha.yrjola@iki.fi>
62d44b
- * Copyright (C) 2005-2016  Douglas E. Engert <deengert@gmail.com>
62d44b
+ * Copyright (C) 2005-2018  Douglas E. Engert <deengert@gmail.com>
62d44b
  * Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
62d44b
  * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com>
62d44b
  *
62d44b
@@ -53,6 +53,7 @@
62d44b
 #ifdef ENABLE_ZLIB
62d44b
 #include "compression.h"
62d44b
 #endif
62d44b
+#include "simpletlv.h"
62d44b
 
62d44b
 enum {
62d44b
 	PIV_OBJ_CCC = 0,
62d44b
@@ -146,6 +147,16 @@ enum {
62d44b
 	PIV_STATE_INIT
62d44b
 };
62d44b
 
62d44b
+/* ccc_flags */
62d44b
+#define PIV_CCC_FOUND		0x00000001
62d44b
+#define PIV_CCC_F0_PIV		0x00000002
62d44b
+#define PIV_CCC_F0_CAC		0x00000004
62d44b
+#define PIV_CCC_F0_JAVA		0x00000008
62d44b
+#define PIV_CCC_F3_CAC_PKI	0x00000010
62d44b
+
62d44b
+#define PIV_CCC_TAG_F0		0xF0
62d44b
+#define PIV_CCC_TAG_F3		0xF3
62d44b
+
62d44b
 typedef struct piv_private_data {
62d44b
 	int enumtag;
62d44b
 	int  selected_obj; /* The index into the piv_objects last selected */
62d44b
@@ -174,6 +185,7 @@ typedef struct piv_private_data {
62d44b
 	unsigned int card_issues; /* card_issues flags for this card */
62d44b
 	int object_test_verify; /* Can test this object to set verification state of card */
62d44b
 	int yubico_version; /* 3 byte version number of NEO or Yubikey4  as integer */
62d44b
+	unsigned int ccc_flags;	    /* From  CCC indicate if CAC card */
62d44b
 } piv_private_data_t;
62d44b
 
62d44b
 #define PIV_DATA(card) ((piv_private_data_t*)card->drv_data)
62d44b
@@ -198,6 +210,37 @@ struct piv_aid {
62d44b
  * These can be discovered by trying GET DATA
62d44b
  */
62d44b
 
62d44b
+/* ATRs of cards known to have PIV applet. But must still be tested for a PIV applet */
62d44b
+static const struct sc_atr_table piv_atrs[] = {
62d44b
+	/* CAC cards with PIV from: CAC-utilziation-and-variation-matrix-v2.03-20May2016.doc */
62d44b
+	/* Oberthur Card Systems (PIV Endpoint) with PIV endpoint applet and PIV auth cert OBSOLETE */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* Gemalto (PIV Endpoint) with PIV endpoint applet and PIV auth cert OBSOLETE */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* Gemalto (PIV Endpoint) 2 entries */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* Oberthur Card System (PIV Endpoint)  2 entries*/
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* Giesecke & Devrient (PIV Endpoint)  2 entries */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* PIVKEY from Taligo */
62d44b
+	/* PIVKEY T600 token and T800  on Feitian eJAVA */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* PIVKEY C910 */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	/* PIVKEY C980 */
62d44b
+	{ "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 },
62d44b
+
62d44b
+	{ NULL, NULL, NULL, 0, 0, NULL }
62d44b
+};
62d44b
+
62d44b
 /* all have same AID */
62d44b
 static struct piv_aid piv_aids[] = {
62d44b
 	{SC_CARD_TYPE_PIV_II_GENERIC, /* TODO not really card type but what PIV AID is supported */
62d44b
@@ -209,9 +252,10 @@ static struct piv_aid piv_aids[] = {
62d44b
 #define CI_VERIFY_630X			    0x00000001U /* VERIFY tries left returns 630X rather then 63CX */
62d44b
 #define CI_VERIFY_LC0_FAIL		    0x00000002U /* VERIFY Lc=0 never returns 90 00 if PIN not needed */
62d44b
 							/* will also test after first PIN verify if protected object can be used instead */
62d44b
+#define CI_NO_RANDOM			    0x00000004U /* can not use Challenge to get random data or no 9B key */
62d44b
 #define CI_CANT_USE_GETDATA_FOR_STATE	    0x00000008U /* No object to test verification inplace of VERIFY Lc=0 */
62d44b
 #define CI_LEAKS_FILE_NOT_FOUND		    0x00000010U /* GET DATA of empty object returns 6A 82 even if PIN not verified */
62d44b
-#define CI_DISCOVERY_USELESS		    0x00000020U /* Discovery can not be used to query active AID */
62d44b
+#define CI_DISCOVERY_USELESS		    0x00000020U /* Discovery can not be used to query active AID invalid or no data returned */
62d44b
 #define CI_PIV_AID_LOSE_STATE		    0x00000040U /* PIV AID can lose the login state run with out it*/
62d44b
 
62d44b
 #define CI_OTHER_AID_LOSE_STATE		    0x00000100U /* Other drivers match routines may reset our security state and lose AID!!! */
62d44b
@@ -219,7 +263,7 @@ static struct piv_aid piv_aids[] = {
62d44b
 
62d44b
 #define CI_NO_RSA2048			    0x00010000U /* does not have RSA 2048 */
62d44b
 #define CI_NO_EC384			    0x00020000U /* does not have EC 384 */
62d44b
-
62d44b
+#define CI_NO_EC			    0x00040000U /* No EC at all */
62d44b
 
62d44b
 /*
62d44b
  * Flags in the piv_object:
62d44b
@@ -2222,11 +2266,33 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
62d44b
 	size_t rbuf_len = 0, out_len = 0;
62d44b
 	int r;
62d44b
 	unsigned int tag, cla;
62d44b
+	piv_private_data_t * priv = PIV_DATA(card);
62d44b
 
62d44b
 	LOG_FUNC_CALLED(card->ctx);
62d44b
 
62d44b
+	if (priv->card_issues & CI_NO_RANDOM) {
62d44b
+		r = SC_ERROR_NOT_SUPPORTED;
62d44b
+		LOG_TEST_GOTO_ERR(card->ctx, r, "No support for random data");
62d44b
+	}
62d44b
+
62d44b
 	/* NIST 800-73-3 says use 9B, previous verisons used 00 */
62d44b
 	r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len);
62d44b
+	/*
62d44b
+	 * piv_get_challenge is called in a loop. 
62d44b
+	 * some cards may allow 1 challenge expecting it to be part of 
62d44b
+	 * NIST 800-73-3 part 2 "Authentication of PIV Card Application Administrator"
62d44b
+	 * and return "6A 80" if last command was a get_challenge.
62d44b
+	 * Now that the card returned error, we can try one more time.
62d44b
+	 */
62d44b
+	 if (r == SC_ERROR_INCORRECT_PARAMETERS) {
62d44b
+		if (rbuf)
62d44b
+			free(rbuf);
62d44b
+		rbuf_len = 0;
62d44b
+		r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, sizeof sbuf, &rbuf, &rbuf_len);
62d44b
+		if (r == SC_ERROR_INCORRECT_PARAMETERS) {
62d44b
+			r = SC_ERROR_NOT_SUPPORTED;
62d44b
+		}
62d44b
+	}
62d44b
 	LOG_TEST_GOTO_ERR(card->ctx, r, "GENERAL AUTHENTICATE failed");
62d44b
 
62d44b
 	p = rbuf;
62d44b
@@ -2635,6 +2701,91 @@ static int piv_process_discovery(sc_card_t *card)
62d44b
 	LOG_FUNC_RETURN(card->ctx, r);
62d44b
 }
62d44b
 
62d44b
+/*
62d44b
+ * parse a CCC to test  if this is a Dual CAC/PIV
62d44b
+ * We read teh CCC using the PIV API.
62d44b
+ * Look for CAC RID=A0 00 00 00 79
62d44b
+ */
62d44b
+ static int piv_parse_ccc(sc_card_t *card, u8* rbuf, size_t rbuflen)
62d44b
+{
62d44b
+	int r = 0;
62d44b
+	const u8 * body;
62d44b
+	size_t bodylen;
62d44b
+	unsigned int cla_out, tag_out;
62d44b
+
62d44b
+	u8  tag;
62d44b
+	const u8 * end;
62d44b
+	size_t len;
62d44b
+
62d44b
+	piv_private_data_t * priv = PIV_DATA(card);
62d44b
+
62d44b
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
62d44b
+
62d44b
+	if (rbuf == NULL || rbuflen == 0) {
62d44b
+		r = SC_ERROR_WRONG_LENGTH;
62d44b
+		goto  err;
62d44b
+	}
62d44b
+
62d44b
+	/* Outer layer is a DER tlv */
62d44b
+	body = rbuf;
62d44b
+	if ((r = sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out,  &bodylen)) != SC_SUCCESS) {
62d44b
+		sc_log(card->ctx, "DER problem %d",r);
62d44b
+		r = SC_ERROR_INVALID_ASN1_OBJECT;
62d44b
+		goto err;
62d44b
+	}
62d44b
+
62d44b
+	priv->ccc_flags |= PIV_CCC_FOUND;
62d44b
+
62d44b
+	/* CCC  entries are simple tlv */
62d44b
+	end = body + bodylen;
62d44b
+	
62d44b
+	for(; (body < end); body += len) {
62d44b
+	
62d44b
+		r = sc_simpletlv_read_tag((u8**)&body, end - body , &tag, &len;;
62d44b
+		if (r < 0)
62d44b
+			goto err;
62d44b
+		switch (tag) {
62d44b
+			case PIV_CCC_TAG_F0:
62d44b
+				if (len == 0x15) {
62d44b
+					if (memcmp(body ,"\xA0\x00\x00\x03\08", 5) == 0)
62d44b
+						priv->ccc_flags |= PIV_CCC_F0_PIV;
62d44b
+					else if (memcmp(body ,"\xA0\x00\x00\x00\x79", 5) == 0)
62d44b
+						priv->ccc_flags |= PIV_CCC_F0_CAC;
62d44b
+					if (*(body + 6) == 0x02)
62d44b
+						priv->ccc_flags |= PIV_CCC_F0_JAVA;
62d44b
+				}
62d44b
+				break;
62d44b
+			case PIV_CCC_TAG_F3:
62d44b
+				if (len == 0x10) {
62d44b
+					if (memcmp(body ,"\xA0\x00\x00\x00\x79\x04", 6) == 0)
62d44b
+						priv->ccc_flags |= PIV_CCC_F3_CAC_PKI;
62d44b
+				}
62d44b
+				break;
62d44b
+		}
62d44b
+	}
62d44b
+
62d44b
+err:
62d44b
+	LOG_FUNC_RETURN(card->ctx, r);
62d44b
+}
62d44b
+
62d44b
+static int piv_process_ccc(sc_card_t *card)
62d44b
+{
62d44b
+	int r = 0;
62d44b
+	u8 * rbuf = NULL;
62d44b
+	size_t rbuflen = 0;
62d44b
+
62d44b
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
62d44b
+	r = piv_get_cached_data(card, PIV_OBJ_CCC, &rbuf, &rbuflen);
62d44b
+
62d44b
+	if (r < 0)
62d44b
+		goto err;
62d44b
+
62d44b
+	/* the object is now cached, see what we have */
62d44b
+	r = piv_parse_ccc(card, rbuf, rbuflen);
62d44b
+err:
62d44b
+	LOG_FUNC_RETURN(card->ctx, r);
62d44b
+}
62d44b
+
62d44b
 
62d44b
 static int piv_find_discovery(sc_card_t *card)
62d44b
 {
62d44b
@@ -2922,7 +3073,8 @@ piv_finish(sc_card_t *card)
62d44b
 static int piv_match_card(sc_card_t *card)
62d44b
 {
62d44b
 	int r = 0;
62d44b
-
62d44b
+	
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d\n", card->type);
62d44b
 	/* piv_match_card may be called with card->type, set by opensc.conf */
62d44b
 	/* user provide card type must be one we know */
62d44b
 	switch (card->type) {
62d44b
@@ -2931,7 +3083,13 @@ static int piv_match_card(sc_card_t *card)
62d44b
 		case SC_CARD_TYPE_PIV_II_HIST:
62d44b
 		case SC_CARD_TYPE_PIV_II_NEO:
62d44b
 		case SC_CARD_TYPE_PIV_II_YUBIKEY4:
62d44b
+		case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC:
62d44b
 		case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR:
62d44b
+		case SC_CARD_TYPE_PIV_II_PIVKEY:
62d44b
 			break;
62d44b
 		default:
62d44b
 			return 0; /* can not handle the card */
62d44b
@@ -2950,13 +3108,14 @@ static int piv_match_card(sc_card_t *card)
62d44b
 		piv_finish(card);
62d44b
 	}
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d r:%d\n", card->type,r);
62d44b
 	return r;
62d44b
 }
62d44b
 
62d44b
 
62d44b
 static int piv_match_card_continued(sc_card_t *card)
62d44b
 {
62d44b
-	int i, r;
62d44b
+	int i, r = 0;
62d44b
 	int type  = -1;
62d44b
 	piv_private_data_t *priv = NULL;
62d44b
 	int saved_type = card->type;
62d44b
@@ -2973,12 +3132,19 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 		case SC_CARD_TYPE_PIV_II_HIST:
62d44b
 		case SC_CARD_TYPE_PIV_II_NEO:
62d44b
 		case SC_CARD_TYPE_PIV_II_YUBIKEY4:
62d44b
+		case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC:
62d44b
 		case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR:
62d44b
+		case SC_CARD_TYPE_PIV_II_PIVKEY:
62d44b
 			type = card->type;
62d44b
 			break;
62d44b
 		default:
62d44b
 			return 0; /* can not handle the card */
62d44b
 	}
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d r:%d\n", card->type, type, r);
62d44b
 	if (type == -1) {
62d44b
 
62d44b
 		/*
62d44b
@@ -2997,18 +3163,6 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 					!(memcmp(card->reader->atr_info.hist_bytes, "Yubikey", 7))) {
62d44b
 				type = SC_CARD_TYPE_PIV_II_NEO;
62d44b
 			}
62d44b
-			/*
62d44b
-			 * https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp1239.pdf
62d44b
-			 * lists 2 ATRS with historical bytes:
62d44b
-			 *   73 66 74 65 2D 63 64 30 38 30
62d44b
-			 *   73 66 74 65 20 63 64 31 34 34
62d44b
-			 * will check for 73 66 74 65
62d44b
-			 */
62d44b
-			else if (card->reader->atr_info.hist_bytes_len >= 4
62d44b
-					&& !(memcmp(card->reader->atr_info.hist_bytes, "sfte", 4))) {
62d44b
-				type = SC_CARD_TYPE_PIV_II_GI_DE;
62d44b
-			}
62d44b
-
62d44b
 			else if (card->reader->atr_info.hist_bytes_len > 0
62d44b
 					&& card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */
62d44b
 				size_t datalen;
62d44b
@@ -3029,10 +3183,17 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 				}
62d44b
 			}
62d44b
 		}
62d44b
-		if (type == -1)
62d44b
-			type = SC_CARD_TYPE_PIV_II_GENERIC;
62d44b
+		sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d r:%d\n", card->type, type, r);
62d44b
+
62d44b
+		if (type == -1) {
62d44b
+			/* use known ATRs  */
62d44b
+			i = _sc_match_atr(card, piv_atrs, &type);
62d44b
+			if (type == -1)
62d44b
+				type = SC_CARD_TYPE_PIV_II_GENERIC; /* may  still be CAC with PIV Endpoint */
62d44b
+		}
62d44b
 	}
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d type:%d r:%d\n", card->type, type, r);
62d44b
 	/* allocate and init basic fields */
62d44b
 
62d44b
 	priv = calloc(1, sizeof(piv_private_data_t));
62d44b
@@ -3046,6 +3207,7 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 	card->drv_data = priv; /* will free if no match, or pass on to piv_init */
62d44b
 	priv->selected_obj = -1;
62d44b
 	priv->pin_preference = 0x80; /* 800-73-3 part 1, table 3 */
62d44b
+	/* TODO Dual CAC/PIV are bases on 800-73-1 were priv->pin_preference = 0. need to check later */
62d44b
 	priv->logged_in = SC_PIN_STATE_UNKNOWN;
62d44b
 	priv->tries_left = 10; /* will assume OK at start */
62d44b
 	priv->pstate = PIV_STATE_MATCH;
62d44b
@@ -3064,38 +3226,104 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 	}
62d44b
 
62d44b
 	/*
62d44b
-	 * detect if active AID is PIV. NIST 800-73 says Only one PIV application per card
62d44b
-	 * and PIV must be the default application
62d44b
-	 * This can avoid doing doing a select_aid and losing the login state on some cards
62d44b
+	 * Detect if active AID is PIV. NIST 800-73 says only one PIV application per card
62d44b
+	 * and PIV must be the default application.
62d44b
+	 * Try to avoid doing a select_aid and losing the login state on some cards.
62d44b
 	 * We may get interference on some cards by other drivers trying SELECT_AID before
62d44b
-	 * we get to see if PIV application is still active.
62d44b
+	 * we get to see if PIV application is still active
62d44b
 	 * putting PIV driver first might help. 
62d44b
-	 * This may fail if the wrong AID is active
62d44b
+	 * This may fail if the wrong AID is active.
62d44b
+	 * Discovery Object introduced in 800-73-3 so will return 0 if found and PIV applet active.
62d44b
+	 * Will fail with SC_ERROR_FILE_NOT_FOUND if 800-73-3 and no Discovery object.
62d44b
+	 * But some other card could also return SC_ERROR_FILE_NOT_FOUND.
62d44b
+	 * Will fail for other reasons if wrong applet is selected, or bad PIV implimentation. 
62d44b
 	 */
62d44b
-	i = piv_find_discovery(card);
62d44b
+	
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x r:%d\n", card->type,  priv->card_issues, r);
62d44b
+	if (priv->card_issues & CI_DISCOVERY_USELESS) /* TODO may be in wrong place */
62d44b
+		i = -1;
62d44b
+	else
62d44b
+		i = piv_find_discovery(card);
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x r:%d\n", card->type, i, priv->card_issues, r);
62d44b
 	if (i < 0) {
62d44b
 		/* Detect by selecting applet */
62d44b
 		i = piv_find_aid(card);
62d44b
 	}
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x r:%d\n", card->type, i, priv->card_issues, r);
62d44b
 	if (i >= 0) {
62d44b
+		int iccc = 0;
62d44b
+		 /* We now know PIV AID is active, test CCC object  800-73-* say CCC is required */
62d44b
+		switch (card->type)  {
62d44b
+			/*
62d44b
+			 * For cards that may also be CAC, try and read the CCC
62d44b
+			 * CCC is required and all Dual PIV/CAC will have a CCC
62d44b
+			 * Currently Dual PIV/CAC are based on NIST 800-73-1 which does not have Discovery or History
62d44b
+			 */
62d44b
+			case SC_CARD_TYPE_PIV_II_GENERIC: /* i.e. really dont know what this is */
62d44b
+			case SC_CARD_TYPE_PIV_II_HIST:
62d44b
+			case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+			case SC_CARD_TYPE_PIV_II_GEMALTO:
62d44b
+			case SC_CARD_TYPE_PIV_II_OBERTHUR:
62d44b
+				iccc = piv_process_ccc(card);
62d44b
+				sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d iccc:%d ccc_flags:%08x CI:%08x r:%d\n",
62d44b
+						card->type, iccc, priv->ccc_flags, priv->card_issues, r);
62d44b
+				/* ignore an error? */
62d44b
+				/* if CCC says it has CAC with PKI on card set to one of the SC_CARD_TYPE_PIV_II_*_DUAL_CAC */
62d44b
+				if (priv->ccc_flags & PIV_CCC_F3_CAC_PKI) {
62d44b
+					switch (card->type)  {
62d44b
+						case SC_CARD_TYPE_PIV_II_GENERIC:
62d44b
+						case SC_CARD_TYPE_PIV_II_HIST:
62d44b
+						case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+						    card->type = SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC;
62d44b
+						    priv->card_issues |= CI_DISCOVERY_USELESS;
62d44b
+						    priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT;
62d44b
+						    break;
62d44b
+						case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC:
62d44b
+						case SC_CARD_TYPE_PIV_II_GEMALTO:
62d44b
+							card->type = SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC;
62d44b
+							priv->card_issues |= CI_DISCOVERY_USELESS;
62d44b
+							priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT;
62d44b
+							break;
62d44b
+						case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC:
62d44b
+						case SC_CARD_TYPE_PIV_II_OBERTHUR:
62d44b
+							card->type =  SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC;
62d44b
+							priv->card_issues |= CI_DISCOVERY_USELESS;
62d44b
+							priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT;
62d44b
+							break;
62d44b
+					}
62d44b
+				}
62d44b
+				break;
62d44b
+
62d44b
+				/* if user forced it to be one of the CAC types, assume it is CAC */
62d44b
+			case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC:
62d44b
+			case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC:
62d44b
+			case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC:
62d44b
+				priv->card_issues |= CI_DISCOVERY_USELESS;
62d44b
+				priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT;
62d44b
+				break;
62d44b
+			}
62d44b
+		}
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x r:%d\n", card->type, i, priv->card_issues, r);
62d44b
+	if (i >= 0 && (priv->card_issues & CI_DISCOVERY_USELESS) == 0) {
62d44b
 		/*
62d44b
-		 * We now know PIV AID is active, test DISCOVERY object 
62d44b
-		 * Some CAC cards with PIV don't support DISCOVERY and return 
62d44b
-		 * SC_ERROR_INCORRECT_PARAMETERS. Any error other then 
62d44b
-		 * SC_ERROR_FILE_NOT_FOUND means we cannot use discovery 
62d44b
+		 * We now know PIV AID is active, test DISCOVERY object again 
62d44b
+		 * Some PIV don't support DISCOVERY and return 
62d44b
+		 * SC_ERROR_INCORRECT_PARAMETERS. Any error 
62d44b
+		 * including SC_ERROR_FILE_NOT_FOUND means we cannot use discovery 
62d44b
 		 * to test for active AID.
62d44b
 		 */
62d44b
 		int i7e = piv_find_discovery(card);
62d44b
 
62d44b
-		if (i7e != 0 && i7e !=  SC_ERROR_FILE_NOT_FOUND) {
62d44b
+		sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i7e:%d CI:%08x r:%d\n", card->type, i7e, priv->card_issues, r);
62d44b
+		if (i7e != 0) {
62d44b
 			priv->card_issues |= CI_DISCOVERY_USELESS;
62d44b
 			priv->obj_cache[PIV_OBJ_DISCOVERY].flags |= PIV_OBJ_CACHE_NOT_PRESENT;
62d44b
 		}
62d44b
 	}
62d44b
 
62d44b
-
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x r:%d\n", card->type, i, priv->card_issues, r);
62d44b
 	if (i < 0) {
62d44b
 		/* don't match. Does not have a PIV applet. */
62d44b
 		sc_unlock(card);
62d44b
@@ -3104,6 +3332,7 @@ static int piv_match_card_continued(sc_card_t *card)
62d44b
 		return 0;
62d44b
 	}
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d i:%d CI:%08x r:%d\n", card->type, i, priv->card_issues, r);
62d44b
 	/* Matched, caller will use or free priv and sc_lock as needed */
62d44b
 	priv->pstate=PIV_STATE_INIT;
62d44b
 	return 1; /* match */
62d44b
@@ -3124,7 +3353,7 @@ static int piv_init(sc_card_t *card)
62d44b
 	/* continue the matching get a lock and the priv */
62d44b
 	r = piv_match_card_continued(card);
62d44b
 	if (r != 1)  {
62d44b
-		sc_log(card->ctx,"piv_match_card_continued failed");
62d44b
+		sc_log(card->ctx,"piv_match_card_continued failed card->type:%d", card->type);
62d44b
 		piv_finish(card);
62d44b
 		/* tell sc_connect_card to try other drivers */
62d44b
 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD);
62d44b
@@ -3147,6 +3376,7 @@ static int piv_init(sc_card_t *card)
62d44b
 	 * Set card_issues based on card type either set by piv_match_card or by opensc.conf
62d44b
 	 */
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x r:%d\n", card->type, priv->card_issues, r);
62d44b
 	switch(card->type) {
62d44b
 		case SC_CARD_TYPE_PIV_II_NEO:
62d44b
 		case SC_CARD_TYPE_PIV_II_YUBIKEY4:
62d44b
@@ -3178,6 +3408,7 @@ static int piv_init(sc_card_t *card)
62d44b
 	 * may be set earlier or later then in the following code. 
62d44b
 	 */
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x r:%d\n", card->type, priv->card_issues, r);
62d44b
 	switch(card->type) {
62d44b
 		case SC_CARD_TYPE_PIV_II_NEO:
62d44b
 			priv->card_issues |= CI_NO_EC384
62d44b
@@ -3196,30 +3427,53 @@ static int piv_init(sc_card_t *card)
62d44b
 				priv->card_issues |= CI_VERIFY_LC0_FAIL;
62d44b
 			break;
62d44b
 
62d44b
+		case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO:
62d44b
+			priv->card_issues |= 0; /* could add others here */
62d44b
+			break;
62d44b
+
62d44b
 		case SC_CARD_TYPE_PIV_II_HIST:
62d44b
-			priv->card_issues |= 0;
62d44b
+			priv->card_issues |= 0; /* could add others here */
62d44b
 			break;
62d44b
 
62d44b
-		case SC_CARD_TYPE_PIV_II_GI_DE:
62d44b
+		case SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC:
62d44b
+		case SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC:
62d44b
 			priv->card_issues |= CI_VERIFY_LC0_FAIL
62d44b
 				| CI_PIV_AID_LOSE_STATE
62d44b
-				| CI_OTHER_AID_LOSE_STATE;;
62d44b
+				| CI_NO_RANDOM
62d44b
+				| CI_OTHER_AID_LOSE_STATE;
62d44b
 			/* TODO may need more research */
62d44b
 			break;
62d44b
 
62d44b
+
62d44b
 		case SC_CARD_TYPE_PIV_II_GENERIC:
62d44b
 			priv->card_issues |= CI_VERIFY_LC0_FAIL
62d44b
 				| CI_OTHER_AID_LOSE_STATE;
62d44b
 			/* TODO may need more research */
62d44b
 			break;
62d44b
 
62d44b
+		case SC_CARD_TYPE_PIV_II_PIVKEY:
62d44b
+			priv->card_issues |= CI_VERIFY_LC0_FAIL
62d44b
+				| CI_PIV_AID_LOSE_STATE /* be conservative */
62d44b
+				| CI_NO_EC384 | CI_NO_EC
62d44b
+				| CI_NO_RANDOM; /* does not have 9B key */
62d44b
+				/* Discovery object returns 6A 82 so is not on card by default */
62d44b
+				/*  TODO may need more research */
62d44b
+			break;
62d44b
+
62d44b
 		default:
62d44b
-		     priv->card_issues = 0; /* opensc.conf may have it wrong, continue anyway */
62d44b
-		     sc_log(card->ctx, "Unknown PIV card->type %d", card->type);
62d44b
-		     card->type = SC_CARD_TYPE_PIV_II_BASE;
62d44b
+			priv->card_issues |= CI_VERIFY_LC0_FAIL
62d44b
+				| CI_OTHER_AID_LOSE_STATE;
62d44b
+			/* opensc.conf may have it wrong, continue anyway */
62d44b
+			sc_log(card->ctx, "Unknown PIV card->type %d", card->type);
62d44b
+			card->type = SC_CARD_TYPE_PIV_II_GENERIC;
62d44b
 	}
62d44b
 	sc_log(card->ctx, "PIV card-type=%d card_issues=0x%08x", card->type, priv->card_issues);
62d44b
 
62d44b
+	sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d CI:%08x r:%d\n", card->type, priv->card_issues, r);
62d44b
+
62d44b
 	priv->enumtag = piv_aids[0].enumtag;
62d44b
 
62d44b
 	/* PKCS#11 may try to generate session keys, and get confused
62d44b
@@ -3233,15 +3487,20 @@ static int piv_init(sc_card_t *card)
62d44b
 	_sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */
62d44b
 	_sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */
62d44b
 
62d44b
-	flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
62d44b
-	ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
62d44b
+	if (!(priv->card_issues & CI_NO_EC)) {
62d44b
+		flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
62d44b
+		ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
62d44b
+
62d44b
+		_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
62d44b
+		if (!(priv->card_issues & CI_NO_EC384))
62d44b
+			_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
62d44b
+	}
62d44b
 
62d44b
-	_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
62d44b
-	if (!(priv->card_issues & CI_NO_EC384))
62d44b
-		_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
62d44b
+	if (!(priv->card_issues & CI_NO_RANDOM))
62d44b
+		card->caps |= SC_CARD_CAP_RNG;
62d44b
 
62d44b
-	/* TODO may turn off SC_CARD_CAP_ISO7816_PIN_INFO later */
62d44b
-	card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
62d44b
+	/* May turn off SC_CARD_CAP_ISO7816_PIN_INFO later */
62d44b
+	card->caps |=  SC_CARD_CAP_ISO7816_PIN_INFO;
62d44b
 
62d44b
 	/*
62d44b
 	 * 800-73-3 cards may have a history object and/or a discovery object
62d44b
@@ -3565,11 +3824,13 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset)
62d44b
 	    r =  SC_ERROR_NO_CARD_SUPPORT;
62d44b
 	} else {
62d44b
 	    r = piv_find_discovery(card);
62d44b
+	    sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH piv_find_discovery card->type:%d r:%d\n", card->type, r);
62d44b
 	}
62d44b
 
62d44b
 	if (r < 0) {
62d44b
 		if (was_reset > 0 || !(priv->card_issues & CI_PIV_AID_LOSE_STATE)) {
62d44b
 			r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen);
62d44b
+			sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH piv_select_aid card->type:%d r:%d\n", card->type, r);
62d44b
 		} else {
62d44b
 			r = 0; /* cant do anything with this card, hope there was no interference */
62d44b
 		}
62d44b
diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
62d44b
index f4df17fb04..121182bb6a 100644
62d44b
--- a/src/libopensc/cards.h
62d44b
+++ b/src/libopensc/cards.h
62d44b
@@ -136,7 +136,13 @@ enum {
62d44b
 	SC_CARD_TYPE_PIV_II_HIST,
62d44b
 	SC_CARD_TYPE_PIV_II_NEO,
62d44b
 	SC_CARD_TYPE_PIV_II_YUBIKEY4,
62d44b
+	SC_CARD_TYPE_PIV_II_GI_DE_DUAL_CAC,
62d44b
 	SC_CARD_TYPE_PIV_II_GI_DE,
62d44b
+	SC_CARD_TYPE_PIV_II_GEMALTO_DUAL_CAC,
62d44b
+	SC_CARD_TYPE_PIV_II_GEMALTO,
62d44b
+	SC_CARD_TYPE_PIV_II_OBERTHUR_DUAL_CAC,
62d44b
+	SC_CARD_TYPE_PIV_II_OBERTHUR,
62d44b
+	SC_CARD_TYPE_PIV_II_PIVKEY,
62d44b
 
62d44b
 	/* MuscleApplet */
62d44b
 	SC_CARD_TYPE_MUSCLE_BASE = 15000,
62d44b