Blame SOURCES/opensc-0.19.0-cac1.patch

b7ace2
commit a2efcb184fcb0302bfadeb97b5cf8953cb77d0fb
b7ace2
Author: Jakub Jelen <jjelen@redhat.com>
b7ace2
Date:   Tue Oct 9 16:03:19 2018 +0200
b7ace2
b7ace2
    WIP: Add minimal CAC1 driver for legacy cards.
b7ace2
    
b7ace2
    It is using the same pkcs15 backend as the CAC2 cards as well as some of
b7ace2
    the CAC2 driver methods.
b7ace2
    
b7ace2
    The separation is made mostly for easier card matching.
b7ace2
b7ace2
diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am
b7ace2
index a99b0c57..5a17df2b 100644
b7ace2
--- a/src/libopensc/Makefile.am
b7ace2
+++ b/src/libopensc/Makefile.am
b7ace2
@@ -40,7 +40,8 @@ libopensc_la_SOURCES_BASE = \
b7ace2
 	card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
b7ace2
 	card-oberthur.c card-belpic.c card-atrust-acos.c \
b7ace2
 	card-entersafe.c card-epass2003.c card-coolkey.c card-incrypto34.c \
b7ace2
-	card-piv.c card-cac.c card-muscle.c card-acos5.c \
b7ace2
+	card-piv.c card-cac-common.c card-cac.c card-cac1.c \
b7ace2
+	card-muscle.c card-acos5.c \
b7ace2
 	card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \
b7ace2
 	card-rtecp.c card-westcos.c card-myeid.c \
b7ace2
 	card-itacns.c card-authentic.c \
b7ace2
diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak
b7ace2
index 10a3b0a9..7ef642b6 100644
b7ace2
--- a/src/libopensc/Makefile.mak
b7ace2
+++ b/src/libopensc/Makefile.mak
b7ace2
@@ -19,7 +19,7 @@ OBJECTS			= \
b7ace2
 	card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
b7ace2
 	card-oberthur.obj card-belpic.obj card-atrust-acos.obj \
b7ace2
 	card-entersafe.obj card-epass2003.obj card-coolkey.obj \
b7ace2
-	card-incrypto34.obj card-cac.obj card-piv.obj card-muscle.obj \
b7ace2
+	card-incrypto34.obj card-cac.obj card-cac1.obj card-piv.obj card-muscle.obj \
b7ace2
 	card-acos5.obj \
b7ace2
 	card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \
b7ace2
 	card-rtecp.obj card-westcos.obj card-myeid.obj \
