From 0ea42e6920a207643cbf3627fad646b266832c5f Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 31 2019 10:14:18 +0000 Subject: import opensc-0.19.0-3.el7 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..846cace --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/opensc-0.19.0.tar.gz diff --git a/.opensc.metadata b/.opensc.metadata new file mode 100644 index 0000000..ec57eb9 --- /dev/null +++ b/.opensc.metadata @@ -0,0 +1 @@ +56cd654550aed081eb8ed86edba86e6d766133c4 SOURCES/opensc-0.19.0.tar.gz diff --git a/SOURCES/opensc-0.19.0-cac1.patch b/SOURCES/opensc-0.19.0-cac1.patch new file mode 100644 index 0000000..a864613 --- /dev/null +++ b/SOURCES/opensc-0.19.0-cac1.patch @@ -0,0 +1,1113 @@ +commit a2efcb184fcb0302bfadeb97b5cf8953cb77d0fb +Author: Jakub Jelen +Date: Tue Oct 9 16:03:19 2018 +0200 + + WIP: Add minimal CAC1 driver for legacy cards. + + It is using the same pkcs15 backend as the CAC2 cards as well as some of + the CAC2 driver methods. + + The separation is made mostly for easier card matching. + +diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am +index a99b0c57..5a17df2b 100644 +--- a/src/libopensc/Makefile.am ++++ b/src/libopensc/Makefile.am +@@ -40,7 +40,8 @@ libopensc_la_SOURCES_BASE = \ + card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \ + card-oberthur.c card-belpic.c card-atrust-acos.c \ + card-entersafe.c card-epass2003.c card-coolkey.c card-incrypto34.c \ +- card-piv.c card-cac.c card-muscle.c card-acos5.c \ ++ card-piv.c card-cac-common.c card-cac.c card-cac1.c \ ++ card-muscle.c card-acos5.c \ + card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \ + card-rtecp.c card-westcos.c card-myeid.c \ + card-itacns.c card-authentic.c \ +diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak +index 10a3b0a9..7ef642b6 100644 +--- a/src/libopensc/Makefile.mak ++++ b/src/libopensc/Makefile.mak +@@ -19,7 +19,7 @@ OBJECTS = \ + card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \ + card-oberthur.obj card-belpic.obj card-atrust-acos.obj \ + card-entersafe.obj card-epass2003.obj card-coolkey.obj \ +- card-incrypto34.obj card-cac.obj card-piv.obj card-muscle.obj \ ++ card-incrypto34.obj card-cac.obj card-cac1.obj card-piv.obj card-muscle.obj \ + card-acos5.obj \ + card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \ + card-rtecp.obj card-westcos.obj card-myeid.obj \ +diff --git a/src/libopensc/card-cac-common.c b/src/libopensc/card-cac-common.c +new file mode 100644 +index 00000000..6c338bf9 +--- /dev/null ++++ b/src/libopensc/card-cac-common.c +@@ -0,0 +1,116 @@ ++/* ++ * card-cac-common.c: Code shared among CAC1 and CAC2 drivers ++ * ++ * Copyright (C) 2018, Red Hat, Inc. ++ * ++ * Author: Jakub Jelen ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#if HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++ ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ ++#include "internal.h" ++#include "iso7816.h" ++#include "card-cac-common.h" ++ ++/* default certificate labels for the CAC card */ ++const char *cac_labels[MAX_CAC_SLOTS] = { ++ "CAC ID Certificate", ++ "CAC Email Signature Certificate", ++ "CAC Email Encryption Certificate", ++ "CAC Cert 4", ++ "CAC Cert 5", ++ "CAC Cert 6", ++ "CAC Cert 7", ++ "CAC Cert 8", ++ "CAC Cert 9", ++ "CAC Cert 10", ++ "CAC Cert 11", ++ "CAC Cert 12", ++ "CAC Cert 13", ++ "CAC Cert 14", ++ "CAC Cert 15", ++ "CAC Cert 16" ++}; ++ ++const char *get_cac_label(int index) ++{ ++ if (index < 0 || index >= MAX_CAC_SLOTS) ++ return NULL; ++ ++ return cac_labels[index]; ++} ++ ++static int cac_list_compare_path(const void *a, const void *b) ++{ ++ if (a == NULL || b == NULL) ++ return 1; ++ return memcmp( &((cac_object_t *) a)->path, ++ &((cac_object_t *) b)->path, sizeof(sc_path_t)); ++} ++ ++/* For SimCList autocopy, we need to know the size of the data elements */ ++static size_t cac_list_meter(const void *el) { ++ return sizeof(cac_object_t); ++} ++ ++cac_private_data_t *cac_new_private_data(void) ++{ ++ cac_private_data_t *priv; ++ priv = calloc(1, sizeof(cac_private_data_t)); ++ if (!priv) ++ return NULL; ++ list_init(&priv->pki_list); ++ list_attributes_comparator(&priv->pki_list, cac_list_compare_path); ++ list_attributes_copy(&priv->pki_list, cac_list_meter, 1); ++ list_init(&priv->general_list); ++ list_attributes_comparator(&priv->general_list, cac_list_compare_path); ++ list_attributes_copy(&priv->general_list, cac_list_meter, 1); ++ /* set other fields as appropriate */ ++ ++ return priv; ++} ++ ++void cac_free_private_data(cac_private_data_t *priv) ++{ ++ free(priv->cac_id); ++ free(priv->cache_buf); ++ free(priv->aca_path); ++ list_destroy(&priv->pki_list); ++ list_destroy(&priv->general_list); ++ free(priv); ++ return; ++} ++ ++int cac_add_object_to_list(list_t *list, const cac_object_t *object) ++{ ++ if (list_append(list, object) < 0) ++ return SC_ERROR_UNKNOWN; ++ return SC_SUCCESS; ++} ++ +diff --git a/src/libopensc/card-cac-common.h b/src/libopensc/card-cac-common.h +new file mode 100644 +index 00000000..77f14761 +--- /dev/null ++++ b/src/libopensc/card-cac-common.h +@@ -0,0 +1,89 @@ ++/* ++ * card-cac-common.h: Code shared among CAC1 and CAC2 drivers ++ * ++ * Copyright (C) 2018, Red Hat, Inc. ++ * ++ * Author: Jakub Jelen ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef HAVE_CARD_CAC_COMMON_H ++#define HAVE_CARD_CAC_COMMON_H ++ ++#define CAC_MAX_SIZE 4096 /* arbitrary, just needs to be 'large enough' */ ++ ++typedef struct cac_cuid { ++ u8 gsc_rid[5]; ++ u8 manufacturer_id; ++ u8 card_type; ++ u8 card_id; ++} cac_cuid_t; ++ ++/* data structures to store meta data about CAC objects */ ++typedef struct cac_object { ++ const char *name; ++ int fd; ++ sc_path_t path; ++} cac_object_t; ++ ++/* ++ * CAC private data per card state ++ */ ++typedef struct cac_private_data { ++ int object_type; /* select set this so we know how to read the file */ ++ int cert_next; /* index number for the next certificate found in the list */ ++ u8 *cache_buf; /* cached version of the currently selected file */ ++ size_t cache_buf_len; /* length of the cached selected file */ ++ int cached; /* is the cached selected file valid */ ++ cac_cuid_t cuid; /* card unique ID from the CCC */ ++ u8 *cac_id; /* card serial number */ ++ size_t cac_id_len; /* card serial number len */ ++ list_t pki_list; /* list of pki containers */ ++ cac_object_t *pki_current; /* current pki object _ctl function */ ++ list_t general_list; /* list of general containers */ ++ cac_object_t *general_current; /* current object for _ctl function */ ++ sc_path_t *aca_path; /* ACA path to be selected before pin verification */ ++} cac_private_data_t; ++ ++#define CAC_DATA(card) ((cac_private_data_t*)card->drv_data) ++ ++/* ++ * Set up the normal CAC paths ++ */ ++#define CAC_1_RID "\xA0\x00\x00\x00\x79" ++#define CAC_TO_AID(x) x, sizeof(x)-1 ++ ++ ++#define MAX_CAC_SLOTS 16 /* Maximum number of slots is 16 now */ ++ ++/* template for a CAC pki object */ ++static const cac_object_t cac_cac_pki_obj = { ++ "CAC Certificate", 0x0, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, ++ { CAC_TO_AID(CAC_1_RID "\x01\x00") } } ++}; ++ ++/* template for emulated cuid */ ++static const cac_cuid_t cac_cac_cuid = { ++ { 0xa0, 0x00, 0x00, 0x00, 0x79 }, ++ 2, 2, 0 ++}; ++ ++cac_private_data_t *cac_new_private_data(void); ++void cac_free_private_data(cac_private_data_t *priv); ++int cac_add_object_to_list(list_t *list, const cac_object_t *object); ++const char *get_cac_label(int index); ++ ++#endif /* HAVE_CARD_CAC_COMMON_H */ +diff --git a/src/libopensc/card-cac.c b/src/libopensc/card-cac.c +index bd4e0336..f9620009 100644 +--- a/src/libopensc/card-cac.c ++++ b/src/libopensc/card-cac.c +@@ -58,8 +58,8 @@ + #include "compression.h" + #endif + #include "iso7816.h" ++#include "card-cac-common.h" + +-#define CAC_MAX_SIZE 4096 /* arbitrary, just needs to be 'large enough' */ + /* + * CAC hardware and APDU constants + */ +@@ -147,20 +147,6 @@ typedef struct cac_card_url { + u8 keyCryptoAlgorithm; /* not used for VM cards */ + } cac_card_url_t; + +-typedef struct cac_cuid { +- u8 gsc_rid[5]; +- u8 manufacturer_id; +- u8 card_type; +- u8 card_id; +-} cac_cuid_t; +- +-/* data structures to store meta data about CAC objects */ +-typedef struct cac_object { +- const char *name; +- int fd; +- sc_path_t path; +-} cac_object_t; +- + #define CAC_MAX_OBJECTS 16 + + typedef struct { +@@ -190,82 +176,10 @@ typedef struct { + #define CAC_OBJECT_TYPE_TLV_FILE 4 + #define CAC_OBJECT_TYPE_GENERIC 5 + +-/* +- * CAC private data per card state +- */ +-typedef struct cac_private_data { +- int object_type; /* select set this so we know how to read the file */ +- int cert_next; /* index number for the next certificate found in the list */ +- u8 *cache_buf; /* cached version of the currently selected file */ +- size_t cache_buf_len; /* length of the cached selected file */ +- int cached; /* is the cached selected file valid */ +- cac_cuid_t cuid; /* card unique ID from the CCC */ +- u8 *cac_id; /* card serial number */ +- size_t cac_id_len; /* card serial number len */ +- list_t pki_list; /* list of pki containers */ +- cac_object_t *pki_current; /* current pki object _ctl function */ +- list_t general_list; /* list of general containers */ +- cac_object_t *general_current; /* current object for _ctl function */ +- sc_path_t *aca_path; /* ACA path to be selected before pin verification */ +-} cac_private_data_t; +- +-#define CAC_DATA(card) ((cac_private_data_t*)card->drv_data) +- +-static int cac_list_compare_path(const void *a, const void *b) +-{ +- if (a == NULL || b == NULL) +- return 1; +- return memcmp( &((cac_object_t *) a)->path, +- &((cac_object_t *) b)->path, sizeof(sc_path_t)); +-} +- +-/* For SimCList autocopy, we need to know the size of the data elements */ +-static size_t cac_list_meter(const void *el) { +- return sizeof(cac_object_t); +-} +- +-static cac_private_data_t *cac_new_private_data(void) +-{ +- cac_private_data_t *priv; +- priv = calloc(1, sizeof(cac_private_data_t)); +- if (!priv) +- return NULL; +- list_init(&priv->pki_list); +- list_attributes_comparator(&priv->pki_list, cac_list_compare_path); +- list_attributes_copy(&priv->pki_list, cac_list_meter, 1); +- list_init(&priv->general_list); +- list_attributes_comparator(&priv->general_list, cac_list_compare_path); +- list_attributes_copy(&priv->general_list, cac_list_meter, 1); +- /* set other fields as appropriate */ +- +- return priv; +-} +- +-static void cac_free_private_data(cac_private_data_t *priv) +-{ +- free(priv->cac_id); +- free(priv->cache_buf); +- free(priv->aca_path); +- list_destroy(&priv->pki_list); +- list_destroy(&priv->general_list); +- free(priv); +- return; +-} +- +-static int cac_add_object_to_list(list_t *list, const cac_object_t *object) +-{ +- if (list_append(list, object) < 0) +- return SC_ERROR_UNKNOWN; +- return SC_SUCCESS; +-} +- + /* + * Set up the normal CAC paths + */ +-#define CAC_TO_AID(x) x, sizeof(x)-1 +- + #define CAC_2_RID "\xA0\x00\x00\x01\x16" +-#define CAC_1_RID "\xA0\x00\x00\x00\x79" + + static const sc_path_t cac_ACA_Path = { + "", 0, +@@ -279,39 +193,6 @@ static const sc_path_t cac_CCC_Path = { + { CAC_TO_AID(CAC_2_RID "\xDB\x00") } + }; + +-#define MAX_CAC_SLOTS 16 /* Maximum number of slots is 16 now */ +-/* default certificate labels for the CAC card */ +-static const char *cac_labels[MAX_CAC_SLOTS] = { +- "CAC ID Certificate", +- "CAC Email Signature Certificate", +- "CAC Email Encryption Certificate", +- "CAC Cert 4", +- "CAC Cert 5", +- "CAC Cert 6", +- "CAC Cert 7", +- "CAC Cert 8", +- "CAC Cert 9", +- "CAC Cert 10", +- "CAC Cert 11", +- "CAC Cert 12", +- "CAC Cert 13", +- "CAC Cert 14", +- "CAC Cert 15", +- "CAC Cert 16" +-}; +- +-/* template for a CAC pki object */ +-static const cac_object_t cac_cac_pki_obj = { +- "CAC Certificate", 0x0, { { 0 }, 0, 0, 0, SC_PATH_TYPE_DF_NAME, +- { CAC_TO_AID(CAC_1_RID "\x01\x00") } } +-}; +- +-/* template for emulated cuid */ +-static const cac_cuid_t cac_cac_cuid = { +- { 0xa0, 0x00, 0x00, 0x00, 0x79 }, +- 2, 2, 0 +-}; +- + /* + * CAC general objects defined in 4.3.1.2 of CAC Applet Developer Guide Version 1.0. + * doubles as a source for CAC-2 labels. +@@ -1178,7 +1059,7 @@ static int cac_get_properties(sc_card_t *card, cac_properties_t *prop) + * + * The rest is just copied from iso7816_select_file + */ +-static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out, int type) ++static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) + { + struct sc_context *ctx; + struct sc_apdu apdu; +@@ -1356,7 +1237,7 @@ static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc + + static int cac_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) + { +- return cac_select_file_by_type(card, in_path, file_out, card->type); ++ return cac_select_file_by_type(card, in_path, file_out); + } + + static int cac_finish(sc_card_t *card) +@@ -1374,13 +1255,13 @@ static int cac_finish(sc_card_t *card) + /* select the Card Capabilities Container on CAC-2 */ + static int cac_select_CCC(sc_card_t *card) + { +- return cac_select_file_by_type(card, &cac_CCC_Path, NULL, SC_CARD_TYPE_CAC_II); ++ return cac_select_file_by_type(card, &cac_CCC_Path, NULL); + } + + /* Select ACA in non-standard location */ + static int cac_select_ACA(sc_card_t *card) + { +- return cac_select_file_by_type(card, &cac_ACA_Path, NULL, SC_CARD_TYPE_CAC_II); ++ return cac_select_file_by_type(card, &cac_ACA_Path, NULL); + } + + static int cac_path_from_cardurl(sc_card_t *card, sc_path_t *path, cac_card_url_t *val, int len) +@@ -1432,7 +1313,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int + /* Call without OID set will just select the AID without subseqent + * OID selection, which we need to figure out just now + */ +- cac_select_file_by_type(card, &new_object.path, NULL, SC_CARD_TYPE_CAC_II); ++ cac_select_file_by_type(card, &new_object.path, NULL); + r = cac_get_properties(card, &prop); + if (r < 0) + return SC_ERROR_INTERNAL; +@@ -1444,7 +1325,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int + + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "ACA: pki_object found, cert_next=%d (%s), privkey=%d", +- priv->cert_next, cac_labels[priv->cert_next], ++ priv->cert_next, get_cac_label(priv->cert_next), + prop.objects[i].privatekey); + + /* If the private key is not initialized, we can safely +@@ -1460,7 +1341,7 @@ static int cac_parse_aid(sc_card_t *card, cac_private_data_t *priv, u8 *aid, int + memcpy(new_object.path.value, &prop.objects[i].oid, 2); + new_object.path.len = 2; + new_object.path.type = SC_PATH_TYPE_FILE_ID; +- new_object.name = cac_labels[priv->cert_next]; ++ new_object.name = get_cac_label(priv->cert_next); + new_object.fd = priv->cert_next+1; + cac_add_object_to_list(&priv->pki_list, &new_object); + priv->cert_next++; +@@ -1488,7 +1369,7 @@ static int cac_parse_cardurl(sc_card_t *card, cac_private_data_t *priv, cac_card + */ + if (priv->cert_next >= MAX_CAC_SLOTS) + break; /* don't fail just because we have more certs than we can support */ +- new_object.name = cac_labels[priv->cert_next]; ++ new_object.name = get_cac_label(priv->cert_next); + new_object.fd = priv->cert_next+1; + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"CARDURL: pki_object found, cert_next=%d (%s),", priv->cert_next, new_object.name); + cac_add_object_to_list(&priv->pki_list, &new_object); +@@ -1629,7 +1510,7 @@ static int cac_parse_CCC(sc_card_t *card, cac_private_data_t *priv, u8 *tl, + if (r < 0) + return r; + +- r = cac_select_file_by_type(card, &new_path, NULL, SC_CARD_TYPE_CAC_II); ++ r = cac_select_file_by_type(card, &new_path, NULL); + if (r < 0) + return r; + +@@ -1740,7 +1621,7 @@ static int cac_select_pki_applet(sc_card_t *card, int index) + { + sc_path_t applet_path = cac_cac_pki_obj.path; + applet_path.aid.value[applet_path.aid.len-1] = index; +- return cac_select_file_by_type(card, &applet_path, NULL, SC_CARD_TYPE_CAC_II); ++ return cac_select_file_by_type(card, &applet_path, NULL); + } + + /* +@@ -1785,7 +1666,7 @@ static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t * + for (i = index; i < MAX_CAC_SLOTS; i++) { + r = cac_select_pki_applet(card, i); + if (r == SC_SUCCESS) { +- pki_obj.name = cac_labels[i]; ++ pki_obj.name = get_cac_label(i); + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "CAC: pki_object found, cert_next=%d (%s),", i, pki_obj.name); + pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i; +@@ -1796,8 +1677,7 @@ static int cac_populate_cac_alt(sc_card_t *card, int index, cac_private_data_t * + + /* populate non-PKI objects */ + for (i=0; i < cac_object_count; i++) { +- r = cac_select_file_by_type(card, &cac_objects[i].path, NULL, +- SC_CARD_TYPE_CAC_II); ++ r = cac_select_file_by_type(card, &cac_objects[i].path, NULL); + if (r == SC_SUCCESS) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, + "CAC: obj_object found, cert_next=%d (%s),", +diff --git a/src/libopensc/card-cac1.c b/src/libopensc/card-cac1.c +new file mode 100644 +index 00000000..f3a16547 +--- /dev/null ++++ b/src/libopensc/card-cac1.c +@@ -0,0 +1,563 @@ ++/* ++ * card-cac1.c: Support for legacy CAC-1 ++ * card-default.c: Support for cards with no driver ++ * ++ * Copyright (C) 2001, 2002 Juha Yrjölä ++ * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert ++ * Copyright (C) 2006, Identity Alliance, Thomas Harning ++ * Copyright (C) 2007, EMC, Russell Larner ++ * Copyright (C) 2016 - 2018, Red Hat, Inc. ++ * ++ * CAC driver author: Robert Relyea ++ * Further work: Jakub Jelen ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#if HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ ++#ifdef ENABLE_OPENSSL ++ /* openssl only needed for card administration */ ++#include ++#include ++#include ++#include ++#include ++#endif /* ENABLE_OPENSSL */ ++ ++#include "internal.h" ++#include "simpletlv.h" ++#include "cardctl.h" ++#ifdef ENABLE_ZLIB ++#include "compression.h" ++#endif ++#include "iso7816.h" ++#include "card-cac-common.h" ++ ++/* ++ * CAC hardware and APDU constants ++ */ ++#define CAC_INS_GET_CERTIFICATE 0x36 /* CAC1 command to read a certificate */ ++ ++/* ++ * OLD cac read certificate, only use with CAC-1 card. ++ */ ++static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_len) ++{ ++ u8 buf[CAC_MAX_SIZE]; ++ u8 *out_ptr; ++ size_t size = 0; ++ size_t left = 0; ++ size_t len, next_len; ++ sc_apdu_t apdu; ++ int r = SC_SUCCESS; ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ /* get the size */ ++ size = left = *out_buf ? *out_len : sizeof(buf); ++ out_ptr = *out_buf ? *out_buf : buf; ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 ); ++ next_len = MIN(left, 100); ++ for (; left > 0; left -= len, out_ptr += len) { ++ len = next_len; ++ apdu.resp = out_ptr; ++ apdu.le = len; ++ apdu.resplen = left; ++ r = sc_transmit_apdu(card, &apdu); ++ if (r < 0) { ++ break; ++ } ++ if (apdu.resplen == 0) { ++ r = SC_ERROR_INTERNAL; ++ break; ++ } ++ /* in the old CAC-1, 0x63 means 'more data' in addition to 'pin failed' */ ++ if (apdu.sw1 != 0x63) { ++ /* we've either finished reading, or hit an error, break */ ++ r = sc_check_sw(card, apdu.sw1, apdu.sw2); ++ left -= len; ++ break; ++ } ++ next_len = MIN(left, apdu.sw2); ++ } ++ if (r < 0) { ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); ++ } ++ r = size - left; ++ if (*out_buf == NULL) { ++ *out_buf = malloc(r); ++ if (*out_buf == NULL) { ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ++ SC_ERROR_OUT_OF_MEMORY); ++ } ++ memcpy(*out_buf, buf, r); ++ } ++ *out_len = r; ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); ++} ++ ++/* ++ * Callers of this may be expecting a certificate, ++ * select file will have saved the object type for us ++ * as well as set that we want the cert from the object. ++ */ ++static int cac_read_binary(sc_card_t *card, unsigned int idx, ++ unsigned char *buf, size_t count, unsigned long flags) ++{ ++ cac_private_data_t * priv = CAC_DATA(card); ++ int r = 0; ++ u8 *val = NULL; ++ u8 *cert_ptr; ++ size_t val_len; ++ size_t len, cert_len; ++ u8 cert_type; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ /* if we didn't return it all last time, return the remainder */ ++ if (priv->cached) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, ++ "returning cached value idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u", ++ idx, count); ++ if (idx > priv->cache_buf_len) { ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_END_REACHED); ++ } ++ len = MIN(count, priv->cache_buf_len-idx); ++ memcpy(buf, &priv->cache_buf[idx], len); ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, len); ++ } ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, ++ "clearing cache idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u", ++ idx, count); ++ if (priv->cache_buf) { ++ free(priv->cache_buf); ++ priv->cache_buf = NULL; ++ priv->cache_buf_len = 0; ++ } ++ ++ r = cac_cac1_get_certificate(card, &val, &val_len); ++ if (r < 0) ++ goto done; ++ ++ cert_type = val[0]; ++ cert_ptr = val + 1; ++ cert_len = val_len - 1; ++ ++ /* if the info byte is 1, then the cert is compressed, decompress it */ ++ if ((cert_type & 0x3) == 1) { ++#ifdef ENABLE_ZLIB ++ r = sc_decompress_alloc(&priv->cache_buf, &priv->cache_buf_len, ++ cert_ptr, cert_len, COMPRESSION_AUTO); ++#else ++ sc_log(card->ctx, "CAC compression not supported, no zlib"); ++ r = SC_ERROR_NOT_SUPPORTED; ++#endif ++ if (r) ++ goto done; ++ cert_ptr = val; ++ } else if (cert_len > 0) { ++ priv->cache_buf = malloc(cert_len); ++ if (priv->cache_buf == NULL) { ++ r = SC_ERROR_OUT_OF_MEMORY; ++ goto done; ++ } ++ priv->cache_buf_len = cert_len; ++ memcpy(priv->cache_buf, cert_ptr, cert_len); ++ } ++ ++ /* OK we've read the data, now copy the required portion out to the callers buffer */ ++ priv->cached = 1; ++ len = MIN(count, priv->cache_buf_len-idx); ++ memcpy(buf, &priv->cache_buf[idx], len); ++ r = len; ++done: ++ if (val) ++ free(val); ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); ++} ++ ++/* ++ * CAC cards use SC_PATH_SELECT_OBJECT_ID rather than SC_PATH_SELECT_FILE_ID. In order to use more ++ * of the PKCS #15 structure, we call the selection SC_PATH_SELECT_FILE_ID, but we set p1 to 2 instead ++ * of 0. Also cac1 does not do any FCI, but it doesn't understand not selecting it. It returns invalid INS ++ * if it doesn't like anything about the select, so we always 'request' FCI for CAC1 ++ * ++ * The rest is just copied from iso7816_select_file ++ */ ++static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) ++{ ++ struct sc_context *ctx; ++ struct sc_apdu apdu; ++ unsigned char buf[SC_MAX_APDU_BUFFER_SIZE]; ++ unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; ++ int r, pathlen, pathtype; ++ struct sc_file *file = NULL; ++ cac_private_data_t * priv = CAC_DATA(card); ++ ++ assert(card != NULL && in_path != NULL); ++ ctx = card->ctx; ++ ++ SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ memcpy(path, in_path->value, in_path->len); ++ pathlen = in_path->len; ++ pathtype = in_path->type; ++ ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, ++ "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)", ++ in_path->aid.value[0], in_path->aid.value[1], ++ in_path->aid.value[2], in_path->aid.value[3], ++ in_path->aid.value[4], in_path->aid.value[5], ++ in_path->aid.value[6], in_path->aid.len, in_path->value[0], ++ in_path->value[1], in_path->value[2], in_path->value[3], ++ in_path->len, in_path->type, in_path->type); ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "file_out=%p index=%d count=%d\n", ++ file_out, in_path->index, in_path->count); ++ ++ /* Sigh, sc_key_select expects paths to keys to have specific formats. There is no override. ++ * we have to add some bytes to the path to make it happy. A better fix would be to give sc_key_file ++ * a flag that says 'no, really this path is fine'. We only need to do this for private keys */ ++ if ((pathlen > 2) && (pathlen <= 4) && memcmp(path, "\x3F\x00", 2) == 0) { ++ if (pathlen > 2) { ++ path += 2; ++ pathlen -= 2; ++ } ++ } ++ ++ ++ /* CAC has multiple different type of objects that aren't PKCS #15. When we read ++ * them we need convert them to something PKCS #15 would understand. Find the object ++ * and object type here: ++ */ ++ if (priv) { /* don't record anything if we haven't been initialized yet */ ++ /* forget any old cached values */ ++ if (priv->cache_buf) { ++ free(priv->cache_buf); ++ priv->cache_buf = NULL; ++ } ++ priv->cache_buf_len = 0; ++ priv->cached = 0; ++ } ++ ++ if (in_path->aid.len) { ++ if (!pathlen) { ++ memcpy(path, in_path->aid.value, in_path->aid.len); ++ pathlen = in_path->aid.len; ++ pathtype = SC_PATH_TYPE_DF_NAME; ++ } else { ++ /* First, select the application */ ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"select application" ); ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 4, 0); ++ apdu.data = in_path->aid.value; ++ apdu.datalen = in_path->aid.len; ++ apdu.lc = in_path->aid.len; ++ ++ r = sc_transmit_apdu(card, &apdu); ++ LOG_TEST_RET(ctx, r, "APDU transmit failed"); ++ r = sc_check_sw(card, apdu.sw1, apdu.sw2); ++ if (r) ++ LOG_FUNC_RETURN(ctx, r); ++ ++ } ++ } ++ ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); ++ ++ switch (pathtype) { ++ /* ideally we would had SC_PATH_TYPE_OBJECT_ID and add code to the iso7816 select. ++ * Unfortunately we'd also need to update the caching code as well. For now just ++ * use FILE_ID and change p1 here */ ++ case SC_PATH_TYPE_FILE_ID: ++ apdu.p1 = 2; ++ if (pathlen != 2) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ break; ++ case SC_PATH_TYPE_DF_NAME: ++ apdu.p1 = 4; ++ break; ++ default: ++ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); ++ } ++ apdu.lc = pathlen; ++ apdu.data = path; ++ apdu.datalen = pathlen; ++ apdu.resp = buf; ++ apdu.resplen = sizeof(buf); ++ apdu.le = sc_get_max_recv_size(card) < 256 ? sc_get_max_recv_size(card) : 256; ++ apdu.p2 = 0x00; ++ ++ r = sc_transmit_apdu(card, &apdu); ++ LOG_TEST_RET(ctx, r, "APDU transmit failed"); ++ ++ if (file_out == NULL) { ++ /* For some cards 'SELECT' can be only with request to return FCI/FCP. */ ++ r = sc_check_sw(card, apdu.sw1, apdu.sw2); ++ if (apdu.sw1 == 0x6A && apdu.sw2 == 0x86) { ++ apdu.p2 = 0x00; ++ apdu.resplen = sizeof(buf); ++ if (sc_transmit_apdu(card, &apdu) == SC_SUCCESS) ++ r = sc_check_sw(card, apdu.sw1, apdu.sw2); ++ } ++ if (apdu.sw1 == 0x61) ++ LOG_FUNC_RETURN(ctx, SC_SUCCESS); ++ LOG_FUNC_RETURN(ctx, r); ++ } ++ ++ r = sc_check_sw(card, apdu.sw1, apdu.sw2); ++ if (r) ++ LOG_FUNC_RETURN(ctx, r); ++ ++ /* CAC cards never return FCI, fake one */ ++ file = sc_file_new(); ++ if (file == NULL) ++ LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); ++ file->path = *in_path; ++ file->size = CAC_MAX_SIZE; /* we don't know how big, just give a large size until we can read the file */ ++ ++ *file_out = file; ++ SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); ++ ++} ++ ++static int cac_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) ++{ ++ return cac_select_file_by_type(card, in_path, file_out); ++} ++ ++static int cac_finish(sc_card_t *card) ++{ ++ cac_private_data_t * priv = CAC_DATA(card); ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ if (priv) { ++ cac_free_private_data(priv); ++ } ++ return SC_SUCCESS; ++} ++ ++ ++/* select a CAC pki applet by index */ ++static int cac_select_pki_applet(sc_card_t *card, int index) ++{ ++ sc_path_t applet_path = cac_cac_pki_obj.path; ++ applet_path.aid.value[applet_path.aid.len-1] = index; ++ return cac_select_file_by_type(card, &applet_path, NULL); ++} ++ ++/* ++ * Find the first existing CAC applet. If none found, then this isn't a CAC ++ */ ++static int cac_find_first_pki_applet(sc_card_t *card, int *index_out) ++{ ++ int r, i; ++ ++ for (i = 0; i < MAX_CAC_SLOTS; i++) { ++ r = cac_select_pki_applet(card, i); ++ if (r == SC_SUCCESS) { ++ u8 data[2]; ++ sc_apdu_t apdu; ++ ++ /* Try to read first two bytes of the buffer to ++ * make sure it is not just malfunctioning card ++ */ ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_2, ++ CAC_INS_GET_CERTIFICATE, 0x00, 0x00); ++ apdu.le = 0x02; ++ apdu.resplen = 2; ++ apdu.resp = data; ++ r = sc_transmit_apdu(card, &apdu); ++ /* SW1 = 0x63 means more data in CAC1 */ ++ if (r == SC_SUCCESS && apdu.sw1 != 0x63) ++ continue; ++ ++ *index_out = i; ++ return SC_SUCCESS; ++ } ++ } ++ return SC_ERROR_OBJECT_NOT_FOUND; ++} ++ ++static int cac_populate_cac1(sc_card_t *card, int index, cac_private_data_t *priv) ++{ ++ int r, i; ++ cac_object_t pki_obj = cac_cac_pki_obj; ++ u8 buf[100]; ++ u8 *val; ++ size_t val_len; ++ ++ /* populate PKI objects */ ++ for (i = index; i < MAX_CAC_SLOTS; i++) { ++ r = cac_select_pki_applet(card, i); ++ if (r == SC_SUCCESS) { ++ pki_obj.name = get_cac_label(i); ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, ++ "CAC: pki_object found, cert_next=%d (%s),", i, pki_obj.name); ++ pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i; ++ pki_obj.fd = i+1; /* don't use id of zero */ ++ cac_add_object_to_list(&priv->pki_list, &pki_obj); ++ } ++ } ++ ++ /* ++ * create a cuid to simulate the cac 2 cuid. ++ */ ++ priv->cuid = cac_cac_cuid; ++ /* create a serial number by hashing the first 100 bytes of the ++ * first certificate on the card */ ++ r = cac_select_pki_applet(card, index); ++ if (r < 0) { ++ return r; /* shouldn't happen unless the card has been removed or is malfunctioning */ ++ } ++ val = buf; ++ val_len = sizeof(buf); ++ r = cac_cac1_get_certificate(card, &val, &val_len); ++ if (r >= 0) { ++ priv->cac_id = malloc(20); ++ if (priv->cac_id == NULL) { ++ return SC_ERROR_OUT_OF_MEMORY; ++ } ++#ifdef ENABLE_OPENSSL ++ SHA1(val, val_len, priv->cac_id); ++ priv->cac_id_len = 20; ++ sc_debug_hex(card->ctx, SC_LOG_DEBUG_VERBOSE, ++ "cuid", priv->cac_id, priv->cac_id_len); ++#else ++ sc_log(card->ctx, "OpenSSL Required"); ++ return SC_ERROR_NOT_SUPPORTED; ++#endif /* ENABLE_OPENSSL */ ++ } ++ return SC_SUCCESS; ++} ++ ++/* ++ * Look for a CAC card. If it exists, initialize our data structures ++ */ ++static int cac_find_and_initialize(sc_card_t *card, int initialize) ++{ ++ int r, index; ++ cac_private_data_t *priv = NULL; ++ ++ /* already initialized? */ ++ if (card->drv_data) { ++ return SC_SUCCESS; ++ } ++ ++ /* is this a CAC Alt token without any accompanying structures */ ++ r = cac_find_first_pki_applet(card, &index); ++ if (r == SC_SUCCESS) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "PKI applet found, is bare CAC-1"); ++ if (!initialize) /* match card only */ ++ return r; ++ ++ if (!priv) { ++ priv = cac_new_private_data(); ++ if (!priv) ++ return SC_ERROR_OUT_OF_MEMORY; ++ } ++ card->drv_data = priv; /* needed for the read_binary() */ ++ r = cac_populate_cac1(card, index, priv); ++ if (r == SC_SUCCESS) { ++ card->type = SC_CARD_TYPE_CAC_I; ++ return r; ++ } ++ card->drv_data = NULL; /* reset on failure */ ++ } ++ if (priv) { ++ cac_free_private_data(priv); ++ } ++ return r; ++} ++ ++ ++/* NOTE: returns a bool, 1 card matches, 0 it does not */ ++static int cac_match_card(sc_card_t *card) ++{ ++ int r; ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ /* Since we send an APDU, the card's logout function may be called... ++ * however it may be in dirty memory */ ++ card->ops->logout = NULL; ++ ++ r = cac_find_and_initialize(card, 0); ++ return (r == SC_SUCCESS); /* never match */ ++} ++ ++ ++static int cac_init(sc_card_t *card) ++{ ++ int r; ++ unsigned long flags; ++ ++ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); ++ ++ r = cac_find_and_initialize(card, 1); ++ if (r < 0) { ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_CARD); ++ } ++ flags = SC_ALGORITHM_RSA_RAW; ++ ++ _sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */ ++ _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ ++ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ ++ ++ card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO; ++ ++ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); ++} ++ ++static struct sc_card_operations cac_ops; ++ ++static struct sc_card_driver cac1_drv = { ++ "Common Access Card (CAC 1)", ++ "cac1", ++ &cac_ops, ++ NULL, 0, NULL ++}; ++ ++static struct sc_card_driver * sc_get_driver(void) ++{ ++ /* Inherit most of the things from the CAC driver */ ++ struct sc_card_driver *cac_drv = sc_get_cac_driver(); ++ ++ cac_ops = *cac_drv->ops; ++ cac_ops.match_card = cac_match_card; ++ cac_ops.init = cac_init; ++ cac_ops.finish = cac_finish; ++ ++ cac_ops.select_file = cac_select_file; /* need to record object type */ ++ cac_ops.read_binary = cac_read_binary; ++ ++ return &cac1_drv; ++} ++ ++ ++struct sc_card_driver * sc_get_cac1_driver(void) ++{ ++ return sc_get_driver(); ++} +diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h +index 5d545b35..f4df17fb 100644 +--- a/src/libopensc/cards.h ++++ b/src/libopensc/cards.h +@@ -286,6 +286,7 @@ extern sc_card_driver_t *sc_get_gids_driver(void); + extern sc_card_driver_t *sc_get_jpki_driver(void); + extern sc_card_driver_t *sc_get_coolkey_driver(void); + extern sc_card_driver_t *sc_get_cac_driver(void); ++extern sc_card_driver_t *sc_get_cac1_driver(void); + extern sc_card_driver_t *sc_get_npa_driver(void); + + #ifdef __cplusplus +diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c +index 98e6038a..5b5d4996 100644 +--- a/src/libopensc/ctx.c ++++ b/src/libopensc/ctx.c +@@ -146,6 +146,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = { + { "openpgp", (void *(*)(void)) sc_get_openpgp_driver }, + { "jpki", (void *(*)(void)) sc_get_jpki_driver }, + { "npa", (void *(*)(void)) sc_get_npa_driver }, ++ { "cac1", (void *(*)(void)) sc_get_cac1_driver }, + /* The default driver should be last, as it handles all the + * unrecognized cards. */ + { "default", (void *(*)(void)) sc_get_default_driver }, diff --git a/SOURCES/opensc-0.19.0-config.patch b/SOURCES/opensc-0.19.0-config.patch new file mode 100644 index 0000000..c409557 --- /dev/null +++ b/SOURCES/opensc-0.19.0-config.patch @@ -0,0 +1,14 @@ +diff -up opensc-0.19.0/etc/opensc.conf.pinpad opensc-0.19.0/etc/opensc.conf +--- opensc-0.19.0/etc/opensc.conf.pinpad 2019-02-06 18:14:26.808343875 +0100 ++++ opensc-0.19.0/etc/opensc.conf 2019-02-06 18:17:06.747828950 +0100 +@@ -4,4 +4,10 @@ app default { + framework pkcs15 { + # use_file_caching = true; + } ++ reader_driver pcsc { ++ # RHEL 7.6: Disabled by default, because of many broken readers ++ enable_pinpad = false; ++ # RHEL 7.7: Backward compatible value with previous version ++ disconnect_action = unpower; ++ } + } diff --git a/SOURCES/opensc-0.19.0-coolkey-matching.patch b/SOURCES/opensc-0.19.0-coolkey-matching.patch new file mode 100644 index 0000000..2f00866 --- /dev/null +++ b/SOURCES/opensc-0.19.0-coolkey-matching.patch @@ -0,0 +1,112 @@ +From 6691487cd7433b4ffc3a99124b5ecf92361b8a76 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 9 Oct 2018 15:10:36 +0200 +Subject: [PATCH 1/3] cac: These functions do not have to be exposed + +--- + src/libopensc/card-cac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libopensc/card-cac.c b/src/libopensc/card-cac.c +index eeab07e4f..bd4e03362 100644 +--- a/src/libopensc/card-cac.c ++++ b/src/libopensc/card-cac.c +@@ -211,7 +211,7 @@ typedef struct cac_private_data { + + #define CAC_DATA(card) ((cac_private_data_t*)card->drv_data) + +-int cac_list_compare_path(const void *a, const void *b) ++static int cac_list_compare_path(const void *a, const void *b) + { + if (a == NULL || b == NULL) + return 1; +@@ -220,7 +220,7 @@ int cac_list_compare_path(const void *a, const void *b) + } + + /* For SimCList autocopy, we need to know the size of the data elements */ +-size_t cac_list_meter(const void *el) { ++static size_t cac_list_meter(const void *el) { + return sizeof(cac_object_t); + } + + +From fab79b70ff45d02d99bc05863be57f8ca8f0acda Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 9 Oct 2018 15:58:12 +0200 +Subject: [PATCH 2/3] coolkey: Improve card matching to avoid mismatches in + muscle + +--- + src/libopensc/card-coolkey.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/src/libopensc/card-coolkey.c b/src/libopensc/card-coolkey.c +index b97559cc3..2cf2362c8 100644 +--- a/src/libopensc/card-coolkey.c ++++ b/src/libopensc/card-coolkey.c +@@ -2224,14 +2224,32 @@ static int coolkey_initialize(sc_card_t *card) + /* NOTE: returns a bool, 1 card matches, 0 it does not */ + static int coolkey_match_card(sc_card_t *card) + { ++ sc_apdu_t apdu; + int r; ++ + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + /* Since we send an APDU, the card's logout function may be called... + * however it may be in dirty memory */ + card->ops->logout = NULL; + + r = coolkey_select_applet(card); +- return (r >= SC_SUCCESS); ++ if (r == SC_SUCCESS) { ++ /* The GET STATUS INS with P1 = 1 returns invalid instruction (0x6D00) ++ * on Coolkey applet (reserved for GetMemory function), ++ * while incorrect P1 (0x9C10) on Muscle applets ++ */ ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_1, COOLKEY_INS_GET_STATUS, 0x01, 0x00); ++ apdu.cla = COOLKEY_CLASS; ++ apdu.le = 0x00; ++ apdu.resplen = 0; ++ apdu.resp = NULL; ++ r = sc_transmit_apdu(card, &apdu); ++ if (r == SC_SUCCESS && apdu.sw1 == 0x6d && apdu.sw2 == 0x00) { ++ return 1; ++ } ++ return 0; ++ } ++ return 0; + } + + + +From 98a1716768d11afd6d0e1e73bf8154dddfe915e9 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 9 Oct 2018 16:01:57 +0200 +Subject: [PATCH 3/3] ctx: Move coolkey driver up after improving the matching + +Fixes #1483 +--- + src/libopensc/ctx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c +index f24a61ca0..98e6038a7 100644 +--- a/src/libopensc/ctx.c ++++ b/src/libopensc/ctx.c +@@ -128,6 +128,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = { + + /* Here should be placed drivers that need some APDU transactions in the + * driver's `match_card()` function. */ ++ { "coolkey", (void *(*)(void)) sc_get_coolkey_driver }, + /* MUSCLE card applet returns 9000 on whatever AID is selected, see + * https://github.com/JavaCardOS/MuscleCard-Applet/blob/master/musclecard/src/com/musclecard/CardEdge/CardEdge.java#L326 + * put the muscle driver first to cope with this bug. */ +@@ -144,7 +145,6 @@ static const struct _sc_driver_entry internal_card_drivers[] = { + #endif + { "openpgp", (void *(*)(void)) sc_get_openpgp_driver }, + { "jpki", (void *(*)(void)) sc_get_jpki_driver }, +- { "coolkey", (void *(*)(void)) sc_get_coolkey_driver }, + { "npa", (void *(*)(void)) sc_get_npa_driver }, + /* The default driver should be last, as it handles all the + * unrecognized cards. */ + diff --git a/SOURCES/opensc-0.19.0-coverity.patch b/SOURCES/opensc-0.19.0-coverity.patch new file mode 100644 index 0000000..12a6d4b --- /dev/null +++ b/SOURCES/opensc-0.19.0-coverity.patch @@ -0,0 +1,446 @@ +diff --git a/src/libopensc/card-epass2003.c b/src/libopensc/card-epass2003.c +index 49b593f9..299520d6 100644 +--- a/src/libopensc/card-epass2003.c ++++ b/src/libopensc/card-epass2003.c +@@ -1846,11 +1846,6 @@ epass2003_process_fci(struct sc_card *card, sc_file_t * file, const u8 * buf, si + case 0x04: + file->ef_structure = SC_FILE_EF_LINEAR_FIXED; + break; +- case 0x03: +- case 0x05: +- case 0x06: +- case 0x07: +- break; + default: + break; + } +diff --git a/src/libopensc/card-iasecc.c b/src/libopensc/card-iasecc.c +index 254f8aa5..7eb3f5d0 100644 +--- a/src/libopensc/card-iasecc.c ++++ b/src/libopensc/card-iasecc.c +@@ -2406,7 +2406,11 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_ + sc_format_path("3F00", &path); + path.type = SC_PATH_TYPE_FILE_ID; + rv = iasecc_select_file(card, &path, NULL); +- LOG_TEST_RET(ctx, rv, "Unable to select MF"); ++ if (rv != SC_SUCCESS) { ++ sc_file_free(save_current); ++ sc_log(ctx, "Unable to select MF"); ++ LOG_FUNC_RETURN(ctx, rv); ++ } + } + + memset(&sdo, 0, sizeof(sdo)); +@@ -3478,9 +3482,12 @@ iasecc_get_free_reference(struct sc_card *card, struct iasecc_ctl_get_free_refer + + sc_log(ctx, "found empty key slot %i", idx); + break; ++ } else if (rv != SC_SUCCESS) { ++ iasecc_sdo_free(card, sdo); ++ ++ sc_log(ctx, "get new key reference failed"); ++ LOG_FUNC_RETURN(ctx, rv); + } +- else +- LOG_TEST_RET(ctx, rv, "get new key reference failed"); + + sz = *(sdo->docp.size.value + 0) * 0x100 + *(sdo->docp.size.value + 1); + sc_log(ctx, +diff --git a/src/libopensc/card-muscle.c b/src/libopensc/card-muscle.c +index c91b8d5e..be5b9f14 100644 +--- a/src/libopensc/card-muscle.c ++++ b/src/libopensc/card-muscle.c +@@ -455,6 +455,7 @@ static int _listFile(mscfs_file_t *file, int reset, void *udata) + static int muscle_init(sc_card_t *card) + { + muscle_private_t *priv; ++ int r; + + card->name = "MuscleApplet"; + card->drv_data = malloc(sizeof(muscle_private_t)); +@@ -478,7 +479,10 @@ static int muscle_init(sc_card_t *card) + card->caps |= SC_CARD_CAP_RNG; + + /* Card type detection */ +- _sc_match_atr(card, muscle_atrs, &card->type); ++ r = _sc_match_atr(card, muscle_atrs, &card->type); ++ if (r < 0) { ++ sc_log(card->ctx, "Failed to match the ATRs"); ++ } + if(card->type == SC_CARD_TYPE_MUSCLE_ETOKEN_72K) { + card->caps |= SC_CARD_CAP_APDU_EXT; + } +diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c +index 61acedc8..a678b768 100644 +--- a/src/libopensc/card-piv.c ++++ b/src/libopensc/card-piv.c +@@ -922,7 +922,11 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + sc_log(card->ctx, "#%d", enumtag); + +- sc_lock(card); /* do check len and get data in same transaction */ ++ r = sc_lock(card); /* do check len and get data in same transaction */ ++ if (r != SC_SUCCESS) { ++ sc_log(card->ctx, "sc_lock failed"); ++ return r; ++ } + + /* assert(enumtag >= 0 && enumtag < PIV_OBJ_LAST_ENUM); */ + +@@ -1481,7 +1485,7 @@ static int piv_get_key(sc_card_t *card, unsigned int alg_id, u8 **key, size_t *l + FILE *f = NULL; + char * keyfilename = NULL; + size_t expected_keylen; +- size_t keylen; ++ size_t keylen, readlen; + u8 * keybuf = NULL; + u8 * tkey = NULL; + +@@ -1530,11 +1534,12 @@ static int piv_get_key(sc_card_t *card, unsigned int alg_id, u8 **key, size_t *l + } + keybuf[fsize] = 0x00; /* in case it is text need null */ + +- if (fread(keybuf, 1, fsize, f) != fsize) { ++ if ((readlen = fread(keybuf, 1, fsize, f)) != fsize) { + sc_log(card->ctx, " Unable to read key\n"); + r = SC_ERROR_WRONG_LENGTH; + goto err; + } ++ keybuf[readlen] = '\0'; + + tkey = malloc(expected_keylen); + if (!tkey) { +@@ -2126,14 +2131,16 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial) + /* test if guid and the fascn starts with ;9999 (in ISO 4bit + parity code) */ + if (!(gbits && fascn[0] == 0xD4 && fascn[1] == 0xE7 + && fascn[2] == 0x39 && (fascn[3] | 0x7F) == 0xFF)) { +- serial->len = fascnlen < SC_MAX_SERIALNR ? fascnlen : SC_MAX_SERIALNR; ++ /* fascnlen is 25 */ ++ serial->len = fascnlen; + memcpy (serial->value, fascn, serial->len); + r = SC_SUCCESS; + gbits = 0; /* set to skip using guid below */ + } + } + if (guid && gbits) { +- serial->len = guidlen < SC_MAX_SERIALNR ? guidlen : SC_MAX_SERIALNR; ++ /* guidlen is 16 */ ++ serial->len = guidlen; + memcpy (serial->value, guid, serial->len); + r = SC_SUCCESS; + } +@@ -2981,7 +2988,7 @@ static int piv_match_card(sc_card_t *card) + + static int piv_match_card_continued(sc_card_t *card) + { +- int i; ++ int i, r; + int type = -1; + piv_private_data_t *priv = NULL; + int saved_type = card->type; +@@ -3080,7 +3087,13 @@ static int piv_match_card_continued(sc_card_t *card) + if(piv_objects[i].flags & PIV_OBJECT_NOT_PRESENT) + priv->obj_cache[i].flags |= PIV_OBJ_CACHE_NOT_PRESENT; + +- sc_lock(card); ++ r = sc_lock(card); ++ if (r != SC_SUCCESS) { ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "sc_lock failed\n"); ++ piv_finish(card); ++ card->type = saved_type; ++ return 0; ++ } + + /* + * detect if active AID is PIV. NIST 800-73 says Only one PIV application per card +@@ -3464,7 +3477,11 @@ piv_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) + if (data->cmd == SC_PIN_CMD_VERIFY && data->pin_type == SC_AC_CONTEXT_SPECIFIC) { + priv->context_specific = 1; + sc_log(card->ctx,"Starting CONTEXT_SPECIFIC verify"); +- sc_lock(card); ++ r = sc_lock(card); ++ if (r != SC_SUCCESS) { ++ sc_log(card->ctx, "sc_lock failed"); ++ return r; ++ } + } + + priv->pin_cmd_verify = 1; /* tell piv_check_sw its a verify to save sw1, sw2 */ +diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c +index 626686a7..f24a61ca 100644 +--- a/src/libopensc/ctx.c ++++ b/src/libopensc/ctx.c +@@ -452,6 +452,10 @@ static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name + const char *(*modversion)(void) = NULL; + const char *(**tmodv)(void) = &modversion; + ++ if (dll == NULL) { ++ sc_log(ctx, "No dll parameter specified"); ++ return NULL; ++ } + if (name == NULL) { /* should not occur, but... */ + sc_log(ctx, "No module specified"); + return NULL; +@@ -481,8 +485,8 @@ static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name + sc_dlclose(handle); + return NULL; + } +- if (dll) +- *dll = handle; ++ ++ *dll = handle; + sc_log(ctx, "successfully loaded card driver '%s'", name); + return modinit(name); + } +diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c +index 718d92ff..6abd2d76 100644 +--- a/src/libopensc/iso7816.c ++++ b/src/libopensc/iso7816.c +@@ -841,13 +841,18 @@ iso7816_set_security_env(struct sc_card *card, + if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) { + if (env->file_ref.len > 0xFF) + return SC_ERROR_INVALID_ARGUMENTS; ++ if (sizeof(sbuf) - (p - sbuf) < env->file_ref.len + 2) ++ return SC_ERROR_OFFSET_TOO_LARGE; ++ + *p++ = 0x81; + *p++ = (u8) env->file_ref.len; +- assert(sizeof(sbuf) - (p - sbuf) >= env->file_ref.len); + memcpy(p, env->file_ref.value, env->file_ref.len); + p += env->file_ref.len; + } + if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { ++ if (sizeof(sbuf) - (p - sbuf) < env->key_ref_len + 2) ++ return SC_ERROR_OFFSET_TOO_LARGE; ++ + if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) + *p++ = 0x83; + else +@@ -855,7 +860,6 @@ iso7816_set_security_env(struct sc_card *card, + if (env->key_ref_len > 0xFF) + return SC_ERROR_INVALID_ARGUMENTS; + *p++ = env->key_ref_len & 0xFF; +- assert(sizeof(sbuf) - (p - sbuf) >= env->key_ref_len); + memcpy(p, env->key_ref, env->key_ref_len); + p += env->key_ref_len; + } +diff --git a/src/libopensc/pkcs15-cac.c b/src/libopensc/pkcs15-cac.c +index 93032113..f34425a5 100644 +--- a/src/libopensc/pkcs15-cac.c ++++ b/src/libopensc/pkcs15-cac.c +@@ -388,6 +388,7 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card) + if (r == SC_SUCCESS) { + token_name = malloc (cn_len+1); + if (!token_name) { ++ free(cn_name); + r = SC_ERROR_OUT_OF_MEMORY; + goto fail; + } +diff --git a/src/libopensc/pkcs15-oberthur.c b/src/libopensc/pkcs15-oberthur.c +index 3415be7c..8c126e46 100644 +--- a/src/libopensc/pkcs15-oberthur.c ++++ b/src/libopensc/pkcs15-oberthur.c +@@ -206,8 +206,10 @@ sc_oberthur_get_certificate_authority(struct sc_pkcs15_der *der, int *out_author + buf_mem.max = buf_mem.length = der->len; + + bio = BIO_new(BIO_s_mem()); +- if(!bio) ++ if (!bio) { ++ free(buf_mem.data); + return SC_ERROR_OUT_OF_MEMORY; ++ } + + BIO_set_mem_buf(bio, &buf_mem, BIO_NOCLOSE); + x = d2i_X509_bio(bio, 0); +diff --git a/src/pkcs15init/pkcs15-authentic.c b/src/pkcs15init/pkcs15-authentic.c +index ddccd032..0b6f9c17 100644 +--- a/src/pkcs15init/pkcs15-authentic.c ++++ b/src/pkcs15init/pkcs15-authentic.c +@@ -355,7 +355,6 @@ authentic_sdo_allocate_prvkey(struct sc_profile *profile, struct sc_card *card, + sc_file_free(file); + LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate 'sc_authentic_sdo'"); + } +- *out = sdo; + + sdo->magic = AUTHENTIC_SDO_MAGIC; + sdo->docp.id = key_info->key_reference & ~AUTHENTIC_OBJECT_REF_FLAG_LOCAL; +@@ -364,11 +363,16 @@ authentic_sdo_allocate_prvkey(struct sc_profile *profile, struct sc_card *card, + rv = authentic_docp_set_acls(card, file, authentic_v3_rsa_ac_ops, + sizeof(authentic_v3_rsa_ac_ops)/sizeof(authentic_v3_rsa_ac_ops[0]), &sdo->docp); + sc_file_free(file); +- LOG_TEST_RET(ctx, rv, "Cannot set key ACLs from file"); ++ if (rv != SC_SUCCESS) { ++ free(sdo); ++ sc_log(ctx, "Cannot set key ACLs from file"); ++ LOG_FUNC_RETURN(ctx, rv); ++ } + + sc_log(ctx, "sdo(mech:%X,id:%X,acls:%s)", sdo->docp.mech, sdo->docp.id, + sc_dump_hex(sdo->docp.acl_data, sdo->docp.acl_data_len)); + ++ *out = sdo; + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + } + +diff --git a/src/pkcs15init/pkcs15-myeid.c b/src/pkcs15init/pkcs15-myeid.c +index 29f9aa22..10258667 100644 +--- a/src/pkcs15init/pkcs15-myeid.c ++++ b/src/pkcs15init/pkcs15-myeid.c +@@ -232,6 +232,7 @@ myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df + for (ii = 0; create_dfs[ii]; ii++) { + sc_log(ctx, "Create '%s'", create_dfs[ii]); + ++ file = NULL; + r = sc_profile_get_file(profile, create_dfs[ii], &file); + sc_file_free(file); + if (r) { +@@ -433,7 +434,11 @@ _add_supported_algo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, + unsigned operations, unsigned mechanism, const struct sc_object_id *oid) + { + struct sc_supported_algo_info *algo; ++ struct sc_context *ctx = p15card->card->ctx; + algo = sc_pkcs15_get_supported_algo(p15card, operations, mechanism); ++ int rv; ++ ++ LOG_FUNC_CALLED(ctx); + if (!algo) { + unsigned ref = 1, ii; + +@@ -451,7 +456,10 @@ _add_supported_algo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, + } + + } +- sc_pkcs15_add_supported_algo_ref(object, algo); ++ rv = sc_pkcs15_add_supported_algo_ref(object, algo); ++ if (rv != SC_SUCCESS) { ++ sc_log(ctx, "Failed to add algorithms refs"); ++ } + } + + static void +@@ -742,7 +750,6 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, + break; + default: + LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); +- break; + } + + sc_log(ctx, "Generate key with ID:%s and path:%s", +diff --git a/src/pkcs15init/pkcs15-oberthur-awp.c b/src/pkcs15init/pkcs15-oberthur-awp.c +index f9c96373..9b12f06c 100644 +--- a/src/pkcs15init/pkcs15-oberthur-awp.c ++++ b/src/pkcs15init/pkcs15-oberthur-awp.c +@@ -284,9 +284,10 @@ awp_create_container_record (struct sc_pkcs15_card *p15card, struct sc_profile * + memset(buff, 0, list_file->record_length); + + rv = awp_new_container_entry(p15card, buff, list_file->record_length); +- if (rv < 0) { ++ if (rv < 0) { + free(buff); +- SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot create container"); ++ sc_log(ctx, "Cannot create container"); ++ SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, rv); + } + + *(buff + 0) = (acc->pubkey_id >> 8) & 0xFF; +diff --git a/src/tools/npa-tool-cmdline.c b/src/tools/npa-tool-cmdline.c +index 117c6cb1..26eed929 100644 +--- a/src/tools/npa-tool-cmdline.c ++++ b/src/tools/npa-tool-cmdline.c +@@ -1685,7 +1685,14 @@ void update_multiple_arg(void *field, char ***orig_field, + struct generic_list *tmp; + + if (prev_given && list) { ++ char **old = *orig_field; ++ char *old_field = field; + *orig_field = (char **) realloc (*orig_field, (field_given + prev_given) * sizeof (char *)); ++ if (*orig_field == NULL) { ++ free(*old); ++ fprintf(stderr, "Failed to allocate memory: aborting"); ++ exit(1); ++ } + + switch(arg_type) { + case ARG_INT: +@@ -1695,6 +1702,11 @@ void update_multiple_arg(void *field, char ***orig_field, + default: + break; + }; ++ if (*((void **)field) == NULL) { ++ free(old_field); ++ fprintf(stderr, "Failed to allocate memory: aborting"); ++ exit(1); ++ } + + for (i = (prev_given - 1); i >= 0; --i) + { +diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c +index ac5292f9..7bc5a3ff 100644 +--- a/src/tools/opensc-explorer.c ++++ b/src/tools/opensc-explorer.c +@@ -1399,7 +1399,7 @@ static int do_get(int argc, char **argv) + if (r == SC_SUCCESS) + r = sc_select_file(card, &path, &file); + sc_unlock(card); +- if (r) { ++ if (r || file == NULL) { + check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); + goto err; + } +diff --git a/src/tools/piv-tool.c b/src/tools/piv-tool.c +index 6dc8213d..23a58ce6 100644 +--- a/src/tools/piv-tool.c ++++ b/src/tools/piv-tool.c +@@ -477,6 +477,7 @@ int main(int argc, char *argv[]) + const char *key_info = NULL; + const char *admin_info = NULL; + sc_context_param_t ctx_param; ++ char **old_apdus = NULL; + + setbuf(stderr, NULL); + setbuf(stdout, NULL); +@@ -493,9 +494,11 @@ int main(int argc, char *argv[]) + action_count++; + break; + case 's': ++ old_apdus = opt_apdus; + opt_apdus = (char **) realloc(opt_apdus, + (opt_apdu_count + 1) * sizeof(char *)); + if (!opt_apdus) { ++ free(old_apdus); + err = 1; + goto end; + } +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index 64525f6a..5795a8ba 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -2695,6 +2695,7 @@ static int write_object(CK_SESSION_HANDLE session) + if (!(f = fopen(opt_attr_from_file, "rb"))) + util_fatal("Couldn't open file \"%s\"", opt_attr_from_file); + certdata_len = fread(certdata, 1, sizeof(certdata), f); ++ certdata[certdata_len] = '\0'; + if (certdata_len < 0) + util_fatal("Couldn't read from file \"%s\"", opt_attr_from_file); + fclose(f); +diff --git a/src/tools/sc-hsm-tool.c b/src/tools/sc-hsm-tool.c +index 02cdfcc6..2b424cf7 100644 +--- a/src/tools/sc-hsm-tool.c ++++ b/src/tools/sc-hsm-tool.c +@@ -1503,13 +1503,13 @@ static int unwrap_key(sc_card_t *card, int keyid, const char *inf, const char *p + return -1; + } + +- if ((keybloblen = fread(keyblob, 1, sizeof(keyblob), in)) < 0) { ++ keybloblen = fread(keyblob, 1, sizeof(keyblob), in); ++ fclose(in); ++ if (keybloblen < 0) { + perror(inf); + return -1; + } + +- fclose(in); +- + ptr = keyblob; + if ((sc_asn1_read_tag(&ptr, keybloblen, &cla, &tag, &len) != SC_SUCCESS) + || ((cla & SC_ASN1_TAG_CONSTRUCTED) != SC_ASN1_TAG_CONSTRUCTED) diff --git a/SOURCES/opensc-0.19.0-dual.patch b/SOURCES/opensc-0.19.0-dual.patch new file mode 100644 index 0000000..d11869f --- /dev/null +++ b/SOURCES/opensc-0.19.0-dual.patch @@ -0,0 +1,609 @@ +diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c +index 03c83868f1..794472134c 100644 +--- a/src/libopensc/card-piv.c ++++ b/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,37 @@ 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 }, ++ ++ /* 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 +252,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 +263,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: +@@ -2222,11 +2266,33 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len) + 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; +@@ -2635,6 +2701,91 @@ static int piv_process_discovery(sc_card_t *card) + 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) + { +@@ -2922,7 +3073,8 @@ piv_finish(sc_card_t *card) + static int piv_match_card(sc_card_t *card) + { + 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) { +@@ -2931,7 +3083,13 @@ static int piv_match_card(sc_card_t *card) + case SC_CARD_TYPE_PIV_II_HIST: + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: ++ case SC_CARD_TYPE_PIV_II_GI_DE_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 */ +@@ -2950,13 +3108,14 @@ static int piv_match_card(sc_card_t *card) + piv_finish(card); + } + ++ sc_debug(card->ctx,SC_LOG_DEBUG_MATCH, "PIV_MATCH card->type:%d r:%d\n", card->type,r); + return r; + } + + + static int piv_match_card_continued(sc_card_t *card) + { +- int i, r; ++ int i, r = 0; + int type = -1; + piv_private_data_t *priv = NULL; + int saved_type = card->type; +@@ -2973,12 +3132,19 @@ static int piv_match_card_continued(sc_card_t *card) + case SC_CARD_TYPE_PIV_II_HIST: + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: ++ case SC_CARD_TYPE_PIV_II_GI_DE_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 r:%d\n", card->type, type, r); + if (type == -1) { + + /* +@@ -2997,18 +3163,6 @@ static int piv_match_card_continued(sc_card_t *card) + !(memcmp(card->reader->atr_info.hist_bytes, "Yubikey", 7))) { + type = SC_CARD_TYPE_PIV_II_NEO; + } +- /* +- * https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp1239.pdf +- * lists 2 ATRS with historical bytes: +- * 73 66 74 65 2D 63 64 30 38 30 +- * 73 66 74 65 20 63 64 31 34 34 +- * will check for 73 66 74 65 +- */ +- else if (card->reader->atr_info.hist_bytes_len >= 4 +- && !(memcmp(card->reader->atr_info.hist_bytes, "sfte", 4))) { +- type = SC_CARD_TYPE_PIV_II_GI_DE; +- } +- + else if (card->reader->atr_info.hist_bytes_len > 0 + && card->reader->atr_info.hist_bytes[0] == 0x80u) { /* compact TLV */ + size_t datalen; +@@ -3029,10 +3183,17 @@ static int piv_match_card_continued(sc_card_t *card) + } + } + } +- 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 r:%d\n", card->type, type, r); ++ ++ if (type == -1) { ++ /* use known ATRs */ ++ i = _sc_match_atr(card, piv_atrs, &type); ++ if (type == -1) ++ 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 r:%d\n", card->type, type, r); + /* allocate and init basic fields */ + + priv = calloc(1, sizeof(piv_private_data_t)); +@@ -3046,6 +3207,7 @@ static int piv_match_card_continued(sc_card_t *card) + card->drv_data = priv; /* will free if no match, or pass on to piv_init */ + priv->selected_obj = -1; + priv->pin_preference = 0x80; /* 800-73-3 part 1, table 3 */ ++ /* TODO Dual CAC/PIV are bases on 800-73-1 were priv->pin_preference = 0. need to check later */ + priv->logged_in = SC_PIN_STATE_UNKNOWN; + priv->tries_left = 10; /* will assume OK at start */ + priv->pstate = PIV_STATE_MATCH; +@@ -3064,38 +3226,104 @@ static int piv_match_card_continued(sc_card_t *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 r:%d\n", card->type, priv->card_issues, r); ++ 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 r:%d\n", card->type, i, priv->card_issues, r); + if (i < 0) { + /* Detect by selecting applet */ + i = piv_find_aid(card); + } + ++ 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); + 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 r:%d\n", ++ card->type, iccc, priv->ccc_flags, priv->card_issues, r); ++ /* 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 r:%d\n", card->type, i, priv->card_issues, r); ++ 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 r:%d\n", card->type, i7e, priv->card_issues, r); ++ 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 r:%d\n", card->type, i, priv->card_issues, r); + if (i < 0) { + /* don't match. Does not have a PIV applet. */ + sc_unlock(card); +@@ -3104,6 +3332,7 @@ static int piv_match_card_continued(sc_card_t *card) + return 0; + } + ++ 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); + /* Matched, caller will use or free priv and sc_lock as needed */ + priv->pstate=PIV_STATE_INIT; + return 1; /* match */ +@@ -3124,7 +3353,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); +@@ -3147,6 +3376,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 r:%d\n", card->type, priv->card_issues, r); + switch(card->type) { + case SC_CARD_TYPE_PIV_II_NEO: + case SC_CARD_TYPE_PIV_II_YUBIKEY4: +@@ -3178,6 +3408,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 r:%d\n", card->type, priv->card_issues, r); + switch(card->type) { + case SC_CARD_TYPE_PIV_II_NEO: + priv->card_issues |= CI_NO_EC384 +@@ -3196,30 +3427,53 @@ 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; + ++ + case SC_CARD_TYPE_PIV_II_GENERIC: + priv->card_issues |= CI_VERIFY_LC0_FAIL + | CI_OTHER_AID_LOSE_STATE; + /* 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 r:%d\n", card->type, priv->card_issues, r); ++ + priv->enumtag = piv_aids[0].enumtag; + + /* PKCS#11 may try to generate session keys, and get confused +@@ -3233,15 +3487,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 +@@ -3565,11 +3824,13 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) + 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 */ + } +diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h +index f4df17fb04..121182bb6a 100644 +--- a/src/libopensc/cards.h ++++ b/src/libopensc/cards.h +@@ -136,7 +136,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/SOURCES/opensc.module b/SOURCES/opensc.module new file mode 100644 index 0000000..2071097 --- /dev/null +++ b/SOURCES/opensc.module @@ -0,0 +1,8 @@ +# This file describes how to load the opensc module +# See: http://p11-glue.freedesktop.org/doc/p11-kit/config.html + +# This is a relative path, which means it will be loaded from +# the p11-kit default path which is usually $(libdir)/pkcs11. +# Doing it this way allows for packagers to package opensc for +# 32-bit and 64-bit and make them parallel installable +module: opensc-pkcs11.so diff --git a/SOURCES/pkcs11-switch.sh b/SOURCES/pkcs11-switch.sh new file mode 100755 index 0000000..f29565c --- /dev/null +++ b/SOURCES/pkcs11-switch.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +# Paths, names and functions definitions +NSSDB="/etc/pki/nssdb/" +COOLKEY_NAME="CoolKey PKCS #11 Module" +COOLKEY_LIBRARY="libcoolkeypk11.so" +OPENSC_NAME="OpenSC PKCS #11 Module" +OPENSC_LIBRARY="opensc-pkcs11.so" + +add_module() { + NAME="$1" + LIBRARY="$2" + modutil -add "$NAME" -dbdir "$NSSDB" -libfile "$LIBRARY" +} +remove_module() { + NAME="$1" + modutil -delete "$NAME" -dbdir "$NSSDB" -force +} + +# Parse arguments. If wrong, print usage +TARGET="$1" +if [ "$TARGET" = "" ]; then + # Print currently installed module + PRINT_CURRENT="1" +elif [ "$TARGET" = "opensc" ] || [ "$TARGET" = "coolkey" ]; then + : # Correct arguments +else + echo "Simple tool to switch between OpenSC and Coolkey PKCS#11 modules in main NSS DB." + echo "Usage: $0 [coolkey|opensc]" + echo " [coolkey|opensc] says which of the modules should be used." + echo " The other one will be removed from database." + echo + echo " If there is no argument specified, prints the current module in NSS DB" + exit 255 +fi + +if [ ! -x /usr/bin/modutil ]; then + echo "The modutil is not installed. Please install package nss-util" + exit 255 +fi + +# Find the current library in NSS DB +CURRENT="" # none +LIBS=$(modutil -rawlist -dbdir "$NSSDB" | grep "^library=") +if echo "$LIBS" | grep "$COOLKEY_NAME" > /dev/null; then + CURRENT="coolkey" +fi +if echo "$LIBS" | grep "$OPENSC_NAME" > /dev/null; then + if [ -n "$CURRENT" ]; then + CURRENT="opensc coolkey" + echo "There are both modules in NSS DB, which is not recommended." + echo "I will remove the other." + else + CURRENT="opensc" + fi +fi + +if [ "$PRINT_CURRENT" = "1" ]; then + echo "$CURRENT" + exit 0 +fi + +# Do we need to change something? +if [ "$CURRENT" = "$TARGET" ]; then + echo "The requested module is already in the NSS DB" + exit 0 +fi + +# Do the actual change +if [ "$TARGET" = "opensc" ]; then + add_module "$OPENSC_NAME" "$OPENSC_LIBRARY" + remove_module "$COOLKEY_NAME" +fi +if [ "$TARGET" = "coolkey" ]; then + add_module "$COOLKEY_NAME" "$COOLKEY_LIBRARY" + remove_module "$OPENSC_NAME" +fi diff --git a/SPECS/opensc.spec b/SPECS/opensc.spec new file mode 100644 index 0000000..f3df2a2 --- /dev/null +++ b/SPECS/opensc.spec @@ -0,0 +1,587 @@ +Name: opensc +Version: 0.19.0 +Release: 3%{?dist} +Summary: Smart card library and applications + +Group: System Environment/Libraries +License: LGPLv2+ +URL: https://github.com/OpenSC/OpenSC/wiki +Source0: https://github.com/OpenSC/OpenSC/releases/download/%{version}/%{name}-%{version}.tar.gz +Source1: opensc.module +Source2: pkcs11-switch.sh +# Disable pinpad by default and use backward compatible configuration (#1547117, #1547744) +Patch1: opensc-0.19.0-config.patch +# https://github.com/OpenSC/OpenSC/pull/1489 +Patch2: opensc-0.19.0-coverity.patch +# https://github.com/OpenSC/OpenSC/pull/1500 +Patch3: opensc-0.19.0-coolkey-matching.patch +# https://github.com/OpenSC/OpenSC/pull/1502 +Patch4: opensc-0.19.0-cac1.patch +# https://github.com/OpenSC/OpenSC/pull/1549 +Patch5: opensc-0.19.0-dual.patch + +BuildRequires: pcsc-lite-devel +BuildRequires: readline-devel +BuildRequires: openssl-devel +BuildRequires: /usr/bin/xsltproc +BuildRequires: docbook-style-xsl +BuildRequires: autoconf automake libtool +Requires: pcsc-lite-libs%{?_isa} +Requires: pcsc-lite +Obsoletes: mozilla-opensc-signer < 0.12.0 +Obsoletes: opensc-devel < 0.12.0 + +%description +OpenSC provides a set of libraries and utilities to work with smart cards. Its +main focus is on cards that support cryptographic operations, and facilitate +their use in security applications such as authentication, mail encryption and +digital signatures. OpenSC implements the PKCS#11 API so applications +supporting this API (such as Mozilla Firefox and Thunderbird) can use it. On +the card OpenSC implements the PKCS#15 standard and aims to be compatible with +every software/card that does so, too. + + +%prep +%setup -q +%patch1 -p1 -b .config +%patch2 -p1 -b .coverity +%patch3 -p1 -b .coolkey-match +%patch4 -p1 -b .cac1 +%patch5 -p1 -b .dual + +cp -p src/pkcs15init/README ./README.pkcs15init +cp -p src/scconf/README.scconf . +# No {_libdir} here to avoid multilib conflicts; it's just an example +sed -i -e 's|/usr/local/towitoko/lib/|/usr/lib/ctapi/|' etc/opensc.conf.example.in + + +%build +autoreconf -fvi +%ifarch %{ix86} ppc s390 +sed -i -e 's/opensc.conf/opensc-%{_arch}.conf/g' src/libopensc/Makefile.in +%endif +sed -i -e 's|"/lib /usr/lib\b|"/%{_lib} %{_libdir}|' configure # lib64 rpaths +%configure --disable-static \ + --disable-assert \ + --enable-pcsc \ + --disable-tests `# Broken release tarball fails to build them` \ + --disable-notify `# This was not present in previous release` \ + --with-completiondir=no `#Bash completion is disabled` \ + --enable-sm \ + --with-pcsc-provider=libpcsclite.so.1 +make %{?_smp_mflags} V=1 + + +%install +make install DESTDIR=$RPM_BUILD_ROOT +rm -f $RPM_BUILD_ROOT%{_bindir}/opensc-notify +install -Dpm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/p11-kit/modules/opensc.module +install -Dpm 755 %{SOURCE2} $RPM_BUILD_ROOT%{_bindir}/pkcs11-switch + +%ifarch %{ix86} ppc s390 +# To avoid multilib issues, move these files on 32b intel architectures +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/opensc.conf +install -Dpm 644 etc/opensc.conf $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/opensc.conf.5 +install -Dpm 644 doc/files/opensc.conf.5 $RPM_BUILD_ROOT%{_mandir}/man5/opensc-%{_arch}.conf.5 +# use NEWS file timestamp as reference for configuration file +touch -r NEWS $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf +touch -r NEWS $RPM_BUILD_ROOT%{_mandir}/man5/opensc-%{_arch}.conf.5 +%else +# For backward compatibility, symlink the old location to the new files +ln -s %{_sysconfdir}/opensc.conf $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf +%endif + +find $RPM_BUILD_ROOT%{_libdir} -type f -name "*.la" | xargs rm + +rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/opensc + +# Upstream considers libopensc API internal and no longer ships +# public headers and pkgconfig files. +# Remove the symlink as nothing is supposed to link against libopensc. +rm -f $RPM_BUILD_ROOT%{_libdir}/libopensc.so +rm -f $RPM_BUILD_ROOT%{_libdir}/libsmm-local.so +rm -f $RPM_BUILD_ROOT%{_mandir}/man1/opensc-notify.1* +rm -f $RPM_BUILD_ROOT%{_datadir}/applications/org.opensc.notify.desktop +%if 0%{?rhel} +rm -rf %{buildroot}%{_sysconfdir}/bash_completion.d/ +%endif + +# the npa-tool builds to nothing since we do not have OpenPACE library +rm -rf %{buildroot}%{_bindir}/npa-tool +rm -rf %{buildroot}%{_mandir}/man1/npa-tool.1* + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + + +%files +%defattr(-,root,root,-) +%doc COPYING NEWS README* + +%if ! 0%{?rhel} +%{_sysconfdir}/bash_completion.d/* +%endif + +%ifarch %{ix86} ppc s390 +%{_mandir}/man5/opensc-%{_arch}.conf.5* +%else +%config(noreplace) %{_sysconfdir}/opensc.conf +%{_mandir}/man5/opensc.conf.5* +%endif + +%config(noreplace) %{_sysconfdir}/opensc-%{_arch}.conf +%{_datadir}/p11-kit/modules/opensc.module +%{_bindir}/cardos-tool +%{_bindir}/cryptoflex-tool +%{_bindir}/eidenv +%{_bindir}/iasecc-tool +%{_bindir}/gids-tool +%{_bindir}/netkey-tool +%{_bindir}/openpgp-tool +%{_bindir}/opensc-explorer +%{_bindir}/opensc-tool +%{_bindir}/opensc-asn1 +%{_bindir}/piv-tool +%{_bindir}/pkcs11-tool +%{_bindir}/pkcs11-switch +%{_bindir}/pkcs15-crypt +%{_bindir}/pkcs15-init +%{_bindir}/pkcs15-tool +%{_bindir}/sc-hsm-tool +%{_bindir}/dnie-tool +%{_bindir}/westcos-tool +%{_bindir}/egk-tool +%{_libdir}/lib*.so.* +%{_libdir}/opensc-pkcs11.so +%{_libdir}/pkcs11-spy.so +%{_libdir}/onepin-opensc-pkcs11.so +%{_libdir}/pkgconfig/*.pc +%%dir %{_libdir}/pkcs11 +%{_libdir}/pkcs11/opensc-pkcs11.so +%{_libdir}/pkcs11/onepin-opensc-pkcs11.so +%{_libdir}/pkcs11/pkcs11-spy.so +%{_datadir}/opensc/ +%{_mandir}/man1/cardos-tool.1* +%{_mandir}/man1/cryptoflex-tool.1* +%{_mandir}/man1/eidenv.1* +%{_mandir}/man1/gids-tool.1* +%{_mandir}/man1/iasecc-tool.1* +%{_mandir}/man1/netkey-tool.1* +%{_mandir}/man1/openpgp-tool.1* +%{_mandir}/man1/opensc-explorer.* +%{_mandir}/man1/opensc-tool.1* +%{_mandir}/man1/opensc-asn1.1* +%{_mandir}/man1/piv-tool.1* +%{_mandir}/man1/pkcs11-tool.1* +%{_mandir}/man1/pkcs15-crypt.1* +%{_mandir}/man1/pkcs15-init.1* +%{_mandir}/man1/pkcs15-tool.1* +%{_mandir}/man1/sc-hsm-tool.1* +%{_mandir}/man1/westcos-tool.1* +%{_mandir}/man1/dnie-tool.1* +%{_mandir}/man1/egk-tool.1* +%{_mandir}/man5/pkcs15-profile.5* + + +%changelog +* Wed Mar 27 2019 Jakub Jelen - 0.19.0-3 +- Make OpenSC multilib also on s390 and ppc arches + +* Wed Mar 27 2019 Jakub Jelen - 0.19.0-2 +- Make OpenSC multilib again by moving the conflicting files on ix86 arch + +* Thu Feb 07 2019 Jakub Jelen - 0.19.0-1 +- Rebase to new upstream release (#1656791) + - Add Support for HID Crescendo 144K (#1612372) + - Add Support for CAC Alt tokens (#1645581) + - Fix usage detection from certificates (#1672898) + - Fix security issues: + - CVE-2018-16391 + - CVE-2018-16392 + - CVE-2018-16393 + - CVE-2018-16418 + - CVE-2018-16419 + - CVE-2018-16420 + - CVE-2018-16421 + - CVE-2018-16422 + - CVE-2018-16423 + - CVE-2018-16426 + - CVE-2018-16427 + +* Tue Jul 03 2018 Jakub Jelen - 0.16.0-10.20170227git +- Improve support for ECC-enabled CardOS 5.3 card (#1562277) + +* Tue Jun 19 2018 Jakub Jelen - 0.16.0-9.20170227git +- make ECPoint behavior standards compliant by default (#1562572) +- allow mechanism to be specified in hexadecimal (#1562572) +- Disable pinpad by default (#1547117, #1547744) + +* Wed Jan 03 2018 Jakub Jelen - 0.16.0-8.20170227git +- Copy labels from certificate (#1448555) +- Avoid infinite loop in CAC driver when reading non-CAC cards (#1473335) +- Properly parse Simple TLV structures in CAC driver (#1473418) + +* Tue Nov 07 2017 Jakub Jelen - 0.16.0-7.20170227git +- Fix issues reported by Coverity +- Use upstream accepted fix for CAC Alt tokens (#1473418) + +* Fri Nov 03 2017 Jakub Jelen - 0.16.0-6.20170227git +- Use label from certificate DN if there is none (#1448555) +- Use Cardholder name in the token label (#1449740) +- Avoid infinite loop when reading CAC cards (#1473335) +- Workaround for CAC Alt tokens (#1473418) + +* Thu May 18 2017 Jakub Jelen - 0.16.0-5.20170227git +- Add missing pkcs11-switch script + +* Thu Apr 13 2017 Jakub Jelen - 0.16.0-4.20170227git +- Release aquired lock for uninitialized ASEPCOS cards (#1376090) + +* Thu Mar 23 2017 Jakub Jelen - 0.16.0-3.20170227git +- Fix more issues identified by Coverity scan + +* Thu Mar 23 2017 Jakub Jelen - 0.16.0-2.20170227git +- Add support for CardOS 5.3 +- Fix coverity issues +- Provide simple tool to swith PKCS#11 library in NSS DB + +* Tue Jan 10 2017 Jakub Jelen - 0.16.0-1.20170110git +- Rebase to OpenSC master with support for CAC cards (#1373164) + +* Thu Feb 25 2016 Nikos Mavrogiannopoulos 0.14.0-2 +- Export PKCS#11 symbols from spy library (#1283305) + +* Thu Apr 23 2015 Nikos Mavrogiannopoulos 0.14.0-1 +- Updated to opensc 0.14.0 + +* Fri Mar 14 2014 Nikos Mavrogiannopoulos 0.13.0-9 +- Configuration file includes arch to allow it operate under multilib + +* Mon Mar 10 2014 Nikos Mavrogiannopoulos 0.13.0-8 +- Ensure that variables are in scope when used (#1062307) + +* Tue Feb 25 2014 Nikos Mavrogiannopoulos 0.13.0-7 +- Corrected path of opensc.module (#1060034) + +* Fri Jan 24 2014 Daniel Mach - 0.13.0-6 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 0.13.0-5 +- Mass rebuild 2013-12-27 + +* Fri Mar 08 2013 Stef Walter - 0.13.0-4 +- Use the standard name format for p11-kit module configs +- Put the p11-kit module config is the system location + +* Thu Feb 14 2013 Fedora Release Engineering - 0.13.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Sun Jan 13 2013 Kalev Lember - 0.13.0-2 +- Backport an upstream patch for fixing pkcs15 cert length calculation + +* Thu Jan 03 2013 Milan Broz - 0.13.0-1 +- Update to 0.13.0 (#890770) +- Remove no longer provided onepin-opensc-pkcs11.so. +- Add iasecc-tool, openpgp-tool and sc-hsm-tool. + +* Fri Jul 27 2012 Tomas Mraz - 0.12.2-6 +- Add a configuration file for p11-kit (#840504) + +* Fri Jul 20 2012 Fedora Release Engineering - 0.12.2-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Sun Mar 4 2012 Peter Robinson - 0.12.2-4 +- Add patch for dso + +* Fri Jan 13 2012 Fedora Release Engineering - 0.12.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Aug 17 2011 Tomas Mraz - 0.12.2-2 +- Rebuilt to fix trailing slashes in filelist from rpmbuild bug + +* Tue Jul 19 2011 Kalev Lember - 0.12.2-1 +- Update to 0.12.2 (#722659) + +* Wed May 18 2011 Kalev Lember - 0.12.1-1 +- Update to 0.12.1 (#705743) +- Removed BR libtool-ltdl-devel to build with glibc's libdl instead + +* Tue Apr 12 2011 Tomas Mraz - 0.12.0-4 +- drop multilib conflicting and duplicated doc file (#695368) + +* Tue Feb 08 2011 Fedora Release Engineering - 0.12.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 03 2011 Kalev Lember - 0.12.0-2 +- Disabled asserts + +* Mon Jan 03 2011 Kalev Lember - 0.12.0-1 +- Update to 0.12.0 +- Removed and obsoleted mozilla-opensc-signer and opensc-devel subpackages +- Dropped patches which are now upstreamed +- It is no longer possible to build in both pcsc-lite and openct support, + so opensc now gets built exclusively with pcsc-lite. + +* Tue Dec 21 2010 Tomas Mraz - 0.11.13-6 +- fix buffer overflow on rogue card serial numbers + +* Tue Oct 19 2010 Tomas Mraz - 0.11.13-5 +- own the _libdir/pkcs11 subdirectory (#644527) + +* Tue Sep 7 2010 Tomas Mraz - 0.11.13-4 +- fix build with new pcsc-lite + +* Wed Aug 11 2010 Rex Dieter - 0.11.13-3 +- build against libassuan1 (f14+) + +* Wed Jun 9 2010 Tomas Mraz - 0.11.13-2 +- replace file dependency (#601943) + +* Tue Feb 16 2010 Kalev Lember - 0.11.13-1 +- new upstream version + +* Sun Feb 14 2010 Kalev Lember - 0.11.12-2 +- Added patch to fix linking with the new --no-add-needed default (#564758) + +* Mon Dec 21 2009 Kalev Lember - 0.11.12-1 +- new upstream version +- replaced %%define with %%global +- BR clean up from items not applicable to current Fedora releases + +* Tue Dec 8 2009 Michael Schwendt - 0.11.11-2 +- Explicitly BR libassuan-static in accordance with the Packaging + Guidelines (libassuan-devel is still static-only). + +* Thu Nov 19 2009 Tomas Mraz - 0.11.11-1 +- new upstream version + +* Tue Sep 29 2009 Tomas Mraz - 0.11.9-2 +- fix multilib conflict in the configuration file (#526269) + +* Wed Sep 09 2009 Tomas Mraz - 0.11.9-1 +- new upstream version + +* Fri Aug 21 2009 Tomas Mraz - 0.11.8-5 +- rebuilt with new openssl + +* Mon Jul 27 2009 Tomas Mraz - 0.11.8-4 +- Depend on specific arch of pcsc-lite-libs (reported by Kalev Lember) + +* Sat Jul 25 2009 Fedora Release Engineering - 0.11.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jun 15 2009 Tomas Mraz - 0.11.8-2 +- Rebuilt with new openct + +* Mon May 11 2009 Tomas Mraz - 0.11.8-1 +- new upstream version - fixes security issue + +* Fri Feb 27 2009 Tomas Mraz - 0.11.7-1 +- new upstream version - fixes CVE-2009-0368 + +* Thu Feb 26 2009 Fedora Release Engineering - 0.11.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Jan 15 2009 Tomas Mraz - 0.11.6-2 +- Add explicit requires for pcsc-lite-libs. Dlopen libpcsclite with the full + soname. + +* Tue Sep 2 2008 Tomas Mraz - 0.11.6-1 +- Update to latest upstream, fixes CVE-2008-2235 + +* Thu Apr 10 2008 Hans de Goede - 0.11.4-5 +- BuildRequire libassuan-devel instead of libassuan-static (bz 441812) + +* Tue Feb 19 2008 Fedora Release Engineering - 0.11.4-4 +- Autorebuild for GCC 4.3 + +* Wed Dec 05 2007 Release Engineering - 0.11.4-3 + - Rebuild for deps + +* Wed Dec 5 2007 Ville Skyttä - 0.11.4-2 +- Rebuild. + +* Mon Sep 10 2007 Ville Skyttä - 0.11.4-1 +- 0.11.4. + +* Mon Aug 20 2007 Ville Skyttä - 0.11.4-0.1.rc1 +- 0.11.4-rc1, pkcs11-tool usage message fix applied upstream. +- License: LGPLv2+ + +* Thu Jul 26 2007 Ville Skyttä - 0.11.3-2 +- Fix pkcs11-tool usage message crash (#249702). + +* Tue Jul 17 2007 Ville Skyttä - 0.11.3-1 +- 0.11.3. + +* Sat Jun 30 2007 Ville Skyttä - 0.11.3-0.1.pre2 +- 0.11.3-pre2. + +* Thu Jun 21 2007 Ville Skyttä - 0.11.3-0.1.pre1 +- 0.11.3-pre1. + +* Sun May 6 2007 Ville Skyttä - 0.11.2-2 +- Add explicit build dependency on ncurses-devel. + +* Sat May 5 2007 Ville Skyttä - 0.11.2-1 +- 0.11.2. + +* Tue Apr 24 2007 Ville Skyttä - 0.11.2-0.3.rc2 +- 0.11.2-rc2. + +* Fri Mar 23 2007 Ville Skyttä - 0.11.2-0.3.rc1 +- 0.11.2-rc1. + +* Thu Mar 15 2007 Ville Skyttä - 0.11.2-0.2.pre6 +- 0.11.2-pre6. + +* Tue Mar 6 2007 Ville Skyttä - 0.11.2-0.2.pre4 +- 0.11.2-pre4. +- Require pinentry-gui instead of the pinentry executable in signer. + +* Sun Dec 3 2006 Ville Skyttä - 0.11.2-0.1.pre3 +- 0.11.2-pre3. +- Build with new libassuan. +- Don't run autotools during build. +- Adjust to readline/termcap/ncurses changes. + +* Sat Oct 14 2006 Ville Skyttä - 0.11.1-6 +- Rebuild with new libassuan. + +* Sun Oct 8 2006 Ville Skyttä - 0.11.1-5 +- Rebuild with new libassuan. + +* Mon Oct 2 2006 Ville Skyttä - 0.11.1-4 +- Rebuild. + +* Tue Sep 26 2006 Ville Skyttä - 0.11.1-3 +- Rebuild with new libassuan. + +* Sat Sep 2 2006 Ville Skyttä - 0.11.1-2 +- Rebuild. + +* Wed May 31 2006 Ville Skyttä - 0.11.1-1 +- 0.11.1. +- Avoid some multilib conflicts. + +* Sun May 7 2006 Ville Skyttä - 0.11.0-2 +- Sync example paths in openct.conf with ctapi-common. +- Update URL. + +* Thu May 4 2006 Ville Skyttä - 0.11.0-1 +- 0.11.0. + +* Thu Apr 27 2006 Ville Skyttä - 0.11.0-0.1.rc2 +- 0.11.0-rc2. + +* Sat Apr 22 2006 Ville Skyttä - 0.11.0-0.1.rc1 +- 0.11.0-rc1. + +* Mon Mar 6 2006 Ville Skyttä - 0.10.1-3 +- Rebuild. + +* Wed Feb 15 2006 Ville Skyttä - 0.10.1-2 +- Avoid standard rpaths on lib64 archs. + +* Sun Jan 8 2006 Ville Skyttä - 0.10.1-1 +- 0.10.1. + +* Wed Nov 9 2005 Ville Skyttä - 0.10.0-1 +- 0.10.0. +- Adapt to modularized X.Org. + +* Wed Oct 26 2005 Ville Skyttä - 0.10.0-0.1.rc2 +- 0.10.0-rc2. +- Install signer plugin only to plugin dir. + +* Sat Oct 22 2005 Ville Skyttä - 0.10.0-0.1.rc1 +- 0.10.0-rc1. + +* Wed Oct 19 2005 Ville Skyttä - 0.10.0-0.1.beta2.rc1 +- 0.10.0-beta2-rc1. +- Specfile cleanups. + +* Tue Apr 26 2005 Ville Skyttä - 0.9.6-2 +- 0.9.6, build patch applied upstream. +- Package summary and description improvements. +- Drop explicit openct dependency. + +* Fri Mar 18 2005 Ville Skyttä - 0.9.4-3 +- Fix FC4 build. +- Rename opensc-pam to pam_opensc per package naming guidelines. + +* Wed Feb 9 2005 Michael Schwendt - 0.9.4-2 +- Substitute hardcoded 'lib' in OpenSSL checks for multi-lib platforms. +- Use --with-plugin-dir instead of --with-plugin-path (fixes x86_64). + +* Thu Feb 3 2005 Ville Skyttä - 0.9.4-1 +- Drop unnecessary Epochs, pre-FC1 compat cruft, and no longer relevant + --with(out) rpmbuild options. +- Exclude *.la. + +* Wed Nov 3 2004 Ville Skyttä - 0:0.9.4-0.fdr.1 +- Update to 0.9.4, parallel build patch applied upstream. +- Patch to fix library paths and LDFLAGS. +- Don't require mozilla, but the plugin dir in signer. +- Build with dependency tracking disabled. + +* Tue Jul 27 2004 Ville Skyttä - 0:0.9.2-0.fdr.2 +- Building the signer plugin can be disabled with "--without signer". + Thanks to Fritz Elfert for the idea. +- Update description. + +* Sun Jul 25 2004 Ville Skyttä - 0:0.9.2-0.fdr.1 +- Update to 0.9.2, old patches applied upstream. +- Add patch to fix parallel builds. +- Convert man pages to UTF-8. + +* Thu Jul 22 2004 Ville Skyttä - 0:0.9.1-0.fdr.1 +- Update to 0.9.1 (preview). + +* Thu Jul 1 2004 Ville Skyttä - 0:0.9.0-0.fdr.0.1.alpha +- Update to 0.9.0-alpha. + +* Sat May 1 2004 Ville Skyttä - 0:0.8.1-0.fdr.8 +- Rebuild with libassuan 0.6.5. + +* Sat Jan 31 2004 Ville Skyttä - 0:0.8.1-0.fdr.7 +- Rebuild with libassuan 0.6.3. +- Add gdm example to PAM quickstart. + +* Mon Jan 19 2004 Ville Skyttä - 0:0.8.1-0.fdr.6 +- Use /%%{_lib} instead of hardcoding /lib. + +* Sat Dec 20 2003 Ville Skyttä - 0:0.8.1-0.fdr.5 +- Split PAM support into a subpackage. +- Rebuild with libassuan 0.6.2. + +* Sun Nov 23 2003 Ville Skyttä - 0:0.8.1-0.fdr.4 +- Rebuild with libassuan 0.6.1. +- Include PAM quickstart doc snippet. + +* Fri Nov 14 2003 Ville Skyttä - 0:0.8.1-0.fdr.3 +- Require OpenCT. + +* Fri Oct 17 2003 Ville Skyttä - 0:0.8.1-0.fdr.2 +- Install example config files as documentation. + +* Tue Oct 14 2003 Ville Skyttä - 0:0.8.1-0.fdr.1 +- Update to 0.8.1. + +* Wed Aug 27 2003 Ville Skyttä - 0:0.8.0-0.fdr.2 +- Signer can be built with oldssl too. + +* Wed Aug 27 2003 Ville Skyttä - 0:0.8.0-0.fdr.1 +- Update to 0.8.0. + +* Wed Jul 30 2003 Ville Skyttä - 0:0.8.0-0.fdr.0.2.cvs20030730 +- Update to 20030730. +- Clean up %%docs. +- Include *.la (uses ltdl). +- Own the %%{_libdir}/pkcs11 directory. +- Disable signer; assuan has disappeared from the tarball :( + +* Fri May 23 2003 Ville Skyttä - 0:0.8.0-0.fdr.0.1.rc1 +- First build.