b7ace2
diff --git a/src/libopensc/card-cac-common.c b/src/libopensc/card-cac-common.c
b7ace2
new file mode 100644
b7ace2
index 00000000..6c338bf9
b7ace2
--- /dev/null
b7ace2
+++ b/src/libopensc/card-cac-common.c
b7ace2
@@ -0,0 +1,116 @@
b7ace2
+/*
b7ace2
+ * card-cac-common.c: Code shared among CAC1 and CAC2 drivers
b7ace2
+ *
b7ace2
+ * Copyright (C) 2018, Red Hat, Inc.
b7ace2
+ *
b7ace2
+ * Author: Jakub Jelen <jjelen@redhat.com>
b7ace2
+ *
b7ace2
+ * This library is free software; you can redistribute it and/or
b7ace2
+ * modify it under the terms of the GNU Lesser General Public
b7ace2
+ * License as published by the Free Software Foundation; either
b7ace2
+ * version 2.1 of the License, or (at your option) any later version.
b7ace2
+ *
b7ace2
+ * This library is distributed in the hope that it will be useful,
b7ace2
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
b7ace2
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
b7ace2
+ * Lesser General Public License for more details.
b7ace2
+ *
b7ace2
+ * You should have received a copy of the GNU Lesser General Public
b7ace2
+ * License along with this library; if not, write to the Free Software
b7ace2
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
b7ace2
+ */
b7ace2
+
b7ace2
+#if HAVE_CONFIG_H
b7ace2
+#include "config.h"
b7ace2
+#endif
b7ace2
+
b7ace2
+#include <ctype.h>
b7ace2
+#include <string.h>
b7ace2
+#include <stdlib.h>
b7ace2
+
b7ace2
+#ifdef _WIN32
b7ace2
+#include <io.h>
b7ace2
+#else
b7ace2
+#include <unistd.h>
b7ace2
+#endif
b7ace2
+
b7ace2
+#include "internal.h"
b7ace2
+#include "iso7816.h"
b7ace2
+#include "card-cac-common.h"
b7ace2
+
b7ace2
+/* default certificate labels for the CAC card */
b7ace2
+const char *cac_labels[MAX_CAC_SLOTS] = {
b7ace2
+	"CAC ID Certificate",
b7ace2
+	"CAC Email Signature Certificate",
b7ace2
+	"CAC Email Encryption Certificate",
b7ace2
+	"CAC Cert 4",
b7ace2
+	"CAC Cert 5",
b7ace2
+	"CAC Cert 6",
b7ace2
+	"CAC Cert 7",
b7ace2
+	"CAC Cert 8",
b7ace2
+	"CAC Cert 9",
b7ace2
+	"CAC Cert 10",
b7ace2
+	"CAC Cert 11",
b7ace2
+	"CAC Cert 12",
b7ace2
+	"CAC Cert 13",
b7ace2
+	"CAC Cert 14",
b7ace2
+	"CAC Cert 15",
b7ace2
+	"CAC Cert 16"
b7ace2
+};
b7ace2
+
b7ace2
+const char *get_cac_label(int index)
b7ace2
+{
b7ace2
+	if (index < 0 || index >= MAX_CAC_SLOTS)
b7ace2
+		return NULL;
b7ace2
+
b7ace2
+	return cac_labels[index];
b7ace2
+}
b7ace2
+
b7ace2
+static int cac_list_compare_path(const void *a, const void *b)
b7ace2
+{
b7ace2
+	if (a == NULL || b == NULL)
b7ace2
+		return 1;
b7ace2
+	return memcmp( &((cac_object_t *) a)->path,
b7ace2
+		&((cac_object_t *) b)->path, sizeof(sc_path_t));
b7ace2
+}
b7ace2
+
b7ace2
+/* For SimCList autocopy, we need to know the size of the data elements */
b7ace2
+static size_t cac_list_meter(const void *el) {
b7ace2
+	return sizeof(cac_object_t);
b7ace2
+}
b7ace2
+
b7ace2
+cac_private_data_t *cac_new_private_data(void)
b7ace2
+{
b7ace2
+	cac_private_data_t *priv;
b7ace2
+	priv = calloc(1, sizeof(cac_private_data_t));
b7ace2
+	if (!priv)
b7ace2
+		return NULL;
b7ace2
+	list_init(&priv->pki_list);
b7ace2
+	list_attributes_comparator(&priv->pki_list, cac_list_compare_path);
b7ace2
+	list_attributes_copy(&priv->pki_list, cac_list_meter, 1);
b7ace2
+	list_init(&priv->general_list);
b7ace2
+	list_attributes_comparator(&priv->general_list, cac_list_compare_path);
b7ace2
+	list_attributes_copy(&priv->general_list, cac_list_meter, 1);
b7ace2
+	/* set other fields as appropriate */
b7ace2
+
b7ace2
+	return priv;
b7ace2
+}
b7ace2
+
b7ace2
+void cac_free_private_data(cac_private_data_t *priv)
b7ace2
+{
b7ace2
+	free(priv->cac_id);
b7ace2
+	free(priv->cache_buf);
b7ace2
+	free(priv->aca_path);
b7ace2
+	list_destroy(&priv->pki_list);
b7ace2
+	list_destroy(&priv->general_list);
b7ace2
+	free(priv);
b7ace2
+	return;
b7ace2
+}
b7ace2
+
b7ace2
+int cac_add_object_to_list(list_t *list, const cac_object_t *object)
b7ace2
+{
b7ace2
+	if (list_append(list, object) < 0)
b7ace2
+		return SC_ERROR_UNKNOWN;
b7ace2
+	return SC_SUCCESS;
b7ace2
+}
b7ace2
+
b7ace2
diff --git a/src/libopensc/card-cac-common.h b/src/libopensc/card-cac-common.h
b7ace2
new file mode 100644
b7ace2
index 00000000..77f14761
b7ace2
--- /dev/null
b7ace2
+++ b/src/libopensc/card-cac-common.h
b7ace2
@@ -0,0 +1,89 @@
b7ace2
+/*
b7ace2
+ * card-cac-common.h: Code shared among CAC1 and CAC2 drivers
b7ace2
+ *
b7ace2
+ * Copyright (C) 2018, Red Hat, Inc.
b7ace2
+ *
b7ace2
+ * Author: Jakub Jelen <jjelen@redhat.com>
b7ace2
+ *
b7ace2
+ * This library is free software; you can redistribute it and/or
b7ace2
+ * modify it under the terms of the GNU Lesser General Public
b7ace2
+ * License as published by the Free Software Foundation; either
b7ace2
+ * version 2.1 of the License, or (at your option) any later version.
b7ace2
+ *
b7ace2
+ * This library is distributed in the hope that it will be useful,
b7ace2
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
b7ace2
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
b7ace2
+ * Lesser General Public License for more details.
b7ace2
+ *
b7ace2
+ * You should have received a copy of the GNU Lesser General Public
b7ace2
+ * License along with this library; if not, write to the Free Software
b7ace2
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
b7ace2
+ */
b7ace2
+
b7ace2
+#ifndef HAVE_CARD_CAC_COMMON_H
b7ace2
+#define HAVE_CARD_CAC_COMMON_H
b7ace2
+
b7ace2
+#define CAC_MAX_SIZE 4096		/* arbitrary, just needs to be 'large enough' */
b7ace2
+
b7ace2
+typedef struct cac_cuid {
b7ace2
+	u8 gsc_rid[5];
b7ace2
+	u8 manufacturer_id;
b7ace2
+	u8 card_type;
b7ace2
+	u8 card_id;
b7ace2
+} cac_cuid_t;
b7ace2
+
b7ace2
+/* data structures to store meta data about CAC objects */
b7ace2
+typedef struct cac_object {
b7ace2
+	const char *name;
b7ace2
+	int fd;
b7ace2
+	sc_path_t path;
b7ace2
+} cac_object_t;
b7ace2
+
b7ace2
+/*
b7ace2
+ * CAC private data per card state
b7ace2
+ */
b7ace2
+typedef struct cac_private_data {
b7ace2
+	int object_type;		/* select set this so we know how to read the file */
b7ace2
+	int cert_next;			/* index number for the next certificate found in the list */
b7ace2
+	u8 *cache_buf;			/* cached version of the currently selected file */
b7ace2
+	size_t cache_buf_len;		/* length of the cached selected file */
b7ace2
+	int cached;			/* is the cached selected file valid */
b7ace2
+	cac_cuid_t cuid;                /* card unique ID from the CCC */
b7ace2
+	u8 *cac_id;                     /* card serial number */
b7ace2
+	size_t cac_id_len;              /* card serial number len */
b7ace2
+	list_t pki_list;                /* list of pki containers */
b7ace2
+	cac_object_t *pki_current;      /* current pki object _ctl function */
b7ace2
+	list_t general_list;            /* list of general containers */
b7ace2
+	cac_object_t *general_current;  /* current object for _ctl function */
b7ace2
+	sc_path_t *aca_path;		/* ACA path to be selected before pin verification */
b7ace2
+} cac_private_data_t;
b7ace2
+
b7ace2
+#define CAC_DATA(card) ((cac_private_data_t*)card->drv_data)
b7ace2
+
b7ace2
+/*
b7ace2
+ * Set up the normal CAC paths
b7ace2
+ */
b7ace2
+#define CAC_1_RID "\xA0\x00\x00\x00\x79"
b7ace2
+#define CAC_TO_AID(x) x, sizeof(x)-1
b7ace2
+
b7ace2
+
b7ace2
+#define MAX_CAC_SLOTS 16		/* Maximum number of slots is 16 now */
b7ace2
+
b7ace2
+/* template for a CAC pki object */
b7ace2
+static const cac_object_t cac_cac_pki_obj = {
b7ace2
+	"CAC Certificate", 0x0, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME,
b7ace2
+	{ CAC_TO_AID(CAC_1_RID "\x01\x00") } }
b7ace2
+};
b7ace2
+
b7ace2
+/* template for emulated cuid */
b7ace2
+static const cac_cuid_t cac_cac_cuid = {
b7ace2
+	{ 0xa0, 0x00, 0x00, 0x00, 0x79 },
b7ace2
+	2, 2, 0
b7ace2
+};
b7ace2
+
b7ace2
+cac_private_data_t *cac_new_private_data(void);
b7ace2
+void cac_free_private_data(cac_private_data_t *priv);
b7ace2
+int cac_add_object_to_list(list_t *list, const cac_object_t *object);
b7ace2
+const char *get_cac_label(int index);
b7ace2
+
b7ace2
+#endif /* HAVE_CARD_CAC_COMMON_H */
b7ace2
diff --git a/src/libopensc/card-cac.c b/src/libopensc/card-cac.c
b7ace2
index bd4e0336..f9620009 100644
b7ace2
--- a/src/libopensc/card-cac.c
b7ace2
+++ b/src/libopensc/card-cac.c
b7ace2
@@ -58,8 +58,8 @@
b7ace2
 #include "compression.h"
b7ace2
 #endif
b7ace2
 #include "iso7816.h"
b7ace2
+#include "card-cac-common.h"
b7ace2
 
b7ace2
-#define CAC_MAX_SIZE 4096		/* arbitrary, just needs to be 'large enough' */
b7ace2
 /*
b7ace2
  *  CAC hardware and APDU constants
b7ace2
  */
b7ace2
@@ -147,20 +147,6 @@ typedef struct cac_card_url {
b7ace2
 	u8 keyCryptoAlgorithm;               /* not used for VM cards */
b7ace2
 } cac_card_url_t;
b7ace2
 
b7ace2
-typedef struct cac_cuid {
b7ace2
-	u8 gsc_rid[5];
b7ace2
-	u8 manufacturer_id;
b7ace2
-	u8 card_type;
b7ace2
-	u8 card_id;
b7ace2
-} cac_cuid_t;
b7ace2
-
b7ace2
-/* data structures to store meta data about CAC objects */
b7ace2
-typedef struct cac_object {
b7ace2
-	const char *name;
b7ace2
-	int fd;
b7ace2
-	sc_path_t path;
b7ace2
-} cac_object_t;
b7ace2
-
b7ace2
 #define CAC_MAX_OBJECTS 16
b7ace2
 
b7ace2
 typedef struct {
b7ace2
@@ -190,82 +176,10 @@ typedef struct {
b7ace2
 #define CAC_OBJECT_TYPE_TLV_FILE	4
b7ace2
 #define CAC_OBJECT_TYPE_GENERIC		5
b7ace2
 
b7ace2
-/*
b7ace2
- * CAC private data per card state
b7ace2
- */
b7ace2
-typedef struct cac_private_data {
b7ace2
-	int object_type;		/* select set this so we know how to read the file */
b7ace2
-	int cert_next;			/* index number for the next certificate found in the list */
b7ace2
-	u8 *cache_buf;			/* cached version of the currently selected file */
b7ace2
-	size_t cache_buf_len;		/* length of the cached selected file */
b7ace2
-	int cached;			/* is the cached selected file valid */
b7ace2
-	cac_cuid_t cuid;                /* card unique ID from the CCC */
b7ace2
-	u8 *cac_id;                     /* card serial number */
b7ace2
-	size_t cac_id_len;              /* card serial number len */
b7ace2
-	list_t pki_list;                /* list of pki containers */
b7ace2
-	cac_object_t *pki_current;      /* current pki object _ctl function */
b7ace2
-	list_t general_list;            /* list of general containers */
b7ace2
-	cac_object_t *general_current;  /* current object for _ctl function */
b7ace2
-	sc_path_t *aca_path;		/* ACA path to be selected before pin verification */
b7ace2
-} cac_private_data_t;
b7ace2
-
b7ace2
-#define CAC_DATA(card) ((cac_private_data_t*)card->drv_data)
b7ace2
-
b7ace2
-static int cac_list_compare_path(const void *a, const void *b)
b7ace2
-{
b7ace2
-	if (a == NULL || b == NULL)
b7ace2
-		return 1;
b7ace2
-	return memcmp( &((cac_object_t *) a)->path,
b7ace2
-		&((cac_object_t *) b)->path, sizeof(sc_path_t));
b7ace2
-}
b7ace2
-
b7ace2
-/* For SimCList autocopy, we need to know the size of the data elements */
b7ace2
-static size_t cac_list_meter(const void *el) {
b7ace2
-	return sizeof(cac_object_t);
b7ace2
-}
b7ace2
-
b7ace2
-static cac_private_data_t *cac_new_private_data(void)
b7ace2
-{
b7ace2
-	cac_private_data_t *priv;
b7ace2
-	priv = calloc(1, sizeof(cac_private_data_t));
b7ace2
-	if (!priv)
b7ace2
-		return NULL;
b7ace2
-	list_init(&priv->pki_list);
b7ace2
-	list_attributes_comparator(&priv->pki_list, cac_list_compare_path);
b7ace2
-	list_attributes_copy(&priv->pki_list, cac_list_meter, 1);
b7ace2
-	list_init(&priv->general_list);
b7ace2
-	list_attributes_comparator(&priv->general_list, cac_list_compare_path);
b7ace2
-	list_attributes_copy(&priv->general_list, cac_list_meter, 1);
b7ace2
-	/* set other fields as appropriate */
b7ace2
-
b7ace2
-	return priv;
b7ace2
-}
b7ace2
-
b7ace2
-static void cac_free_private_data(cac_private_data_t *priv)
b7ace2
-{
b7ace2
-	free(priv->cac_id);
b7ace2
-	free(priv->cache_buf);
b7ace2
-	free(priv->aca_path);
b7ace2
-	list_destroy(&priv->pki_list);
b7ace2
-	list_destroy(&priv->general_list);
b7ace2
-	free(priv);
b7ace2
-	return;
b7ace2
-}
b7ace2
-
b7ace2
-static int cac_add_object_to_list(list_t *list, const cac_object_t *object)
b7ace2
-{
b7ace2
-	if (list_append(list, object) < 0)
b7ace2
-		return SC_ERROR_UNKNOWN;
b7ace2
-	return SC_SUCCESS;
b7ace2
-}
b7ace2
-
b7ace2
 /*
b7ace2
  * Set up the normal CAC paths
b7ace2
  */
b7ace2
-#define CAC_TO_AID(x) x, sizeof(x)-1
b7ace2
-
b7ace2
 #define CAC_2_RID "\xA0\x00\x00\x01\x16"
b7ace2
-#define CAC_1_RID "\xA0\x00\x00\x00\x79"
b7ace2
 
b7ace2
 static const sc_path_t cac_ACA_Path = {
b7ace2
 	"", 0,
b7ace2
@@ -279,39 +193,6 @@ static const sc_path_t cac_CCC_Path = {
b7ace2
 	{ CAC_TO_AID(CAC_2_RID "\xDB\x00") }
b7ace2
 };
b7ace2
 
b7ace2
-#define MAX_CAC_SLOTS 16		/* Maximum number of slots is 16 now */
b7ace2
-/* default certificate labels for the CAC card */
b7ace2
-static const char *cac_labels[MAX_CAC_SLOTS] = {
b7ace2
-	"CAC ID Certificate",
b7ace2
-	"CAC Email Signature Certificate",
b7ace2
-	"CAC Email Encryption Certificate",
b7ace2
-	"CAC Cert 4",
b7ace2
-	"CAC Cert 5",
b7ace2
-	"CAC Cert 6",
b7ace2
-	"CAC Cert 7",
b7ace2
-	"CAC Cert 8",
b7ace2
-	"CAC Cert 9",
b7ace2
-	"CAC Cert 10",
b7ace2
-	"CAC Cert 11",
b7ace2
-	"CAC Cert 12",
b7ace2
-	"CAC Cert 13",
b7ace2
-	"CAC Cert 14",
b7ace2
-	"CAC Cert 15",
b7ace2
-	"CAC Cert 16"
b7ace2
-};
b7ace2
-
b7ace2
-/* template for a CAC pki object */
b7ace2
-static const cac_object_t cac_cac_pki_obj = {
b7ace2
-	"CAC Certificate", 0x0, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME,
b7ace2
-	{ CAC_TO_AID(CAC_1_RID "\x01\x00") } }
b7ace2
-};
b7ace2
-
b7ace2
-/* template for emulated cuid */
b7ace2
-static const cac_cuid_t cac_cac_cuid = {
b7ace2
-	{ 0xa0, 0x00, 0x00, 0x00, 0x79 },
b7ace2
-	2, 2, 0
b7ace2
-};
b7ace2
-
b7ace2
 /*
b7ace2
  *  CAC general objects defined in 4.3.1.2 of CAC Applet Developer Guide Version 1.0.
b7ace2
  *   doubles as a source for CAC-2 labels.
b7ace2
@@ -1178,7 +1059,7 @@ static int cac_get_properties(sc_card_t *card, cac_properties_t *prop)
b7ace2
  *
b7ace2
  * The rest is just copied from iso7816_select_file
b7ace2
  */
b7ace2
-static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out, int type)
b7ace2
+static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
b7ace2
 {
b7ace2
 	struct sc_context *ctx;
b7ace2
 	struct sc_apdu apdu;
b7ace2
@@ -1356,7 +1237,7 @@ static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc
b7ace2
 
b7ace2
 static int cac_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
b7ace2
 {
b7ace2
-	return cac_select_file_by_type(card, in_path, file_out, card->type);
b7ace2
+	return cac_select_file_by_type(card, in_path, file_out);
b7ace2
 }
b7ace2
 
b7ace2
 static int cac_finish(sc_card_t *card)
b7ace2
@@ -1374,13 +1255,13 @@ static int cac_finish(sc_card_t *card)
b7ace2
 /* select the Card Capabilities Container on CAC-2 */
b7ace2
 static int cac_select_CCC(sc_card_t *card)
b7ace2
 {
b7ace2
-	return cac_select_file_by_type(card, &cac_CCC_Path, NULL, SC_CARD_TYPE_CAC_II);
b7ace2
+	return cac_select_file_by_type(card, &cac_CCC_Path, NULL);
b7ace2
 }
b7ace2
 
b7ace2
 /* Select ACA in non-standard location */
b7ace2
 static int cac_select_ACA(sc_card_t *card)
b7ace2
 {
b7ace2
-	return cac_select_file_by_type(card, &cac_ACA_Path, NULL, SC_CARD_TYPE_CAC_II);
b7ace2
+	return cac_select_file_by_type(card, &cac_ACA_Path, NULL);
b7ace2
 }
b7ace2
 
b7ace2
 static int cac_path_from_cardurl(sc_card_t *card, sc_path_t *path, cac_card_url_t *val, int len)
b7ace2
@@ -1432,7 +1313,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int
b7ace2
 	/* Call without OID set will just select the AID without subseqent
b7ace2
 	 * OID selection, which we need to figure out just now
b7ace2
 	 */
b7ace2
-	cac_select_file_by_type(card, &new_object.path, NULL, SC_CARD_TYPE_CAC_II);
b7ace2
+	cac_select_file_by_type(card, &new_object.path, NULL);
b7ace2
 	r = cac_get_properties(card, &prop);
b7ace2
 	if (r < 0)
b7ace2
 		return SC_ERROR_INTERNAL;
b7ace2
@@ -1444,7 +1325,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int
b7ace2
 
b7ace2
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
 		    "ACA: pki_object found, cert_next=%d (%s), privkey=%d",
b7ace2
-		    priv->cert_next, cac_labels[priv->cert_next],
b7ace2
+		    priv->cert_next, get_cac_label(priv->cert_next),
b7ace2
 		    prop.objects[i].privatekey);
b7ace2
 
b7ace2
 		/* If the private key is not initialized, we can safely
b7ace2
@@ -1460,7 +1341,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int
b7ace2
 		memcpy(new_object.path.value, &prop.objects[i].oid, 2);
b7ace2
 		new_object.path.len = 2;
b7ace2
 		new_object.path.type = SC_PATH_TYPE_FILE_ID;
b7ace2
-		new_object.name = cac_labels[priv->cert_next];
b7ace2
+		new_object.name = get_cac_label(priv->cert_next);
b7ace2
 		new_object.fd = priv->cert_next+1;
b7ace2
 		cac_add_object_to_list(&priv->pki_list, &new_object);
b7ace2
 		priv->cert_next++;
b7ace2
@@ -1488,7 +1369,7 @@ static int cac_parse_cardurl(sc_card_t *card, cac_private_data_t *priv, cac_card
b7ace2
 		 */
b7ace2
 		if (priv->cert_next >= MAX_CAC_SLOTS)
b7ace2
 			break; /* don't fail just because we have more certs than we can support */
b7ace2
-		new_object.name = cac_labels[priv->cert_next];
b7ace2
+		new_object.name = get_cac_label(priv->cert_next);
b7ace2
 		new_object.fd = priv->cert_next+1;
b7ace2
 		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CARDURL: pki_object found, cert_next=%d (%s),", priv->cert_next, new_object.name);
b7ace2
 		cac_add_object_to_list(&priv->pki_list, &new_object);
b7ace2
@@ -1629,7 +1510,7 @@ static int cac_parse_CCC(sc_card_t *card, cac_private_data_t *priv, u8 *tl,
b7ace2
 			if (r < 0)
b7ace2
 				return r;
b7ace2
 
b7ace2
-			r = cac_select_file_by_type(card, &new_path, NULL, SC_CARD_TYPE_CAC_II);
b7ace2
+			r = cac_select_file_by_type(card, &new_path, NULL);
b7ace2
 			if (r < 0)
b7ace2
 				return r;
b7ace2
 
b7ace2
@@ -1740,7 +1621,7 @@ static int cac_select_pki_applet(sc_card_t *card, int index)
b7ace2
 {
b7ace2
 	sc_path_t applet_path = cac_cac_pki_obj.path;
b7ace2
 	applet_path.aid.value[applet_path.aid.len-1] = index;
b7ace2
-	return cac_select_file_by_type(card, &applet_path, NULL, SC_CARD_TYPE_CAC_II);
b7ace2
+	return cac_select_file_by_type(card, &applet_path, NULL);
b7ace2
 }
b7ace2
 
b7ace2
 /*
b7ace2
@@ -1785,7 +1666,7 @@ static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t *
b7ace2
 	for (i = index; i < MAX_CAC_SLOTS; i++) {
b7ace2
 		r = cac_select_pki_applet(card, i);
b7ace2
 		if (r == SC_SUCCESS) {
b7ace2
-			pki_obj.name = cac_labels[i];
b7ace2
+			pki_obj.name = get_cac_label(i);
b7ace2
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
 			    "CAC: pki_object found, cert_next=%d (%s),", i, pki_obj.name);
b7ace2
 			pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i;
b7ace2
@@ -1796,8 +1677,7 @@ static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t *
b7ace2
 
b7ace2
 	/* populate non-PKI objects */
b7ace2
 	for (i=0; i < cac_object_count; i++) {
b7ace2
-		r = cac_select_file_by_type(card, &cac_objects[i].path, NULL,
b7ace2
-		    SC_CARD_TYPE_CAC_II);
b7ace2
+		r = cac_select_file_by_type(card, &cac_objects[i].path, NULL);
b7ace2
 		if (r == SC_SUCCESS) {
b7ace2
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
 			    "CAC: obj_object found, cert_next=%d (%s),",
b7ace2
diff --git a/src/libopensc/card-cac1.c b/src/libopensc/card-cac1.c
b7ace2
new file mode 100644
b7ace2
index 00000000..f3a16547
b7ace2
--- /dev/null
b7ace2
+++ b/src/libopensc/card-cac1.c
b7ace2
@@ -0,0 +1,563 @@
b7ace2
+/*
b7ace2
+ * card-cac1.c: Support for legacy CAC-1
b7ace2
+ * card-default.c: Support for cards with no driver
b7ace2
+ *
b7ace2
+ * Copyright (C) 2001, 2002  Juha Yrjölä <juha.yrjola@iki.fi>
b7ace2
+ * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert <deengert@anl.gov>
b7ace2
+ * Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com>
b7ace2
+ * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com>
b7ace2
+ * Copyright (C) 2016 - 2018, Red Hat, Inc.
b7ace2
+ *
b7ace2
+ * CAC driver author: Robert Relyea <rrelyea@redhat.com>
b7ace2
+ * Further work: Jakub Jelen <jjelen@redhat.com>
b7ace2
+ *
b7ace2
+ * This library is free software; you can redistribute it and/or
b7ace2
+ * modify it under the terms of the GNU Lesser General Public
b7ace2
+ * License as published by the Free Software Foundation; either
b7ace2
+ * version 2.1 of the License, or (at your option) any later version.
b7ace2
+ *
b7ace2
+ * This library is distributed in the hope that it will be useful,
b7ace2
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
b7ace2
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
b7ace2
+ * Lesser General Public License for more details.
b7ace2
+ *
b7ace2
+ * You should have received a copy of the GNU Lesser General Public
b7ace2
+ * License along with this library; if not, write to the Free Software
b7ace2
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
b7ace2
+ */
b7ace2
+
b7ace2
+#if HAVE_CONFIG_H
b7ace2
+#include "config.h"
b7ace2
+#endif
b7ace2
+
b7ace2
+#include <ctype.h>
b7ace2
+#include <fcntl.h>
b7ace2
+#include <limits.h>
b7ace2
+#include <stdlib.h>
b7ace2
+#include <string.h>
b7ace2
+
b7ace2
+#ifdef _WIN32
b7ace2
+#include <io.h>
b7ace2
+#else
b7ace2
+#include <unistd.h>
b7ace2
+#endif
b7ace2
+
b7ace2
+#ifdef ENABLE_OPENSSL
b7ace2
+	/* openssl only needed for card administration */
b7ace2
+#include <openssl/evp.h>
b7ace2
+#include <openssl/bio.h>
b7ace2
+#include <openssl/pem.h>
b7ace2
+#include <openssl/rand.h>
b7ace2
+#include <openssl/rsa.h>
b7ace2
+#endif /* ENABLE_OPENSSL */
b7ace2
+
b7ace2
+#include "internal.h"
b7ace2
+#include "simpletlv.h"
b7ace2
+#include "cardctl.h"
b7ace2
+#ifdef ENABLE_ZLIB
b7ace2
+#include "compression.h"
b7ace2
+#endif
b7ace2
+#include "iso7816.h"
b7ace2
+#include "card-cac-common.h"
b7ace2
+
b7ace2
+/*
b7ace2
+ *  CAC hardware and APDU constants
b7ace2
+ */
b7ace2
+#define CAC_INS_GET_CERTIFICATE       0x36  /* CAC1 command to read a certificate */
b7ace2
+
b7ace2
+/*
b7ace2
+ * OLD cac read certificate, only use with CAC-1 card.
b7ace2
+ */
b7ace2
+static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_len)
b7ace2
+{
b7ace2
+	u8 buf[CAC_MAX_SIZE];
b7ace2
+	u8 *out_ptr;
b7ace2
+	size_t size = 0;
b7ace2
+	size_t left = 0;
b7ace2
+	size_t len, next_len;
b7ace2
+	sc_apdu_t apdu;
b7ace2
+	int r = SC_SUCCESS;
b7ace2
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+	/* get the size */
b7ace2
+	size = left = *out_buf ? *out_len : sizeof(buf);
b7ace2
+	out_ptr = *out_buf ? *out_buf : buf;
b7ace2
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 );
b7ace2
+	next_len = MIN(left, 100);
b7ace2
+	for (; left > 0; left -= len, out_ptr += len) {
b7ace2
+		len = next_len;
b7ace2
+		apdu.resp = out_ptr;
b7ace2
+		apdu.le = len;
b7ace2
+		apdu.resplen = left;
b7ace2
+		r = sc_transmit_apdu(card, &apdu);
b7ace2
+		if (r < 0) {
b7ace2
+			break;
b7ace2
+		}
b7ace2
+		if (apdu.resplen == 0) {
b7ace2
+			r = SC_ERROR_INTERNAL;
b7ace2
+			break;
b7ace2
+		}
b7ace2
+		/* in the old CAC-1, 0x63 means 'more data' in addition to 'pin failed' */
b7ace2
+		if (apdu.sw1 != 0x63)  {
b7ace2
+			/* we've either finished reading, or hit an error, break */
b7ace2
+			r = sc_check_sw(card, apdu.sw1, apdu.sw2);
b7ace2
+			left -= len;
b7ace2
+			break;
b7ace2
+		}
b7ace2
+		next_len = MIN(left, apdu.sw2);
b7ace2
+	}
b7ace2
+	if (r < 0) {
b7ace2
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
b7ace2
+	}
b7ace2
+	r = size - left;
b7ace2
+	if (*out_buf == NULL) {
b7ace2
+		*out_buf = malloc(r);
b7ace2
+		if (*out_buf == NULL) {
b7ace2
+			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
+			    SC_ERROR_OUT_OF_MEMORY);
b7ace2
+		}
b7ace2
+		memcpy(*out_buf, buf, r);
b7ace2
+	}
b7ace2
+	*out_len = r;
b7ace2
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
b7ace2
+}
b7ace2
+
b7ace2
+/*
b7ace2
+ * Callers of this may be expecting a certificate,
b7ace2
+ * select file will have saved the object type for us
b7ace2
+ * as well as set that we want the cert from the object.
b7ace2
+ */
b7ace2
+static int cac_read_binary(sc_card_t *card, unsigned int idx,
b7ace2
+		unsigned char *buf, size_t count, unsigned long flags)
b7ace2
+{
b7ace2
+	cac_private_data_t * priv = CAC_DATA(card);
b7ace2
+	int r = 0;
b7ace2
+	u8 *val = NULL;
b7ace2
+	u8 *cert_ptr;
b7ace2
+	size_t val_len;
b7ace2
+	size_t len, cert_len;
b7ace2
+	u8 cert_type;
b7ace2
+
b7ace2
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+
b7ace2
+	/* if we didn't return it all last time, return the remainder */
b7ace2
+	if (priv->cached) {
b7ace2
+		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
b7ace2
+			 "returning cached value idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u",
b7ace2
+			 idx, count);
b7ace2
+		if (idx > priv->cache_buf_len) {
b7ace2
+			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_END_REACHED);
b7ace2
+		}
b7ace2
+		len = MIN(count, priv->cache_buf_len-idx);
b7ace2
+		memcpy(buf, &priv->cache_buf[idx], len);
b7ace2
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, len);
b7ace2
+	}
b7ace2
+
b7ace2
+	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
b7ace2
+		 "clearing cache idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u",
b7ace2
+		 idx, count);
b7ace2
+	if (priv->cache_buf) {
b7ace2
+		free(priv->cache_buf);
b7ace2
+		priv->cache_buf = NULL;
b7ace2
+		priv->cache_buf_len = 0;
b7ace2
+	}
b7ace2
+
b7ace2
+	r = cac_cac1_get_certificate(card, &val, &val_len);
b7ace2
+	if (r < 0)
b7ace2
+		goto done;
b7ace2
+
b7ace2
+	cert_type = val[0];
b7ace2
+	cert_ptr = val + 1;
b7ace2
+	cert_len = val_len - 1;
b7ace2
+
b7ace2
+	/* if the info byte is 1, then the cert is compressed, decompress it */
b7ace2
+	if ((cert_type & 0x3) == 1) {
b7ace2
+#ifdef ENABLE_ZLIB
b7ace2
+		r = sc_decompress_alloc(&priv->cache_buf, &priv->cache_buf_len,
b7ace2
+			cert_ptr, cert_len, COMPRESSION_AUTO);
b7ace2
+#else
b7ace2
+		sc_log(card->ctx, "CAC compression not supported, no zlib");
b7ace2
+		r = SC_ERROR_NOT_SUPPORTED;
b7ace2
+#endif
b7ace2
+		if (r)
b7ace2
+			goto done;
b7ace2
+		cert_ptr = val;
b7ace2
+	} else if (cert_len > 0) {
b7ace2
+		priv->cache_buf = malloc(cert_len);
b7ace2
+		if (priv->cache_buf == NULL) {
b7ace2
+			r = SC_ERROR_OUT_OF_MEMORY;
b7ace2
+			goto done;
b7ace2
+		}
b7ace2
+		priv->cache_buf_len = cert_len;
b7ace2
+		memcpy(priv->cache_buf, cert_ptr, cert_len);
b7ace2
+	}
b7ace2
+
b7ace2
+	/* OK we've read the data, now copy the required portion out to the callers buffer */
b7ace2
+	priv->cached = 1;
b7ace2
+	len = MIN(count, priv->cache_buf_len-idx);
b7ace2
+	memcpy(buf, &priv->cache_buf[idx], len);
b7ace2
+	r = len;
b7ace2
+done:
b7ace2
+	if (val)
b7ace2
+		free(val);
b7ace2
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
b7ace2
+}
b7ace2
+
b7ace2
+/*
b7ace2
+ * CAC cards use SC_PATH_SELECT_OBJECT_ID rather than SC_PATH_SELECT_FILE_ID. In order to use more
b7ace2
+ * of the PKCS #15 structure, we call the selection SC_PATH_SELECT_FILE_ID, but we set p1 to 2 instead
b7ace2
+ * of 0. Also cac1 does not do any FCI, but it doesn't understand not selecting it. It returns invalid INS
b7ace2
+ * if it doesn't like anything about the select, so we always 'request' FCI for CAC1
b7ace2
+ *
b7ace2
+ * The rest is just copied from iso7816_select_file
b7ace2
+ */
b7ace2
+static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
b7ace2
+{
b7ace2
+	struct sc_context *ctx;
b7ace2
+	struct sc_apdu apdu;
b7ace2
+	unsigned char buf[SC_MAX_APDU_BUFFER_SIZE];
b7ace2
+	unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
b7ace2
+	int r, pathlen, pathtype;
b7ace2
+	struct sc_file *file = NULL;
b7ace2
+	cac_private_data_t * priv = CAC_DATA(card);
b7ace2
+
b7ace2
+	assert(card != NULL && in_path != NULL);
b7ace2
+	ctx = card->ctx;
b7ace2
+
b7ace2
+	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+
b7ace2
+	memcpy(path, in_path->value, in_path->len);
b7ace2
+	pathlen = in_path->len;
b7ace2
+	pathtype = in_path->type;
b7ace2
+
b7ace2
+	sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
+		 "path->aid=%x %x %x %x %x %x %x  len=%"SC_FORMAT_LEN_SIZE_T"u, path->value = %x %x %x %x len=%"SC_FORMAT_LEN_SIZE_T"u path->type=%d (%x)",
b7ace2
+		 in_path->aid.value[0], in_path->aid.value[1],
b7ace2
+		 in_path->aid.value[2], in_path->aid.value[3],
b7ace2
+		 in_path->aid.value[4], in_path->aid.value[5],
b7ace2
+		 in_path->aid.value[6], in_path->aid.len, in_path->value[0],
b7ace2
+		 in_path->value[1], in_path->value[2], in_path->value[3],
b7ace2
+		 in_path->len, in_path->type, in_path->type);
b7ace2
+	sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "file_out=%p index=%d count=%d\n",
b7ace2
+		 file_out, in_path->index, in_path->count);
b7ace2
+
b7ace2
+	/* Sigh, sc_key_select expects paths to keys to have specific formats. There is no override.
b7ace2
+	 * we have to add some bytes to the path to make it happy. A better fix would be to give sc_key_file
b7ace2
+	 * a flag that says 'no, really this path is fine'.  We only need to do this for private keys */
b7ace2
+	if ((pathlen > 2) && (pathlen <= 4) && memcmp(path, "\x3F\x00", 2) == 0) {
b7ace2
+		if (pathlen > 2) {
b7ace2
+			path += 2;
b7ace2
+			pathlen -= 2;
b7ace2
+		}
b7ace2
+	}
b7ace2
+
b7ace2
+
b7ace2
+	/* CAC has multiple different type of objects that aren't PKCS #15. When we read
b7ace2
+	 * them we need convert them to something PKCS #15 would understand. Find the object
b7ace2
+	 * and object type here:
b7ace2
+	 */
b7ace2
+	if (priv) { /* don't record anything if we haven't been initialized yet */
b7ace2
+		/* forget any old cached values */
b7ace2
+		if (priv->cache_buf) {
b7ace2
+			free(priv->cache_buf);
b7ace2
+			priv->cache_buf = NULL;
b7ace2
+		}
b7ace2
+		priv->cache_buf_len = 0;
b7ace2
+		priv->cached = 0;
b7ace2
+	}
b7ace2
+
b7ace2
+	if (in_path->aid.len) {
b7ace2
+		if (!pathlen) {
b7ace2
+			memcpy(path, in_path->aid.value, in_path->aid.len);
b7ace2
+			pathlen = in_path->aid.len;
b7ace2
+			pathtype = SC_PATH_TYPE_DF_NAME;
b7ace2
+		} else {
b7ace2
+			/* First, select the application */
b7ace2
+			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"select application" );
b7ace2
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 4, 0);
b7ace2
+			apdu.data = in_path->aid.value;
b7ace2
+			apdu.datalen = in_path->aid.len;
b7ace2
+			apdu.lc = in_path->aid.len;
b7ace2
+
b7ace2
+			r = sc_transmit_apdu(card, &apdu);
b7ace2
+			LOG_TEST_RET(ctx, r, "APDU transmit failed");
b7ace2
+			r = sc_check_sw(card, apdu.sw1, apdu.sw2);
b7ace2
+			if (r)
b7ace2
+				LOG_FUNC_RETURN(ctx, r);
b7ace2
+
b7ace2
+		}
b7ace2
+	}
b7ace2
+
b7ace2
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
b7ace2
+
b7ace2
+	switch (pathtype) {
b7ace2
+	/* ideally we would had SC_PATH_TYPE_OBJECT_ID and add code to the iso7816 select.
b7ace2
+	 * Unfortunately we'd also need to update the caching code as well. For now just
b7ace2
+	 * use FILE_ID and change p1 here */
b7ace2
+	case SC_PATH_TYPE_FILE_ID:
b7ace2
+		apdu.p1 = 2;
b7ace2
+		if (pathlen != 2)
b7ace2
+			return SC_ERROR_INVALID_ARGUMENTS;
b7ace2
+		break;
b7ace2
+	case SC_PATH_TYPE_DF_NAME:
b7ace2
+		apdu.p1 = 4;
b7ace2
+		break;
b7ace2
+	default:
b7ace2
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
b7ace2
+	}
b7ace2
+	apdu.lc = pathlen;
b7ace2
+	apdu.data = path;
b7ace2
+	apdu.datalen = pathlen;
b7ace2
+	apdu.resp = buf;
b7ace2
+	apdu.resplen = sizeof(buf);
b7ace2
+	apdu.le = sc_get_max_recv_size(card) < 256 ? sc_get_max_recv_size(card) : 256;
b7ace2
+	apdu.p2 = 0x00;
b7ace2
+
b7ace2
+	r = sc_transmit_apdu(card, &apdu);
b7ace2
+	LOG_TEST_RET(ctx, r, "APDU transmit failed");
b7ace2
+
b7ace2
+	if (file_out == NULL) {
b7ace2
+		/* For some cards 'SELECT' can be only with request to return FCI/FCP. */
b7ace2
+		r = sc_check_sw(card, apdu.sw1, apdu.sw2);
b7ace2
+		if (apdu.sw1 == 0x6A && apdu.sw2 == 0x86)   {
b7ace2
+			apdu.p2 = 0x00;
b7ace2
+			apdu.resplen = sizeof(buf);
b7ace2
+			if (sc_transmit_apdu(card, &apdu) == SC_SUCCESS)
b7ace2
+				r = sc_check_sw(card, apdu.sw1, apdu.sw2);
b7ace2
+		}
b7ace2
+		if (apdu.sw1 == 0x61)
b7ace2
+			LOG_FUNC_RETURN(ctx, SC_SUCCESS);
b7ace2
+		LOG_FUNC_RETURN(ctx, r);
b7ace2
+	}
b7ace2
+
b7ace2
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
b7ace2
+	if (r)
b7ace2
+		LOG_FUNC_RETURN(ctx, r);
b7ace2
+
b7ace2
+	/* CAC cards never return FCI, fake one */
b7ace2
+	file = sc_file_new();
b7ace2
+	if (file == NULL)
b7ace2
+			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
b7ace2
+	file->path = *in_path;
b7ace2
+	file->size = CAC_MAX_SIZE; /* we don't know how big, just give a large size until we can read the file */
b7ace2
+
b7ace2
+	*file_out = file;
b7ace2
+	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
b7ace2
+
b7ace2
+}
b7ace2
+
b7ace2
+static int cac_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
b7ace2
+{
b7ace2
+	return cac_select_file_by_type(card, in_path, file_out);
b7ace2
+}
b7ace2
+
b7ace2
+static int cac_finish(sc_card_t *card)
b7ace2
+{
b7ace2
+	cac_private_data_t * priv = CAC_DATA(card);
b7ace2
+
b7ace2
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+	if (priv) {
b7ace2
+		cac_free_private_data(priv);
b7ace2
+	}
b7ace2
+	return SC_SUCCESS;
b7ace2
+}
b7ace2
+
b7ace2
+
b7ace2
+/* select a CAC pki applet by index */
b7ace2
+static int cac_select_pki_applet(sc_card_t *card, int index)
b7ace2
+{
b7ace2
+	sc_path_t applet_path = cac_cac_pki_obj.path;
b7ace2
+	applet_path.aid.value[applet_path.aid.len-1] = index;
b7ace2
+	return cac_select_file_by_type(card, &applet_path, NULL);
b7ace2
+}
b7ace2
+
b7ace2
+/*
b7ace2
+ *  Find the first existing CAC applet. If none found, then this isn't a CAC
b7ace2
+ */
b7ace2
+static int cac_find_first_pki_applet(sc_card_t *card, int *index_out)
b7ace2
+{
b7ace2
+	int r, i;
b7ace2
+
b7ace2
+	for (i = 0; i < MAX_CAC_SLOTS; i++) {
b7ace2
+		r = cac_select_pki_applet(card, i);
b7ace2
+		if (r == SC_SUCCESS) {
b7ace2
+			u8 data[2];
b7ace2
+			sc_apdu_t apdu;
b7ace2
+
b7ace2
+			/* Try to read first two bytes of the buffer to
b7ace2
+			 * make sure it is not just malfunctioning card
b7ace2
+			 */
b7ace2
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_2,
b7ace2
+			    CAC_INS_GET_CERTIFICATE, 0x00, 0x00);
b7ace2
+			apdu.le = 0x02;
b7ace2
+			apdu.resplen = 2;
b7ace2
+			apdu.resp = data;
b7ace2
+			r = sc_transmit_apdu(card, &apdu);
b7ace2
+			/* SW1 = 0x63 means more data in CAC1 */
b7ace2
+			if (r == SC_SUCCESS && apdu.sw1 != 0x63)
b7ace2
+				continue;
b7ace2
+
b7ace2
+			*index_out = i;
b7ace2
+			return SC_SUCCESS;
b7ace2
+		}
b7ace2
+	}
b7ace2
+	return SC_ERROR_OBJECT_NOT_FOUND;
b7ace2
+}
b7ace2
+
b7ace2
+static int cac_populate_cac1(sc_card_t *card, int index, cac_private_data_t *priv)
b7ace2
+{
b7ace2
+	int r, i;
b7ace2
+	cac_object_t pki_obj = cac_cac_pki_obj;
b7ace2
+	u8 buf[100];
b7ace2
+	u8 *val;
b7ace2
+	size_t val_len;
b7ace2
+
b7ace2
+	/* populate PKI objects */
b7ace2
+	for (i = index; i < MAX_CAC_SLOTS; i++) {
b7ace2
+		r = cac_select_pki_applet(card, i);
b7ace2
+		if (r == SC_SUCCESS) {
b7ace2
+			pki_obj.name = get_cac_label(i);
b7ace2
+			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
+			    "CAC: pki_object found, cert_next=%d (%s),", i, pki_obj.name);
b7ace2
+			pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i;
b7ace2
+			pki_obj.fd = i+1; /* don't use id of zero */
b7ace2
+			cac_add_object_to_list(&priv->pki_list, &pki_obj);
b7ace2
+		}
b7ace2
+	}
b7ace2
+
b7ace2
+	/*
b7ace2
+	 * create a cuid to simulate the cac 2 cuid.
b7ace2
+	 */
b7ace2
+	priv->cuid = cac_cac_cuid;
b7ace2
+	/* create a serial number by hashing the first 100 bytes of the
b7ace2
+	 * first certificate on the card */
b7ace2
+	r = cac_select_pki_applet(card, index);
b7ace2
+	if (r < 0) {
b7ace2
+		return r; /* shouldn't happen unless the card has been removed or is malfunctioning */
b7ace2
+	}
b7ace2
+	val = buf;
b7ace2
+	val_len = sizeof(buf);
b7ace2
+	r = cac_cac1_get_certificate(card, &val, &val_len);
b7ace2
+	if (r >= 0) {
b7ace2
+		priv->cac_id = malloc(20);
b7ace2
+		if (priv->cac_id == NULL) {
b7ace2
+			return SC_ERROR_OUT_OF_MEMORY;
b7ace2
+		}
b7ace2
+#ifdef ENABLE_OPENSSL
b7ace2
+		SHA1(val, val_len, priv->cac_id);
b7ace2
+		priv->cac_id_len = 20;
b7ace2
+		sc_debug_hex(card->ctx, SC_LOG_DEBUG_VERBOSE,
b7ace2
+		    "cuid", priv->cac_id, priv->cac_id_len);
b7ace2
+#else
b7ace2
+		sc_log(card->ctx, "OpenSSL Required");
b7ace2
+		return SC_ERROR_NOT_SUPPORTED;
b7ace2
+#endif /* ENABLE_OPENSSL */
b7ace2
+	}
b7ace2
+	return SC_SUCCESS;
b7ace2
+}
b7ace2
+
b7ace2
+/*
b7ace2
+ * Look for a CAC card. If it exists, initialize our data structures
b7ace2
+ */
b7ace2
+static int cac_find_and_initialize(sc_card_t *card, int initialize)
b7ace2
+{
b7ace2
+	int r, index;
b7ace2
+	cac_private_data_t *priv = NULL;
b7ace2
+
b7ace2
+	/* already initialized? */
b7ace2
+	if (card->drv_data) {
b7ace2
+		return SC_SUCCESS;
b7ace2
+	}
b7ace2
+
b7ace2
+	/* is this a CAC Alt token without any accompanying structures */
b7ace2
+	r = cac_find_first_pki_applet(card, &index);
b7ace2
+	if (r == SC_SUCCESS) {
b7ace2
+		sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "PKI applet found, is bare CAC-1");
b7ace2
+		if (!initialize) /* match card only */
b7ace2
+			return r;
b7ace2
+
b7ace2
+		if (!priv) {
b7ace2
+			priv = cac_new_private_data();
b7ace2
+			if (!priv)
b7ace2
+				return SC_ERROR_OUT_OF_MEMORY;
b7ace2
+		}
b7ace2
+		card->drv_data = priv; /* needed for the read_binary() */
b7ace2
+		r = cac_populate_cac1(card, index, priv);
b7ace2
+		if (r == SC_SUCCESS) {
b7ace2
+			card->type = SC_CARD_TYPE_CAC_I;
b7ace2
+			return r;
b7ace2
+		}
b7ace2
+		card->drv_data = NULL; /* reset on failure */
b7ace2
+	}
b7ace2
+	if (priv) {
b7ace2
+		cac_free_private_data(priv);
b7ace2
+	}
b7ace2
+	return r;
b7ace2
+}
b7ace2
+
b7ace2
+
b7ace2
+/* NOTE: returns a bool, 1 card matches, 0 it does not */
b7ace2
+static int cac_match_card(sc_card_t *card)
b7ace2
+{
b7ace2
+	int r;
b7ace2
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+	/* Since we send an APDU, the card's logout function may be called...
b7ace2
+	 * however it may be in dirty memory */
b7ace2
+	card->ops->logout = NULL;
b7ace2
+
b7ace2
+	r = cac_find_and_initialize(card, 0);
b7ace2
+	return (r == SC_SUCCESS); /* never match */
b7ace2
+}
b7ace2
+
b7ace2
+
b7ace2
+static int cac_init(sc_card_t *card)
b7ace2
+{
b7ace2
+	int r;
b7ace2
+	unsigned long flags;
b7ace2
+
b7ace2
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
b7ace2
+
b7ace2
+	r = cac_find_and_initialize(card, 1);
b7ace2
+	if (r < 0) {
b7ace2
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_CARD);
b7ace2
+	}
b7ace2
+	flags = SC_ALGORITHM_RSA_RAW;
b7ace2
+
b7ace2
+	_sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */
b7ace2
+	_sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */
b7ace2
+	_sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */
b7ace2
+
b7ace2
+	card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
b7ace2
+
b7ace2
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
b7ace2
+}
b7ace2
+
b7ace2
+static struct sc_card_operations cac_ops;
b7ace2
+
b7ace2
+static struct sc_card_driver cac1_drv = {
b7ace2
+	"Common Access Card (CAC 1)",
b7ace2
+	"cac1",
b7ace2
+	&cac_ops,
b7ace2
+	NULL, 0, NULL
b7ace2
+};
b7ace2
+
b7ace2
+static struct sc_card_driver * sc_get_driver(void)
b7ace2
+{
b7ace2
+	/* Inherit most of the things from the CAC driver */
b7ace2
+	struct sc_card_driver *cac_drv = sc_get_cac_driver();
b7ace2
+
b7ace2
+	cac_ops = *cac_drv->ops;
b7ace2
+	cac_ops.match_card = cac_match_card;
b7ace2
+	cac_ops.init = cac_init;
b7ace2
+	cac_ops.finish = cac_finish;
b7ace2
+
b7ace2
+	cac_ops.select_file =  cac_select_file; /* need to record object type */
b7ace2
+	cac_ops.read_binary = cac_read_binary;
b7ace2
+
b7ace2
+	return &cac1_drv;
b7ace2
+}
b7ace2
+
b7ace2
+
b7ace2
+struct sc_card_driver * sc_get_cac1_driver(void)
b7ace2
+{
b7ace2
+	return sc_get_driver();
b7ace2
+}
b7ace2
diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
b7ace2
index 5d545b35..f4df17fb 100644
b7ace2
--- a/src/libopensc/cards.h
b7ace2
+++ b/src/libopensc/cards.h
b7ace2
@@ -286,6 +286,7 @@ extern sc_card_driver_t *sc_get_gids_driver(void);
b7ace2
 extern sc_card_driver_t *sc_get_jpki_driver(void);
b7ace2
 extern sc_card_driver_t *sc_get_coolkey_driver(void);
b7ace2
 extern sc_card_driver_t *sc_get_cac_driver(void);
b7ace2
+extern sc_card_driver_t *sc_get_cac1_driver(void);
b7ace2
 extern sc_card_driver_t *sc_get_npa_driver(void);
b7ace2
 
b7ace2
 #ifdef __cplusplus
b7ace2
diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c
b7ace2
index 98e6038a..5b5d4996 100644
b7ace2
--- a/src/libopensc/ctx.c
b7ace2
+++ b/src/libopensc/ctx.c
b7ace2
@@ -146,6 +146,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
b7ace2
 	{ "openpgp",	(void *(*)(void)) sc_get_openpgp_driver },
b7ace2
 	{ "jpki",	(void *(*)(void)) sc_get_jpki_driver },
b7ace2
 	{ "npa",	(void *(*)(void)) sc_get_npa_driver },
b7ace2
+	{ "cac1",	(void *(*)(void)) sc_get_cac1_driver },
b7ace2
 	/* The default driver should be last, as it handles all the
b7ace2
 	 * unrecognized cards. */
b7ace2
 	{ "default",	(void *(*)(void)) sc_get_default_driver },