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-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-0.19.0-pinpad.patch b/SOURCES/opensc-0.19.0-pinpad.patch new file mode 100644 index 0000000..f531b8b --- /dev/null +++ b/SOURCES/opensc-0.19.0-pinpad.patch @@ -0,0 +1,13 @@ +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 2018-10-22 14:31:12.082963540 +0200 ++++ opensc-0.19.0/etc/opensc.conf 2018-10-22 14:33:59.939410701 +0200 +@@ -4,4 +4,9 @@ app default { + framework pkcs15 { + # use_file_caching = true; + } ++ reader_driver pcsc { ++ # The pinpad is disabled by default, ++ # because of many broken readers out there ++ enable_pinpad = false; ++ } + } diff --git a/SOURCES/opensc-0.19.0-rsa-pss.patch b/SOURCES/opensc-0.19.0-rsa-pss.patch new file mode 100644 index 0000000..2842071 --- /dev/null +++ b/SOURCES/opensc-0.19.0-rsa-pss.patch @@ -0,0 +1,2385 @@ +From b85c0706db871828f0bc4672571dd0b9c98dd835 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Sun, 22 Jul 2018 16:23:54 +0200 +Subject: [PATCH 1/5] doc: Fix the pkcs11-tool example + +Signed-off-by: Jakub Jelen +--- + doc/tools/pkcs11-tool.1.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml +index 37093f352..c609ec0e2 100644 +--- a/doc/tools/pkcs11-tool.1.xml ++++ b/doc/tools/pkcs11-tool.1.xml +@@ -568,7 +568,7 @@ + + To read the certificate with ID KEY_ID + in DER format from smart card: +- pkcs11-tool --read-object --id KEY_ID --type cert --outfile cert.der ++ pkcs11-tool --read-object --id KEY_ID --type cert --output-file cert.der + + To convert the certificate in DER format to PEM format, use OpenSSL + tools: + +From 5cc144111acb7b9982ddec7f7597a22c10c4d456 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 14 Sep 2018 14:11:18 +0200 +Subject: [PATCH 2/5] p11test: Add missing CKM_SHA224_RSA_PKCS_PSS + +Signed-off-by: Jakub Jelen +--- + src/tests/p11test/p11test_case_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/tests/p11test/p11test_case_common.c b/src/tests/p11test/p11test_case_common.c +index deb2a56fe..d44b0d8e3 100644 +--- a/src/tests/p11test/p11test_case_common.c ++++ b/src/tests/p11test/p11test_case_common.c +@@ -587,6 +587,8 @@ const char *get_mechanism_name(int mech_id) + return "RSA_PKCS_PSS"; + case CKM_SHA1_RSA_PKCS_PSS: + return "SHA1_RSA_PKCS_PSS"; ++ case CKM_SHA224_RSA_PKCS_PSS: ++ return "SHA224_RSA_PKCS_PSS"; + case CKM_SHA256_RSA_PKCS_PSS: + return "SHA256_RSA_PKCS_PSS"; + case CKM_SHA384_RSA_PKCS_PSS: + +From 5aa3dbcdd76af0197946252ff53a0636cb979ab3 Mon Sep 17 00:00:00 2001 +From: Nicholas Wilson +Date: Tue, 25 Aug 2015 12:45:27 +0100 +Subject: [PATCH 3/5] Add support for PSS padding to RSA signatures + +A card driver may declare support for computing the padding on the card, +or else the padding will be applied locally in padding.c. All five +PKCS11 PSS mechanisms are supported, for signature and verification. + +There are a few limits on what we choose to support, in particular I +don't see a need for arbitrary combinations of MGF hash, data hash, and +salt length, so I've restricted it (for the user's benefit) to the only +cases that really matter, where salt_len = hash_len and the same hash is +used for the MGF and data hashing. + +------------------------------------------------------------------------ +Reworked and extended in 2018 by Jakub Jelen against +current OpenSC master, to actually work with existing PIV cards: + * extended of missing mechanisms (SHA224, possibility to select MGF1) + * compatibility with OpenSSL 1.1+ + * Removed the ANSI padding + * Formatting cleanup, error checking + +Based on the original work from + +https://github.com/NWilson/OpenSC/commit/42f3199e66 + +Signed-off-by: Jakub Jelen +--- + src/libopensc/card-atrust-acos.c | 2 +- + src/libopensc/card-starcos.c | 4 +- + src/libopensc/internal.h | 2 +- + src/libopensc/opensc.h | 74 +++++++-- + src/libopensc/padding.c | 257 ++++++++++++++++++++++++++---- + src/libopensc/pkcs15-sec.c | 33 ++-- + src/pkcs11/framework-pkcs15.c | 265 +++++++++++++++++++++++-------- + src/pkcs11/mechanism.c | 31 +++- + src/pkcs11/openssl.c | 151 ++++++++++++++++-- + src/pkcs11/pkcs11.h | 3 +- + src/pkcs11/sc-pkcs11.h | 9 +- + 11 files changed, 674 insertions(+), 157 deletions(-) + +diff --git a/src/libopensc/card-atrust-acos.c b/src/libopensc/card-atrust-acos.c +index fb0b296c8..05ef0f441 100644 +--- a/src/libopensc/card-atrust-acos.c ++++ b/src/libopensc/card-atrust-acos.c +@@ -722,7 +722,7 @@ static int atrust_acos_compute_signature(struct sc_card *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + tmp_len = sizeof(sbuf); + r = sc_pkcs1_encode(card->ctx, flags, data, datalen, +- sbuf, &tmp_len, sizeof(sbuf)); ++ sbuf, &tmp_len, sizeof(sbuf)*8); + if (r < 0) + return r; + } else { +diff --git a/src/libopensc/card-starcos.c b/src/libopensc/card-starcos.c +index 7ad132dc1..799c6a680 100644 +--- a/src/libopensc/card-starcos.c ++++ b/src/libopensc/card-starcos.c +@@ -1545,7 +1545,7 @@ static int starcos_compute_signature(sc_card_t *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + } + tmp_len = sizeof(sbuf); +- r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)); ++ r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)*8); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_pkcs1_encode failed"); + } else { + memcpy(sbuf, data, datalen); +@@ -1607,7 +1607,7 @@ static int starcos_compute_signature(sc_card_t *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + tmp_len = sizeof(sbuf); + r = sc_pkcs1_encode(card->ctx, flags, data, datalen, +- sbuf, &tmp_len, sizeof(sbuf)); ++ sbuf, &tmp_len, sizeof(sbuf)*8); + if (r < 0) + return r; + } else { +diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h +index 9d6a77ffe..08d590f23 100644 +--- a/src/libopensc/internal.h ++++ b/src/libopensc/internal.h +@@ -159,7 +159,7 @@ int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm, + * @return SC_SUCCESS on success and an error code otherwise + */ + int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, +- const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t modlen); ++ const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t mod_bits); + /** + * Get the necessary padding and sec. env. flags. + * @param ctx IN sc_contex_t object +diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h +index b9b960d8f..a4e87d5bf 100644 +--- a/src/libopensc/opensc.h ++++ b/src/libopensc/opensc.h +@@ -93,19 +93,39 @@ extern "C" { + #define SC_ALGORITHM_NEED_USAGE 0x40000000 + #define SC_ALGORITHM_SPECIFIC_FLAGS 0x001FFFFF + +-#define SC_ALGORITHM_RSA_RAW 0x00000001 + /* If the card is willing to produce a cryptogram padded with the following +- * methods, set these flags accordingly. */ +-#define SC_ALGORITHM_RSA_PADS 0x0000001E +-#define SC_ALGORITHM_RSA_PAD_NONE 0x00000000 +-#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 ++ * methods, set these flags accordingly. These flags are exclusive: an RSA card ++ * must support at least one of them, and exactly one of them must be selected ++ * for a given operation. */ ++#define SC_ALGORITHM_RSA_RAW 0x00000001 ++#define SC_ALGORITHM_RSA_PADS 0x0000001F ++#define SC_ALGORITHM_RSA_PAD_NONE 0x00000001 ++#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 /* PKCS#1 v1.5 padding */ + #define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004 + #define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008 +-#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 ++#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* PKCS#1 v2.0 PSS */ + + /* If the card is willing to produce a cryptogram with the following +- * hash values, set these flags accordingly. */ +-#define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 ++ * hash values, set these flags accordingly. The interpretation of the hash ++ * flags depends on the algorithm and padding chosen: for RSA, the hash flags ++ * determine how the padding is constructed and do not describe the first ++ * hash applied to the document before padding begins. ++ * ++ * - For PAD_NONE, ANSI X9.31, (and ISO9796?), the hash value is therefore ++ * ignored. For ANSI X9.31, the input data must already have the hash ++ * identifier byte appended (eg 0x33 for SHA-1). ++ * - For PKCS1 (v1.5) the hash is recorded in the padding, and HASH_NONE is a ++ * valid value, meaning that the hash's DigestInfo has already been ++ * prepended to the data, otherwise the hash id is put on the front. ++ * - For PSS (PKCS#1 v2.0) the hash is used to derive the padding from the ++ * already-hashed message. ++ * ++ * In no case is the hash actually applied to the entire document. ++ * ++ * It's possible that the card may support different hashes for PKCS1 and PSS ++ * signatures; in this case the card driver has to pick the lowest-denominator ++ * when it sets these flags to indicate its capabilities. */ ++#define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 /* only applies to PKCS1 padding */ + #define SC_ALGORITHM_RSA_HASH_SHA1 0x00000200 + #define SC_ALGORITHM_RSA_HASH_MD5 0x00000400 + #define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000800 +@@ -114,21 +134,39 @@ extern "C" { + #define SC_ALGORITHM_RSA_HASH_SHA384 0x00004000 + #define SC_ALGORITHM_RSA_HASH_SHA512 0x00008000 + #define SC_ALGORITHM_RSA_HASH_SHA224 0x00010000 +-#define SC_ALGORITHM_RSA_HASHES 0x0001FE00 +- ++#define SC_ALGORITHM_RSA_HASHES 0x0001FF00 ++ ++/* This defines the hashes to be used with MGF1 in PSS padding */ ++#define SC_ALGORITHM_MGF1_SHA1 0x00100000 ++#define SC_ALGORITHM_MGF1_SHA256 0x00200000 ++#define SC_ALGORITHM_MGF1_SHA384 0x00400000 ++#define SC_ALGORITHM_MGF1_SHA512 0x00800000 ++#define SC_ALGORITHM_MGF1_SHA224 0x01000000 ++#define SC_ALGORITHM_MGF1_HASHES 0x01F00000 ++ ++/* These flags are exclusive: a GOST R34.10 card must support at least one or the ++ * other of the methods, and exactly one of them applies to any given operation. ++ * Note that the GOST R34.11 hash is actually applied to the data (ie if this ++ * algorithm is chosen the entire unhashed document is passed in). */ + #define SC_ALGORITHM_GOSTR3410_RAW 0x00020000 +-#define SC_ALGORITHM_GOSTR3410_HASH_NONE 0x00040000 ++#define SC_ALGORITHM_GOSTR3410_HASH_NONE SC_ALGORITHM_GOSTR3410_RAW /*XXX*/ + #define SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411 0x00080000 +-#define SC_ALGORITHM_GOSTR3410_HASHES 0x00080000 +-/*TODO: -DEE Should the above be 0x0000E000 */ +-/* Or should the HASH_NONE be 0x00000010 and HASHES be 0x00008010 */ +- ++#define SC_ALGORITHM_GOSTR3410_HASHES 0x000A0000 ++/*TODO: -DEE Should the above be 0x000E0000 */ ++/* Or should the HASH_NONE be 0x00000100 and HASHES be 0x00080010 */ ++ ++/* The ECDSA flags are exclusive, and exactly one of them applies to any given ++ * operation. If ECDSA with a hash is specified, then the data passed in is ++ * the entire document, unhashed, and the hash is applied once to it before ++ * truncating and signing. These flags are distinct from the RSA hash flags, ++ * which determine the hash ids the card is willing to put in RSA message ++ * padding. */ + /* May need more bits if card can do more hashes */ + /* TODO: -DEE Will overload RSA_HASHES with EC_HASHES */ + /* Not clear if these need their own bits or not */ + /* The PIV card does not support and hashes */ +-#define SC_ALGORITHM_ECDSA_RAW 0x00100000 + #define SC_ALGORITHM_ECDH_CDH_RAW 0x00200000 ++#define SC_ALGORITHM_ECDSA_RAW 0x00100000 + #define SC_ALGORITHM_ECDSA_HASH_NONE SC_ALGORITHM_RSA_HASH_NONE + #define SC_ALGORITHM_ECDSA_HASH_SHA1 SC_ALGORITHM_RSA_HASH_SHA1 + #define SC_ALGORITHM_ECDSA_HASH_SHA224 SC_ALGORITHM_RSA_HASH_SHA224 +@@ -142,7 +180,9 @@ extern "C" { + SC_ALGORITHM_ECDSA_HASH_SHA512) + + /* define mask of all algorithms that can do raw */ +-#define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ECDSA_RAW) ++#define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | \ ++ SC_ALGORITHM_GOSTR3410_RAW | \ ++ SC_ALGORITHM_ECDSA_RAW) + + /* extended algorithm bits for selected mechs */ + #define SC_ALGORITHM_EXT_EC_F_P 0x00000001 +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index f544e5778..53a87c352 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -23,6 +23,12 @@ + #include "config.h" + #endif + ++#ifdef ENABLE_OPENSSL ++#include ++#include ++#include ++#endif ++ + #include + #include + +@@ -231,22 +237,183 @@ int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm, + return SC_ERROR_INTERNAL; + } + ++#ifdef ENABLE_OPENSSL ++ ++static const EVP_MD* hash_flag2md(unsigned int hash) ++{ ++ switch (hash & SC_ALGORITHM_RSA_HASHES) { ++ case SC_ALGORITHM_RSA_HASH_SHA1: ++ return EVP_sha1(); ++ case SC_ALGORITHM_RSA_HASH_SHA224: ++ return EVP_sha224(); ++ case SC_ALGORITHM_RSA_HASH_SHA256: ++ return EVP_sha256(); ++ case SC_ALGORITHM_RSA_HASH_SHA384: ++ return EVP_sha384(); ++ case SC_ALGORITHM_RSA_HASH_SHA512: ++ return EVP_sha512(); ++ default: ++ return NULL; ++ } ++} ++ ++static const EVP_MD* mgf1_flag2md(unsigned int mgf1) ++{ ++ switch (mgf1 & SC_ALGORITHM_MGF1_HASHES) { ++ case SC_ALGORITHM_MGF1_SHA1: ++ return EVP_sha1(); ++ case SC_ALGORITHM_MGF1_SHA224: ++ return EVP_sha224(); ++ case SC_ALGORITHM_MGF1_SHA256: ++ return EVP_sha256(); ++ case SC_ALGORITHM_MGF1_SHA384: ++ return EVP_sha384(); ++ case SC_ALGORITHM_MGF1_SHA512: ++ return EVP_sha512(); ++ default: ++ return NULL; ++ } ++} ++ ++/* add PKCS#1 v2.0 PSS padding */ ++static int sc_pkcs1_add_pss_padding(unsigned int hash, unsigned int mgf1_hash, ++ const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits) ++{ ++ /* hLen = sLen in our case */ ++ int rv = SC_ERROR_INTERNAL, i, j, hlen, dblen, plen, round, mgf_rounds; ++ int mgf1_hlen; ++ const EVP_MD* md, *mgf1_md; ++ EVP_MD_CTX* ctx = NULL; ++ u8 buf[8]; ++ u8 salt[EVP_MAX_MD_SIZE], mask[EVP_MAX_MD_SIZE]; ++ size_t mod_length = (mod_bits + 7) / 8; ++ ++ if (*out_len < mod_length) ++ return SC_ERROR_BUFFER_TOO_SMALL; ++ ++ md = hash_flag2md(hash); ++ if (md == NULL) ++ return SC_ERROR_NOT_SUPPORTED; ++ hlen = EVP_MD_size(md); ++ dblen = mod_length - hlen - 1; /* emLen - hLen - 1 */ ++ plen = mod_length - 2*hlen - 1; ++ if (in_len != (unsigned)hlen) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ if (2 * (unsigned)hlen + 2 > mod_length) ++ /* RSA key too small for chosen hash (1296 bits or higher needed for ++ * signing SHA-512 hashes) */ ++ return SC_ERROR_NOT_SUPPORTED; ++ ++ if (RAND_bytes(salt, hlen) != 1) ++ return SC_ERROR_INTERNAL; ++ ++ /* Hash M' to create H */ ++ if (!(ctx = EVP_MD_CTX_create())) ++ goto done; ++ memset(buf, 0x00, 8); ++ if (EVP_DigestInit_ex(ctx, md, NULL) != 1 || ++ EVP_DigestUpdate(ctx, buf, 8) != 1 || ++ EVP_DigestUpdate(ctx, in, hlen) != 1 || /* mHash */ ++ EVP_DigestUpdate(ctx, salt, hlen) != 1) { ++ goto done; ++ } ++ ++ /* Construct padding2, salt, H, and BC in the output block */ ++ /* DB = PS || 0x01 || salt */ ++ memset(out, 0x00, plen - 1); /* emLen - sLen - hLen - 2 */ ++ out[plen - 1] = 0x01; ++ memcpy(out + plen, salt, hlen); ++ if (EVP_DigestFinal_ex(ctx, out + dblen, NULL) != 1) { /* H */ ++ goto done; ++ } ++ out[dblen + hlen] = 0xBC; ++ /* EM = DB* || H || 0xbc ++ * *the first part is masked later */ ++ ++ /* Construct the DB mask block by block and XOR it in. */ ++ mgf1_md = mgf1_flag2md(mgf1_hash); ++ if (mgf1_md == NULL) ++ return SC_ERROR_NOT_SUPPORTED; ++ mgf1_hlen = EVP_MD_size(mgf1_md); ++ ++ mgf_rounds = (dblen + mgf1_hlen - 1) / mgf1_hlen; /* round up */ ++ for (round = 0; round < mgf_rounds; ++round) { ++ buf[0] = (round&0xFF000000U) >> 24; ++ buf[1] = (round&0x00FF0000U) >> 16; ++ buf[2] = (round&0x0000FF00U) >> 8; ++ buf[3] = (round&0x000000FFU); ++ if (EVP_DigestInit_ex(ctx, mgf1_md, NULL) != 1 || ++ EVP_DigestUpdate(ctx, out + dblen, hlen) != 1 || /* H (Z parameter of MGF1) */ ++ EVP_DigestUpdate(ctx, buf, 4) != 1 || /* C */ ++ EVP_DigestFinal_ex(ctx, mask, NULL)) { ++ goto done; ++ } ++ /* this is no longer part of the MGF1, but actually ++ * XORing mask with DB to create maskedDB inplace */ ++ for (i = round * mgf1_hlen, j = 0; i < dblen && j < mgf1_hlen; ++i, ++j) { ++ out[i] ^= mask[j]; ++ } ++ } ++ ++ /* Set leftmost N bits in leftmost octet in maskedDB to zero ++ * to make sure the result is smaller than the modulus ( +1) ++ */ ++ out[0] &= (0xff >> (8 * mod_length - mod_bits + 1)); ++ ++ *out_len = mod_length; ++ rv = SC_SUCCESS; ++ ++done: ++ OPENSSL_cleanse(salt, sizeof(salt)); ++ OPENSSL_cleanse(mask, sizeof(mask)); ++ if (ctx) { ++ EVP_MD_CTX_destroy(ctx); ++ } ++ return rv; ++} ++ ++static int hash_len2algo(size_t hash_len) ++{ ++ switch (hash_len) { ++ case SHA_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA1; ++ case SHA224_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA224; ++ case SHA256_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA256; ++ case SHA384_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA384; ++ case SHA512_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA512; ++ } ++ /* Should never happen -- the mechanism and data should be already ++ * verified to match one of the above. If not, we will fail later ++ */ ++ return SC_ALGORITHM_RSA_HASH_NONE; ++} ++#endif ++ + /* general PKCS#1 encoding function */ + int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, +- const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_len) ++ const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits) + { + int rv, i; + size_t tmp_len = *out_len; + const u8 *tmp = in; + unsigned int hash_algo, pad_algo; ++ size_t mod_len = (mod_bits + 7) / 8; ++#ifdef ENABLE_OPENSSL ++ unsigned int mgf1_hash; ++#endif + + LOG_FUNC_CALLED(ctx); + +- hash_algo = flags & (SC_ALGORITHM_RSA_HASHES | SC_ALGORITHM_RSA_HASH_NONE); ++ hash_algo = flags & SC_ALGORITHM_RSA_HASHES; + pad_algo = flags & SC_ALGORITHM_RSA_PADS; + sc_log(ctx, "hash algorithm 0x%X, pad algorithm 0x%X", hash_algo, pad_algo); + +- if (hash_algo != SC_ALGORITHM_RSA_HASH_NONE) { ++ if ((pad_algo == SC_ALGORITHM_RSA_PAD_PKCS1 || !pad_algo) && ++ hash_algo != SC_ALGORITHM_RSA_HASH_NONE) { + i = sc_pkcs1_add_digest_info_prefix(hash_algo, in, in_len, out, &tmp_len); + if (i != SC_SUCCESS) { + sc_log(ctx, "Unable to add digest info 0x%x", hash_algo); +@@ -268,10 +435,29 @@ int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, + /* add pkcs1 bt01 padding */ + rv = sc_pkcs1_add_01_padding(tmp, tmp_len, out, out_len, mod_len); + LOG_FUNC_RETURN(ctx, rv); ++ case SC_ALGORITHM_RSA_PAD_PSS: ++ /* add PSS padding */ ++#ifdef ENABLE_OPENSSL ++ mgf1_hash = flags & SC_ALGORITHM_MGF1_HASHES; ++ if (hash_algo == SC_ALGORITHM_RSA_HASH_NONE) { ++ /* this is generic RSA_PKCS1_PSS mechanism with hash ++ * already done outside of the module. The parameters ++ * were already checked so we need to adjust the hash ++ * algorithm to do the padding with the correct hash ++ * function. ++ */ ++ hash_algo = hash_len2algo(tmp_len); ++ } ++ rv = sc_pkcs1_add_pss_padding(hash_algo, mgf1_hash, ++ tmp, tmp_len, out, out_len, mod_bits); ++#else ++ rv = SC_ERROR_NOT_SUPPORTED; ++#endif ++ LOG_FUNC_RETURN(ctx, rv); + default: +- /* currently only pkcs1 padding is supported */ +- sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported padding algorithm 0x%x", pad_algo); +- LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); ++ /* We shouldn't be called with an unexpected padding type, we've already ++ * returned SC_ERROR_NOT_SUPPORTED if the card can't be used. */ ++ LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); + } + } + +@@ -279,42 +465,45 @@ int sc_get_encoding_flags(sc_context_t *ctx, + unsigned long iflags, unsigned long caps, + unsigned long *pflags, unsigned long *sflags) + { +- size_t i; +- + LOG_FUNC_CALLED(ctx); + if (pflags == NULL || sflags == NULL) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + sc_log(ctx, "iFlags 0x%lX, card capabilities 0x%lX", iflags, caps); +- for (i = 0; digest_info_prefix[i].algorithm != 0; i++) { +- if (iflags & digest_info_prefix[i].algorithm) { +- if (digest_info_prefix[i].algorithm != SC_ALGORITHM_RSA_HASH_NONE && +- caps & digest_info_prefix[i].algorithm) +- *sflags |= digest_info_prefix[i].algorithm; +- else +- *pflags |= digest_info_prefix[i].algorithm; +- break; +- } +- } + +- if (iflags & SC_ALGORITHM_RSA_PAD_PKCS1) { +- if (caps & SC_ALGORITHM_RSA_PAD_PKCS1) +- *sflags |= SC_ALGORITHM_RSA_PAD_PKCS1; +- else +- *pflags |= SC_ALGORITHM_RSA_PAD_PKCS1; +- } else if ((iflags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { +- +- /* Work with RSA, EC and maybe GOSTR? */ +- if (!(caps & SC_ALGORITHM_RAW_MASK)) +- LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "raw encryption is not supported"); ++ /* For ECDSA and GOSTR, we don't do any padding or hashing ourselves, the ++ * card has to support the requested operation. Similarly, for RSA with ++ * raw padding (raw RSA) and ISO9796, we require the card to do it for us. ++ * Finally, for PKCS1 (v1.5 and PSS) and ASNI X9.31 we can apply the padding ++ * ourselves if the card supports raw RSA. */ + +- *sflags |= (caps & SC_ALGORITHM_RAW_MASK); /* adds in the one raw type */ ++ /* TODO: Could convert GOSTR3410_HASH_GOSTR3411 -> GOSTR3410_RAW and ++ * ECDSA_HASH_ -> ECDSA_RAW using OpenSSL (not much benefit though). */ ++ ++ if ((caps & iflags) == iflags) { ++ /* Card supports the signature operation we want to do, great, let's ++ * go with it then. */ ++ *sflags = iflags; + *pflags = 0; +- } else if (iflags & SC_ALGORITHM_RSA_PAD_PSS) { +- if (caps & SC_ALGORITHM_RSA_PAD_PSS) +- *sflags |= SC_ALGORITHM_RSA_PAD_PSS; +- else +- *pflags |= SC_ALGORITHM_RSA_PAD_PSS; ++ ++ } else if ((caps & SC_ALGORITHM_RSA_PAD_PSS) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PSS)) { ++ *sflags |= SC_ALGORITHM_RSA_PAD_PSS; ++ ++ } else if (((caps & SC_ALGORITHM_RSA_RAW) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) ++ || iflags & SC_ALGORITHM_RSA_PAD_PSS) { ++ /* Use the card's raw RSA capability on the padded input */ ++ *sflags = SC_ALGORITHM_RSA_PAD_NONE; ++ *pflags = iflags; ++ ++ } else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) { ++ /* A corner case - the card can partially do PKCS1, if we prepend the ++ * DigestInfo bit it will do the rest. */ ++ *sflags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; ++ *pflags = iflags & SC_ALGORITHM_RSA_HASHES; ++ + } else { + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported algorithm"); + } +diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c +index 6ee4fa3c7..3e7e03b12 100644 +--- a/src/libopensc/pkcs15-sec.c ++++ b/src/libopensc/pkcs15-sec.c +@@ -329,7 +329,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + + switch (obj->type) { + case SC_PKCS15_TYPE_PRKEY_RSA: +- modlen = prkey->modulus_length / 8; ++ modlen = (prkey->modulus_length + 7) / 8; + break; + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + modlen = (prkey->modulus_length + 7) / 8 * 2; +@@ -377,7 +377,8 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + if (modlen > tmplen) + LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!"); + +- r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, modlen); ++ /* XXX Assuming RSA key here */ ++ r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length); + + /* no padding needed - already done */ + flags &= ~SC_ALGORITHM_RSA_PADS; +@@ -391,10 +392,15 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + } + + +- /* If the card doesn't support the requested algorithm, see if we +- * can strip the input so a more restrictive algo can be used */ ++ /* If the card doesn't support the requested algorithm, we normally add the ++ * padding here in software and ask the card to do a raw signature. There's ++ * one exception to that, where we might be able to get the signature to ++ * succeed by stripping padding if the card only offers higher-level ++ * signature operations. The only thing we can strip is the DigestInfo ++ * block from PKCS1 padding. */ + if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && +- !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) { ++ !(alg_info->flags & SC_ALGORITHM_RSA_RAW) && ++ !(alg_info->flags & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE))) { + unsigned int algo; + size_t tmplen = sizeof(buf); + +@@ -420,19 +426,16 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + + /* add the padding bytes (if necessary) */ + if (pad_flags != 0) { +- if (flags & SC_ALGORITHM_RSA_PAD_PSS) { +- // TODO PSS padding +- } else { +- size_t tmplen = sizeof(buf); +- +- r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); +- SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); ++ size_t tmplen = sizeof(buf); + +- inlen = tmplen; +- } ++ /* XXX Assuming RSA key here */ ++ r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, ++ prkey->modulus_length); ++ SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); ++ inlen = tmplen; + } + else if ( senv.algorithm == SC_ALGORITHM_RSA && +- (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { ++ (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { + /* Add zero-padding if input is shorter than the modulus */ + if (inlen < modlen) { + if (modlen > sizeof(buf)) +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 80f9ce89f..a75d239f4 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -3478,7 +3478,8 @@ struct sc_pkcs11_object_ops pkcs15_cert_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + /* +@@ -3703,53 +3704,44 @@ static CK_RV + pkcs15_prkey_check_pss_param(CK_MECHANISM_PTR pMechanism, CK_ULONG hlen) + { + CK_RSA_PKCS_PSS_PARAMS *pss_param; +- +- if (pMechanism->pParameter == NULL) +- return CKR_OK; // Support applications that don't provide CK_RSA_PKCS_PSS_PARAMS +- +- if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) +- return CKR_MECHANISM_PARAM_INVALID; ++ int i; ++ const unsigned int hash_lens[5] = { 160, 256, 385, 512, 224 }; ++ const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256, ++ CKM_SHA384, CKM_SHA512, CKM_SHA224 }; + + pss_param = (CK_RSA_PKCS_PSS_PARAMS *)pMechanism->pParameter; + +- // Hash parameter must match mechanisms or length of data supplied for CKM_RSA_PKCS_PSS +- switch(pss_param->hashAlg) { +- case CKM_SHA_1: +- if (hlen != 20) +- return CKR_MECHANISM_PARAM_INVALID; +- break; +- case CKM_SHA256: +- if (hlen != 32) ++ // Hash parameter must match length of data supplied for CKM_RSA_PKCS_PSS ++ for (i = 0; i < 5; i++) { ++ if (pss_param->hashAlg == hashes[i] ++ && hlen != hash_lens[i]/8) + return CKR_MECHANISM_PARAM_INVALID; +- break; +- default: +- return CKR_MECHANISM_PARAM_INVALID; + } ++ /* other aspects of pss params were already verified during SignInit */ + +- // SmartCards typically only support MGFs based on the same hash as the +- // message digest +- switch(pss_param->mgf) { +- case CKG_MGF1_SHA1: +- if (hlen != 20) +- return CKR_MECHANISM_PARAM_INVALID; ++ return CKR_OK; ++} ++ ++static int mgf2flags(CK_RSA_PKCS_MGF_TYPE mgf) ++{ ++ switch (mgf) { ++ case CKG_MGF1_SHA224: ++ return SC_ALGORITHM_MGF1_SHA224; + break; + case CKG_MGF1_SHA256: +- if (hlen != 32) +- return CKR_MECHANISM_PARAM_INVALID; +- break; ++ return SC_ALGORITHM_MGF1_SHA256; ++ case CKG_MGF1_SHA384: ++ return SC_ALGORITHM_MGF1_SHA384; ++ case CKG_MGF1_SHA512: ++ return SC_ALGORITHM_MGF1_SHA512; ++ case CKG_MGF1_SHA1: ++ return SC_ALGORITHM_MGF1_SHA1; + default: +- return CKR_MECHANISM_PARAM_INVALID; ++ return -1; + } +- +- // SmartCards typically support only a salt length equal to the hash length +- if (pss_param->sLen != hlen) +- return CKR_MECHANISM_PARAM_INVALID; +- +- return CKR_OK; + } + + +- + static CK_RV + pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData, +@@ -3798,35 +3790,74 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + case CKM_SHA512_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA512; + break; ++ case CKM_RIPEMD160_RSA_PKCS: ++ flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_RIPEMD160; ++ break; ++ case CKM_RSA_X_509: ++ flags = SC_ALGORITHM_RSA_RAW; ++ break; + case CKM_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); ++ flags = SC_ALGORITHM_RSA_PAD_PSS; ++ /* The hash was done ouside of the module */ ++ flags |= SC_ALGORITHM_RSA_HASH_NONE; ++ /* Omited parameter can use MGF1-SHA1 ? */ ++ if (pMechanism->pParameter == NULL) { ++ flags |= SC_ALGORITHM_MGF1_SHA1; ++ if (ulDataLen != SHA_DIGEST_LENGTH) ++ return CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } + +- if (rv != CKR_OK) ++ /* Check the data length matches the selected hash */ ++ rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); ++ if (rv != CKR_OK) { ++ sc_log(context, "Invalid data lenght for the selected " ++ "PSS parameters"); + return rv; ++ } + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_NONE; +- break; +- case CKM_SHA1_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, 20); +- +- if (rv != CKR_OK) +- return rv; ++ /* The MGF parameter was already verified in SignInit() */ ++ flags |= mgf2flags(((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->mgf); + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA1; ++ /* Assuming salt is the size of hash */ + break; ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, 32); ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ flags = SC_ALGORITHM_RSA_PAD_PSS; ++ /* Omited parameter can use MGF1-SHA1 and SHA1 hash ? */ ++ if (pMechanism->pParameter == NULL) { ++ flags |= SC_ALGORITHM_RSA_HASH_SHA1; ++ flags |= SC_ALGORITHM_MGF1_SHA1; ++ break; ++ } + +- if (rv != CKR_OK) +- return rv; ++ switch (((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->hashAlg) { ++ case CKM_SHA_1: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA1; ++ break; ++ case CKM_SHA224: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA224; ++ break; ++ case CKM_SHA256: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA256; ++ break; ++ case CKM_SHA384: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA384; ++ break; ++ case CKM_SHA512: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA512; ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA256; +- break; +- case CKM_RIPEMD160_RSA_PKCS: +- flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_RIPEMD160; +- break; +- case CKM_RSA_X_509: +- flags = SC_ALGORITHM_RSA_RAW; ++ /* The MGF parameter was already verified in SignInit() */ ++ flags |= mgf2flags(((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->mgf); ++ ++ /* Assuming salt is the size of hash */ + break; + case CKM_GOSTR3410: + flags = SC_ALGORITHM_GOSTR3410_HASH_NONE; +@@ -4074,6 +4105,76 @@ pkcs15_prkey_can_do(struct sc_pkcs11_session *session, void *obj, + } + + ++static CK_RV ++pkcs15_prkey_init_params(struct sc_pkcs11_session *session, ++ CK_MECHANISM_PTR pMechanism) ++{ ++ const CK_RSA_PKCS_PSS_PARAMS *pss_params; ++ unsigned int expected_hash = 0, i; ++ unsigned int expected_salt_len = 0; ++ const unsigned int salt_lens[5] = { 160, 256, 384, 512, 224 }; ++ const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256, ++ CKM_SHA384, CKM_SHA512, CKM_SHA224 }; ++ ++ switch (pMechanism->mechanism) { ++ case CKM_RSA_PKCS_PSS: ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: ++ case CKM_SHA256_RSA_PKCS_PSS: ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ if (!pMechanism->pParameter || ++ pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ pss_params = (CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter; ++ if (pss_params->mgf < CKG_MGF1_SHA1 || pss_params->mgf > CKG_MGF1_SHA224) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* The hashAlg field can have any value for CKM_RSA_PKCS_PSS and must be ++ * used again in the PSS padding; for the other mechanisms it strictly ++ * must match the padding declared in the mechanism. ++ */ ++ if (pMechanism->mechanism == CKM_SHA1_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA_1; ++ expected_salt_len = 160; ++ } else if (pMechanism->mechanism == CKM_SHA224_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA224; ++ expected_salt_len = 224; ++ } else if (pMechanism->mechanism == CKM_SHA256_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA256; ++ expected_salt_len = 256; ++ } else if (pMechanism->mechanism == CKM_SHA384_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA384; ++ expected_salt_len = 384; ++ } else if (pMechanism->mechanism == CKM_SHA512_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA512; ++ expected_salt_len = 512; ++ } else if (pMechanism->mechanism == CKM_RSA_PKCS_PSS) { ++ for (i = 0; i < 5; ++i) { ++ if (hashes[i] == pss_params->hashAlg) { ++ expected_hash = hashes[i]; ++ expected_salt_len = salt_lens[i]; ++ } ++ } ++ } ++ ++ if (expected_hash != pss_params->hashAlg) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* We're strict, and only do PSS signatures with a salt length that ++ * matches the digest length (any shorter is rubbish, any longer ++ * is useless). */ ++ if (pss_params->sLen != expected_salt_len / 8) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* TODO support different salt lengths */ ++ break; ++ } ++ return CKR_OK; ++} ++ ++ + struct sc_pkcs11_object_ops pkcs15_prkey_ops = { + pkcs15_prkey_release, + pkcs15_prkey_set_attribute, +@@ -4084,8 +4185,9 @@ struct sc_pkcs11_object_ops pkcs15_prkey_ops = { + pkcs15_prkey_sign, + NULL, /* unwrap */ + pkcs15_prkey_decrypt, +- pkcs15_prkey_derive, +- pkcs15_prkey_can_do ++ pkcs15_prkey_derive, ++ pkcs15_prkey_can_do, ++ pkcs15_prkey_init_params, + }; + + /* +@@ -4322,7 +4424,8 @@ struct sc_pkcs11_object_ops pkcs15_pubkey_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + +@@ -4500,7 +4603,8 @@ struct sc_pkcs11_object_ops pkcs15_dobj_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + +@@ -4629,7 +4733,8 @@ struct sc_pkcs11_object_ops pkcs15_skey_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + /* +@@ -5040,6 +5145,17 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + /* We support PKCS1 padding in software */ + /* either the card supports it or OpenSC does */ + rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; ++#ifdef ENABLE_OPENSSL ++ rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS; ++#endif ++ } ++ ++ if (rsa_flags & SC_ALGORITHM_RSA_PAD_ISO9796) { ++ /* Supported in hardware only, if the card driver declares it. */ ++ mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_9796, &mech_info, CKK_RSA, NULL, NULL); ++ rc = sc_pkcs11_register_mechanism(p11card, mt); ++ if (rc != CKR_OK) ++ return rc; + } + + #ifdef ENABLE_OPENSSL +@@ -5098,23 +5214,40 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + #endif /* ENABLE_OPENSSL */ + } + +- /* TODO support other padding mechanisms */ +- + if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) { +- mech_info.flags &= ~(CKF_DECRYPT|CKF_VERIFY); +- ++ mech_info.flags &= ~(CKF_DECRYPT|CKF_ENCRYPT); + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL); + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA224_RSA_PKCS_PSS, CKM_SHA224, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA384_RSA_PKCS_PSS, CKM_SHA384, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA512_RSA_PKCS_PSS, CKM_SHA512, mt); + if (rc != CKR_OK) + return rc; + } +diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c +index 5f006c839..d4ce7fef5 100644 +--- a/src/pkcs11/mechanism.c ++++ b/src/pkcs11/mechanism.c +@@ -262,11 +262,20 @@ sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechani + if (mt->key_type != key_type) + LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT); + ++ if (pMechanism->pParameter && ++ pMechanism->ulParameterLen > sizeof(operation->mechanism_params)) ++ LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); ++ + rv = session_start_operation(session, SC_PKCS11_OPERATION_SIGN, mt, &operation); + if (rv != CKR_OK) + LOG_FUNC_RETURN(context, rv); + + memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM)); ++ if (pMechanism->pParameter) { ++ memcpy(&operation->mechanism_params, pMechanism->pParameter, ++ pMechanism->ulParameterLen); ++ operation->mechanism.pParameter = &operation->mechanism_params; ++ } + rv = mt->sign_init(operation, key); + if (rv != CKR_OK) + session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); +@@ -387,6 +396,16 @@ sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation, + } + } + ++ /* Validate the mechanism parameters */ ++ if (key->ops->init_params) { ++ rv = key->ops->init_params(operation->session, &operation->mechanism); ++ if (rv != CKR_OK) { ++ /* Probably bad arguments */ ++ free(data); ++ LOG_FUNC_RETURN(context, rv); ++ } ++ } ++ + /* If this is a signature with hash operation, + * and card cannot perform itself signature with hash operation, + * set up the hash operation */ +@@ -636,6 +655,16 @@ sc_pkcs11_verify_init(sc_pkcs11_operation_t *operation, + } + } + ++ /* Validate the mechanism parameters */ ++ if (key->ops->init_params) { ++ rv = key->ops->init_params(operation->session, &operation->mechanism); ++ if (rv != CKR_OK) { ++ /* Probably bad arguments */ ++ free(data); ++ LOG_FUNC_RETURN(context, rv); ++ } ++ } ++ + /* If this is a verify with hash operation, set up the + * hash operation */ + info = (struct hash_signature_info *) operation->type->mech_data; +@@ -729,7 +758,7 @@ sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation, + + rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen, + params, sizeof(params), +- operation->mechanism.mechanism, data->md, ++ &operation->mechanism, data->md, + data->buffer, data->buffer_len, pSignature, ulSignatureLen); + + done: +diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c +index 59de1210d..e8b246145 100644 +--- a/src/pkcs11/openssl.c ++++ b/src/pkcs11/openssl.c +@@ -68,6 +68,23 @@ static sc_pkcs11_mechanism_type_t openssl_sha1_mech = { + NULL, /* free_mech_data */ + }; + ++static sc_pkcs11_mechanism_type_t openssl_sha224_mech = { ++ CKM_SHA224, ++ { 0, 0, CKF_DIGEST }, ++ 0, ++ sizeof(struct sc_pkcs11_operation), ++ sc_pkcs11_openssl_md_release, ++ sc_pkcs11_openssl_md_init, ++ sc_pkcs11_openssl_md_update, ++ sc_pkcs11_openssl_md_final, ++ NULL, NULL, NULL, NULL, /* sign_* */ ++ NULL, NULL, NULL, /* verif_* */ ++ NULL, NULL, /* decrypt_* */ ++ NULL, /* derive */ ++ NULL, /* mech_data */ ++ NULL, /* free_mech_data */ ++}; ++ + #if OPENSSL_VERSION_NUMBER >= 0x00908000L + static sc_pkcs11_mechanism_type_t openssl_sha256_mech = { + CKM_SHA256, +@@ -231,6 +248,8 @@ sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *p11card) + + openssl_sha1_mech.mech_data = EVP_sha1(); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha1_mech, sizeof openssl_sha1_mech)); ++ openssl_sha224_mech.mech_data = EVP_sha224(); ++ sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha224_mech, sizeof openssl_sha224_mech)); + #if OPENSSL_VERSION_NUMBER >= 0x00908000L + openssl_sha256_mech.mech_data = EVP_sha256(); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech)); +@@ -396,7 +415,7 @@ static CK_RV gostr3410_verify_data(const unsigned char *pubkey, int pubkey_len, + */ + CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, +- CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, ++ CK_MECHANISM_PTR mech, sc_pkcs11_operation_t *md, + unsigned char *data, int data_len, + unsigned char *signat, int signat_len) + { +@@ -405,7 +424,7 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + EVP_PKEY *pkey = NULL; + const unsigned char *pubkey_tmp = NULL; + +- if (mech == CKM_GOSTR3410) ++ if (mech->mechanism == CKM_GOSTR3410) + { + #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) + return gostr3410_verify_data(pubkey, pubkey_len, +@@ -429,37 +448,53 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + if (pkey == NULL) + return CKR_GENERAL_ERROR; + +- if (md != NULL) { ++ if (md != NULL && (mech->mechanism == CKM_SHA1_RSA_PKCS ++ || mech->mechanism == CKM_SHA224_RSA_PKCS ++ || mech->mechanism == CKM_SHA256_RSA_PKCS ++ || mech->mechanism == CKM_SHA384_RSA_PKCS ++ || mech->mechanism == CKM_SHA512_RSA_PKCS)) { + EVP_MD_CTX *md_ctx = DIGEST_CTX(md); + ++ /* This does not really use the data argument, but the data ++ * are already collected in the md_ctx ++ */ ++ sc_log(context, "Trying to verify using EVP"); + res = EVP_VerifyFinal(md_ctx, signat, signat_len, pkey); + EVP_PKEY_free(pkey); + if (res == 1) + return CKR_OK; +- else if (res == 0) ++ else if (res == 0) { ++ sc_log(context, "EVP_VerifyFinal(): Signature invalid"); + return CKR_SIGNATURE_INVALID; +- else { ++ } else { + sc_log(context, "EVP_VerifyFinal() returned %d\n", res); + return CKR_GENERAL_ERROR; + } +- } +- else { ++ } else { + RSA *rsa; + unsigned char *rsa_out = NULL, pad; + int rsa_outlen = 0; + +- switch(mech) { ++ sc_log(context, "Trying to verify using low-level API"); ++ switch (mech->mechanism) { + case CKM_RSA_PKCS: + pad = RSA_PKCS1_PADDING; + break; +- case CKM_RSA_X_509: +- pad = RSA_NO_PADDING; +- break; +- /* TODO support more then RSA */ +- default: ++ case CKM_RSA_X_509: ++ pad = RSA_NO_PADDING; ++ break; ++ case CKM_RSA_PKCS_PSS: ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: ++ case CKM_SHA256_RSA_PKCS_PSS: ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ pad = RSA_NO_PADDING; ++ break; ++ default: + EVP_PKEY_free(pkey); +- return CKR_ARGUMENTS_BAD; +- } ++ return CKR_ARGUMENTS_BAD; ++ } + + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); +@@ -473,13 +508,95 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + } + + rsa_outlen = RSA_public_decrypt(signat_len, signat, rsa_out, rsa, pad); +- RSA_free(rsa); +- if(rsa_outlen <= 0) { ++ if (rsa_outlen <= 0) { + free(rsa_out); + sc_log(context, "RSA_public_decrypt() returned %d\n", rsa_outlen); + return CKR_GENERAL_ERROR; + } + ++ /* For PSS mechanisms we can not simply compare the "decrypted" ++ * data -- we need to verify the PSS padding is valid ++ */ ++ if (mech->mechanism == CKM_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA1_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA224_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA256_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA384_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA512_RSA_PKCS_PSS) { ++ CK_RSA_PKCS_PSS_PARAMS* param = NULL; ++ const EVP_MD *mgf_md, *pss_md; ++ unsigned char digest[EVP_MAX_MD_SIZE]; ++ ++ if (mech->pParameter == NULL) { ++ sc_log(context, "PSS mechanism requires parameter"); ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ param = (CK_RSA_PKCS_PSS_PARAMS*)mech->pParameter; ++ switch (param->mgf) { ++ case CKG_MGF1_SHA1: ++ mgf_md = EVP_sha1(); ++ break; ++ case CKG_MGF1_SHA224: ++ mgf_md = EVP_sha224(); ++ break; ++ case CKG_MGF1_SHA256: ++ mgf_md = EVP_sha256(); ++ break; ++ case CKG_MGF1_SHA384: ++ mgf_md = EVP_sha384(); ++ break; ++ case CKG_MGF1_SHA512: ++ mgf_md = EVP_sha512(); ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ switch (param->hashAlg) { ++ case CKM_SHA_1: ++ pss_md = EVP_sha1(); ++ break; ++ case CKM_SHA224: ++ pss_md = EVP_sha224(); ++ break; ++ case CKM_SHA256: ++ pss_md = EVP_sha256(); ++ break; ++ case CKM_SHA384: ++ pss_md = EVP_sha384(); ++ break; ++ case CKM_SHA512: ++ pss_md = EVP_sha512(); ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ /* for the mechanisms with hash algorithm, the data ++ * is already added to the hash buffer, so we need ++ * to finish the hash operation here ++ */ ++ if (mech->mechanism != CKM_RSA_PKCS_PSS) { ++ EVP_MD_CTX *md_ctx = DIGEST_CTX(md); ++ unsigned char *tmp = digest; ++ unsigned int tmp_len; ++ ++ EVP_DigestFinal(md_ctx, tmp, &tmp_len); ++ data = tmp; ++ data_len = tmp_len; ++ } ++ rv = CKR_SIGNATURE_INVALID; ++ if (data_len == EVP_MD_size(pss_md) && ++ RSA_verify_PKCS1_PSS_mgf1(rsa, data, pss_md, mgf_md, ++ rsa_out, EVP_MD_size(pss_md)/*sLen*/) == 1) ++ rv = CKR_OK; ++ RSA_free(rsa); ++ sc_log(context, "Returning %lu", rv); ++ return rv; ++ } ++ RSA_free(rsa); ++ + if (rsa_outlen == data_len && memcmp(rsa_out, data, data_len) == 0) + rv = CKR_OK; + else +diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h +index 61a5050df..8219b961b 100644 +--- a/src/pkcs11/pkcs11.h ++++ b/src/pkcs11/pkcs11.h +@@ -480,8 +480,6 @@ struct ck_date + + typedef unsigned long ck_mechanism_type_t; + +-typedef unsigned long int ck_rsa_pkcs_mgf_type_t; +- + #define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) + #define CKM_RSA_PKCS (1UL) + #define CKM_RSA_9796 (2UL) +@@ -764,6 +762,7 @@ typedef struct CK_ECDH1_DERIVE_PARAMS { + unsigned char * pPublicData; + } CK_ECDH1_DERIVE_PARAMS; + ++typedef unsigned long ck_rsa_pkcs_mgf_type_t; + typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE; + + typedef struct CK_RSA_PKCS_OAEP_PARAMS { +diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h +index 843245882..f0115ed04 100644 +--- a/src/pkcs11/sc-pkcs11.h ++++ b/src/pkcs11/sc-pkcs11.h +@@ -119,6 +119,9 @@ struct sc_pkcs11_object_ops { + /* Check compatibility of PKCS#15 object usage and an asked PKCS#11 mechanism. */ + CK_RV (*can_do)(struct sc_pkcs11_session *, void *, CK_MECHANISM_TYPE, unsigned int); + ++ /* General validation of mechanism parameters (sign, encrypt, etc) */ ++ CK_RV (*init_params)(struct sc_pkcs11_session *, CK_MECHANISM_PTR); ++ + /* Others to be added when implemented */ + }; + +@@ -290,6 +293,10 @@ typedef struct sc_pkcs11_mechanism_type sc_pkcs11_mechanism_type_t; + struct sc_pkcs11_operation { + sc_pkcs11_mechanism_type_t *type; + CK_MECHANISM mechanism; ++ union { ++ CK_RSA_PKCS_PSS_PARAMS pss; ++ CK_RSA_PKCS_OAEP_PARAMS oaep; ++ } mechanism_params; + struct sc_pkcs11_session *session; + void * priv_data; + }; +@@ -434,7 +441,7 @@ CK_RV sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *, + #ifdef ENABLE_OPENSSL + CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, +- CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, ++ CK_MECHANISM_PTR mech, sc_pkcs11_operation_t *md, + unsigned char *inp, int inp_len, + unsigned char *signat, int signat_len); + #endif + +From 2f36612d116ed1fb3ed305a5657871fa12f75011 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Sun, 22 Jul 2018 16:29:19 +0200 +Subject: [PATCH 4/5] pkcs11-tool: Support for signature verification + +Signed-off-by: Jakub Jelen +--- + doc/tools/pkcs11-tool.1.xml | 14 ++ + src/tools/pkcs11-tool.c | 273 +++++++++++++++++++++++++++--------- + 2 files changed, 222 insertions(+), 65 deletions(-) + +diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml +index c609ec0e2..fd823c06e 100644 +--- a/doc/tools/pkcs11-tool.1.xml ++++ b/doc/tools/pkcs11-tool.1.xml +@@ -481,6 +481,13 @@ + non-zero number. + + ++ ++ ++ , ++ ++ Verify signature of some data. ++ ++ + + + , +@@ -530,6 +537,13 @@ + cert/privkey/pubkey). + + ++ ++ ++ filename ++ ++ The path to the signature file for signature verification ++ ++ + + + format +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index 64525f6ad..e3c52e2f8 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -150,6 +150,8 @@ enum { + OPT_HASH_ALGORITHM, + OPT_MGF, + OPT_SALT, ++ OPT_VERIFY, ++ OPT_SIGNATURE_FILE, + }; + + static const struct option options[] = { +@@ -161,6 +163,7 @@ static const struct option options[] = { + { "list-objects", 0, NULL, 'O' }, + + { "sign", 0, NULL, 's' }, ++ { "verify", 0, NULL, OPT_VERIFY }, + { "decrypt", 0, NULL, OPT_DECRYPT }, + { "hash", 0, NULL, 'h' }, + { "derive", 0, NULL, OPT_DERIVE }, +@@ -203,6 +206,7 @@ static const struct option options[] = { + { "set-id", 1, NULL, 'e' }, + { "attr-from", 1, NULL, OPT_ATTR_FROM }, + { "input-file", 1, NULL, 'i' }, ++ { "signature-file", 1, NULL, OPT_SIGNATURE_FILE }, + { "output-file", 1, NULL, 'o' }, + { "signature-format", 1, NULL, 'f' }, + +@@ -230,6 +234,7 @@ static const char *option_help[] = { + "Show objects on token", + + "Sign some data", ++ "Verify a signature of some data", + "Decrypt some data", + "Hash some data", + "Derive a secret key using another key and some data", +@@ -272,6 +277,7 @@ static const char *option_help[] = { + "Set the CKA_ID of an object, = the (new) CKA_ID", + "Use to create some attributes when writing an object", + "Specify the input file", ++ "Specify the file with signature for verification", + "Specify the output file", + "Format for ECDSA signature : 'rs' (default), 'sequence', 'openssl'", + +@@ -293,6 +299,7 @@ static const char * app_name = "pkcs11-tool"; /* for utils.c */ + static int verbose = 0; + static const char * opt_input = NULL; + static const char * opt_output = NULL; ++static const char * opt_signature_file = NULL; + static const char * opt_module = DEFAULT_PKCS11_PROVIDER; + static int opt_slot_set = 0; + static CK_SLOT_ID opt_slot = 0; +@@ -331,8 +338,8 @@ static int opt_derive_pass_der = 0; + static unsigned long opt_random_bytes = 0; + static CK_MECHANISM_TYPE opt_hash_alg = 0; + static unsigned long opt_mgf = 0; +-static long salt_len = 0; +-static int salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */ ++static long opt_salt_len = 0; ++static int opt_salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */ + + static void *module = NULL; + static CK_FUNCTION_LIST_PTR p11 = NULL; +@@ -396,6 +403,7 @@ static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); + static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); ++static void verify_signature(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void hash_data(CK_SLOT_ID, CK_SESSION_HANDLE); + static void derive_key(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); +@@ -532,6 +540,7 @@ int main(int argc, char * argv[]) + int do_list_mechs = 0; + int do_list_objects = 0; + int do_sign = 0; ++ int do_verify = 0; + int do_decrypt = 0; + int do_hash = 0; + int do_derive = 0; +@@ -685,6 +694,9 @@ int main(int argc, char * argv[]) + case 'i': + opt_input = optarg; + break; ++ case OPT_SIGNATURE_FILE: ++ opt_signature_file = optarg; ++ break; + case 'l': + need_session |= NEED_SESSION_RW; + opt_login = 1; +@@ -700,8 +712,8 @@ int main(int argc, char * argv[]) + opt_mgf = p11_name_to_mgf(optarg); + break; + case OPT_SALT: +- salt_len = (CK_ULONG) strtoul(optarg, NULL, 0); +- salt_len_given = 1; ++ opt_salt_len = (CK_ULONG) strtoul(optarg, NULL, 0); ++ opt_salt_len_given = 1; + break; + case 'o': + opt_output = optarg; +@@ -726,6 +738,11 @@ int main(int argc, char * argv[]) + do_sign = 1; + action_count++; + break; ++ case OPT_VERIFY: ++ need_session |= NEED_SESSION_RO; ++ do_verify = 1; ++ action_count++; ++ break; + case OPT_DECRYPT: + need_session |= NEED_SESSION_RW; + do_decrypt = 1; +@@ -1037,6 +1054,16 @@ int main(int argc, char * argv[]) + util_fatal("Private key not found"); + } + ++ if (do_verify) { ++ if (!find_object(session, CKO_PUBLIC_KEY, &object, ++ opt_object_id_len ? opt_object_id : NULL, ++ opt_object_id_len, 0) && ++ !find_object(session, CKO_CERTIFICATE, &object, ++ opt_object_id_len ? opt_object_id : NULL, ++ opt_object_id_len, 0)) ++ util_fatal("Public key nor certificate not found"); ++ } ++ + /* before list objects, so we can see a derived key */ + if (do_derive) + derive_key(opt_slot, session, object); +@@ -1047,6 +1074,9 @@ int main(int argc, char * argv[]) + if (do_sign) + sign_data(opt_slot, session, object); + ++ if (do_verify) ++ verify_signature(opt_slot, session, object); ++ + if (do_decrypt) + decrypt_data(opt_slot, session, object); + +@@ -1636,7 +1666,7 @@ static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type) + } + + /* return digest length in bytes */ +-static unsigned long figure_pss_salt_length(const int hash) { ++static unsigned long hash_length(const int hash) { + unsigned long sLen = 0; + switch (hash) { + case CKM_SHA_1: +@@ -1662,26 +1692,16 @@ static unsigned long figure_pss_salt_length(const int hash) { + return sLen; + } + +-static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, +- CK_OBJECT_HANDLE key) ++static unsigned long ++parse_pss_params(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, ++ CK_MECHANISM *mech, CK_RSA_PKCS_PSS_PARAMS *pss_params) + { +- unsigned char in_buffer[1025], sig_buffer[512]; +- CK_MECHANISM mech; +- CK_RSA_PKCS_PSS_PARAMS pss_params; +- CK_RV rv; +- CK_ULONG sig_len; +- int fd, r; ++ unsigned long hashlen = 0; + +- unsigned long hashlen = 0, modlen = 0; +- +- if (!opt_mechanism_used) +- if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism)) +- util_fatal("Sign mechanism not supported"); ++ if (pss_params == NULL) ++ return 0; + +- fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); +- memset(&mech, 0, sizeof(mech)); +- mech.mechanism = opt_mechanism; +- pss_params.hashAlg = 0; ++ pss_params->hashAlg = 0; + + if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_PSS) + util_fatal("The hash-algorithm is applicable only to " +@@ -1690,93 +1710,118 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + /* set "default" MGF and hash algorithms. We can overwrite MGF later */ + switch (opt_mechanism) { + case CKM_RSA_PKCS_PSS: +- pss_params.hashAlg = opt_hash_alg; ++ pss_params->hashAlg = opt_hash_alg; + + switch (opt_hash_alg) { + case CKM_SHA224: +- pss_params.mgf = CKG_MGF1_SHA224; ++ pss_params->mgf = CKG_MGF1_SHA224; + break; + case CKM_SHA256: +- pss_params.mgf = CKG_MGF1_SHA256; ++ pss_params->mgf = CKG_MGF1_SHA256; + break; + case CKM_SHA384: +- pss_params.mgf = CKG_MGF1_SHA384; ++ pss_params->mgf = CKG_MGF1_SHA384; + break; + case CKM_SHA512: +- pss_params.mgf = CKG_MGF1_SHA512; ++ pss_params->mgf = CKG_MGF1_SHA512; + break; + default: + /* the PSS should use SHA-1 if not specified */ +- pss_params.hashAlg = CKM_SHA_1; ++ pss_params->hashAlg = CKM_SHA_1; + /* fallthrough */ + case CKM_SHA_1: +- pss_params.mgf = CKG_MGF1_SHA1; ++ pss_params->mgf = CKG_MGF1_SHA1; + } + break; + + case CKM_SHA1_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA_1; +- pss_params.mgf = CKG_MGF1_SHA1; ++ pss_params->hashAlg = CKM_SHA_1; ++ pss_params->mgf = CKG_MGF1_SHA1; + break; + + case CKM_SHA224_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA224; +- pss_params.mgf = CKG_MGF1_SHA224; ++ pss_params->hashAlg = CKM_SHA224; ++ pss_params->mgf = CKG_MGF1_SHA224; + break; + + case CKM_SHA256_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA256; +- pss_params.mgf = CKG_MGF1_SHA256; ++ pss_params->hashAlg = CKM_SHA256; ++ pss_params->mgf = CKG_MGF1_SHA256; + break; + + case CKM_SHA384_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA384; +- pss_params.mgf = CKG_MGF1_SHA384; ++ pss_params->hashAlg = CKM_SHA384; ++ pss_params->mgf = CKG_MGF1_SHA384; + break; + + case CKM_SHA512_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA512; +- pss_params.mgf = CKG_MGF1_SHA512; ++ pss_params->hashAlg = CKM_SHA512; ++ pss_params->mgf = CKG_MGF1_SHA512; + break; + } + + /* One of RSA-PSS mechanisms above: They need parameters */ +- if (pss_params.hashAlg) { ++ if (pss_params->hashAlg) { + if (opt_mgf != 0) +- pss_params.mgf = opt_mgf; ++ pss_params->mgf = opt_mgf; + +- hashlen = figure_pss_salt_length(pss_params.hashAlg); ++ hashlen = hash_length(pss_params->hashAlg); + +- if (salt_len_given == 1) { /* salt size explicitly given */ +- if (salt_len < 0 && salt_len != -1 && salt_len != -2) +- util_fatal("Salt length must be greater or equal \ +-to zero, or equal to -1 (meaning: use digest size) or to -2 \ +-(meaning: use maximum permissible size"); ++ if (opt_salt_len_given == 1) { /* salt size explicitly given */ ++ unsigned long modlen = 0; ++ if (opt_salt_len < 0 && opt_salt_len != -1 && opt_salt_len != -2) ++ util_fatal("Salt length must be greater or equal " ++ "to zero, or equal to -1 (meaning: use digest size) " ++ "or to -2 (meaning: use maximum permissible size"); + + modlen = (get_private_key_length(session, key) + 7) / 8; +- switch(salt_len) { ++ switch (opt_salt_len) { + case -1: /* salt size equals to digest size */ +- pss_params.sLen = hashlen; ++ pss_params->sLen = hashlen; + break; + case -2: /* maximum permissible salt len */ +- pss_params.sLen = modlen - hashlen -2; ++ pss_params->sLen = modlen - hashlen -2; + break; + default: /* use given size but its value must be >= 0 */ +- pss_params.sLen = salt_len; ++ pss_params->sLen = opt_salt_len; + break; +- } /* end switch (salt_len_given) */ ++ } /* end switch (opt_salt_len_given) */ + } else { /* use default: salt len of digest size */ +- pss_params.sLen = hashlen; ++ pss_params->sLen = hashlen; + } + +- mech.pParameter = &pss_params; +- mech.ulParameterLen = sizeof(pss_params); ++ mech->pParameter = pss_params; ++ mech->ulParameterLen = sizeof(*pss_params); + + fprintf(stderr, "PSS parameters: hashAlg=%s, mgf=%s, salt_len=%lu B\n", +- p11_mechanism_to_name(pss_params.hashAlg), +- p11_mgf_to_name(pss_params.mgf), +- pss_params.sLen); ++ p11_mechanism_to_name(pss_params->hashAlg), ++ p11_mgf_to_name(pss_params->mgf), ++ pss_params->sLen); + } ++ return hashlen; ++} ++ ++static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, ++ CK_OBJECT_HANDLE key) ++{ ++ unsigned char in_buffer[1025], sig_buffer[512]; ++ CK_MECHANISM mech; ++ CK_RSA_PKCS_PSS_PARAMS pss_params; ++ CK_RV rv; ++ CK_ULONG sig_len; ++ int fd, r; ++ unsigned long hashlen; ++ ++ if (!opt_mechanism_used) ++ if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism)) ++ util_fatal("Sign mechanism not supported"); ++ ++ fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); ++ memset(&mech, 0, sizeof(mech)); ++ mech.mechanism = opt_mechanism; ++ hashlen = parse_pss_params(session, key, &mech, &pss_params); ++ if (hashlen == 0) ++ util_fatal("Invalid RSA-PSS parameters"); + + if (opt_input == NULL) + fd = 0; +@@ -1787,12 +1832,15 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes) must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS) { ++ if ((unsigned long)r != hashlen) ++ util_fatal("For %s mechanism, message size (got %d bytes) " ++ "must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ } + + rv = CKR_CANCEL; +- if (r < (int) sizeof(in_buffer)) { ++ if (r < (int) sizeof(in_buffer)) { + rv = p11->C_SignInit(session, &mech, key); + if (rv != CKR_OK) + p11_fatal("C_SignInit", rv); +@@ -1833,12 +1881,16 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + util_fatal("failed to open %s: %m", opt_output); + } + +- if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 || opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 || opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) { +- if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { ++ if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 || ++ opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 || ++ opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) { ++ if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || ++ !strcmp(opt_sig_format, "sequence"))) { + unsigned char *seq; + size_t seqlen; + +- if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, sig_len, &seq, &seqlen)) { ++ if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, ++ sig_len, &seq, &seqlen)) { + util_fatal("Failed to convert signature to ASN.1 sequence format"); + } + +@@ -1856,6 +1908,97 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + close(fd); + } + ++static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, ++ CK_OBJECT_HANDLE key) ++{ ++ unsigned char in_buffer[1025], sig_buffer[512]; ++ CK_MECHANISM mech; ++ CK_RSA_PKCS_PSS_PARAMS pss_params; ++ CK_RV rv; ++ CK_ULONG sig_len; ++ int fd, fd2, r, r2; ++ unsigned long hashlen; ++ ++ if (!opt_mechanism_used) ++ if (!find_mechanism(slot, CKF_VERIFY|CKF_HW, NULL, 0, &opt_mechanism)) ++ util_fatal("Mechanism not supported for signature verification"); ++ ++ fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); ++ memset(&mech, 0, sizeof(mech)); ++ mech.mechanism = opt_mechanism; ++ hashlen = parse_pss_params(session, key, &mech, &pss_params); ++ if (hashlen == 0) ++ util_fatal("Invalid RSA-PSS parameters"); ++ ++ /* Open a signature file */ ++ if (opt_signature_file == NULL) ++ util_fatal("No file with signature provided. Use --signature-file"); ++ else if ((fd2 = open(opt_signature_file, O_RDONLY|O_BINARY)) < 0) ++ util_fatal("Cannot open %s: %m", opt_signature_file); ++ ++ r2 = read(fd2, sig_buffer, sizeof(sig_buffer)); ++ if (r2 < 0) ++ util_fatal("Cannot read from %s: %m", opt_signature_file); ++ ++ close(fd2); ++ ++ /* Open the data file */ ++ if (opt_input == NULL) ++ fd = 0; ++ else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0) ++ util_fatal("Cannot open %s: %m", opt_input); ++ ++ r = read(fd, in_buffer, sizeof(in_buffer)); ++ if (r < 0) ++ util_fatal("Cannot read from %s: %m", opt_input); ++ ++ if (opt_mechanism == CKM_RSA_PKCS_PSS) { ++ if ((unsigned long)r != hashlen) ++ util_fatal("For %s mechanism, message size (got %d bytes)" ++ " must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ } ++ ++ rv = CKR_CANCEL; ++ if (r < (int) sizeof(in_buffer)) { ++ rv = p11->C_VerifyInit(session, &mech, key); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyInit", rv); ++ ++ sig_len = r2; ++ rv = p11->C_Verify(session, in_buffer, r, sig_buffer, sig_len); ++ } ++ ++ if (rv != CKR_OK) { ++ rv = p11->C_VerifyInit(session, &mech, key); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyInit", rv); ++ ++ do { ++ rv = p11->C_VerifyUpdate(session, in_buffer, r); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyUpdate", rv); ++ ++ r = read(fd, in_buffer, sizeof(in_buffer)); ++ } while (r > 0); ++ ++ sig_len = sizeof(sig_buffer); ++ rv = p11->C_VerifyFinal(session, sig_buffer, sig_len); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyFinal", rv); ++ } ++ ++ if (fd != 0) ++ close(fd); ++ ++ if (rv == CKR_OK) ++ printf("Signature is valid\n"); ++ else if (rv == CKR_SIGNATURE_INVALID) ++ printf("Invalid signature\n"); ++ else ++ printf("Cryptoki returned erorr: %s\n", CKR2Str(rv)); ++} ++ + + static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE key) + +From 256502bed97d56a6813c0b4a7d4c64ee1ff0606e Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 14 Sep 2018 17:27:11 +0200 +Subject: [PATCH 5/5] slot: Switch cleanup steps to avoid segfaults on errors + +and some more sanity checking + +Signed-off-by: Jakub Jelen +--- + src/pkcs11/framework-pkcs15.c | 2 +- + src/pkcs11/slot.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index a75d239f4..85e12df66 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -365,7 +365,7 @@ pkcs15_unbind(struct sc_pkcs11_card *p11card) + + unlock_card(fw_data); + +- if (fw_data->p15_card) { ++ if (fw_data->p15_card && fw_data->p15_card->card) { + if (idx == 0) { + int rc = sc_detect_card_presence(fw_data->p15_card->card->reader); + if (rc <= 0 || rc & SC_READER_CARD_CHANGED) { +diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c +index fe322e68e..3102bf986 100644 +--- a/src/pkcs11/slot.c ++++ b/src/pkcs11/slot.c +@@ -374,10 +374,10 @@ CK_RV card_detect(sc_reader_t *reader) + + fail: + if (free_p11card) { +- if (p11card->card != NULL) +- sc_disconnect_card(p11card->card); + if (p11card->framework) + p11card->framework->unbind(p11card); ++ if (p11card->card != NULL) ++ sc_disconnect_card(p11card->card); + free(p11card); + } + + +From 2fd8e278f5d3664555cad706d7270229c87cae56 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Wed, 17 Oct 2018 16:07:20 -0500 +Subject: [PATCH] pkcs11/openssl.c - add missing mechanisms fixes #1497 + + On branch pkcs11-openssl-c + Changes to be committed: + modified: ../pkcs11/openssl.c +--- + src/pkcs11/openssl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c +index 00b9814e4..fb9f8fea8 100644 +--- a/src/pkcs11/openssl.c ++++ b/src/pkcs11/openssl.c +@@ -449,6 +449,8 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + return CKR_GENERAL_ERROR; + + if (md != NULL && (mech->mechanism == CKM_SHA1_RSA_PKCS ++ || mech->mechanism == CKM_MD5_RSA_PKCS ++ || mech->mechanism == CKM_RIPEMD160_RSA_PKCS + || mech->mechanism == CKM_SHA224_RSA_PKCS + || mech->mechanism == CKM_SHA256_RSA_PKCS + || mech->mechanism == CKM_SHA384_RSA_PKCS +@@ -478,6 +480,8 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + sc_log(context, "Trying to verify using low-level API"); + switch (mech->mechanism) { + case CKM_RSA_PKCS: ++ case CKM_MD5_RSA_PKCS: ++ case CKM_RIPEMD160_RSA_PKCS: + pad = RSA_PKCS1_PADDING; + break; + case CKM_RSA_X_509: + + +From 9b289e074bff22f7e2339b7d3f9428c3233efb71 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 11:46:37 +0100 +Subject: [PATCH 2/7] coolkey: Check return values from list initialization + (coverity) + +>>> CID 324484: Error handling issues (CHECKED_RETURN) +>>> Calling "list_init" without checking return value (as is done elsewhere 8 out of 9 times). +--- + src/libopensc/card-coolkey.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/libopensc/card-coolkey.c b/src/libopensc/card-coolkey.c +index c1c09b662..e320290df 100644 +--- a/src/libopensc/card-coolkey.c ++++ b/src/libopensc/card-coolkey.c +@@ -784,18 +784,25 @@ size_t coolkey_list_meter(const void *el) { + return sizeof(sc_cardctl_coolkey_object_t); + } + ++static void coolkey_free_private_data(coolkey_private_data_t *priv); ++ + static coolkey_private_data_t *coolkey_new_private_data(void) + { + coolkey_private_data_t *priv; ++ + /* allocate priv and zero all the fields */ + priv = calloc(1, sizeof(coolkey_private_data_t)); + if (!priv) + return NULL; ++ + /* set other fields as appropriate */ + priv->key_id = COOLKEY_INVALID_KEY; +- list_init(&priv->objects_list); +- list_attributes_comparator(&priv->objects_list, coolkey_compare_id); +- list_attributes_copy(&priv->objects_list, coolkey_list_meter, 1); ++ if (list_init(&priv->objects_list) != 0 || ++ list_attributes_comparator(&priv->objects_list, coolkey_compare_id) != 0 || ++ list_attributes_copy(&priv->objects_list, coolkey_list_meter, 1) != 0) { ++ coolkey_free_private_data(priv); ++ return NULL; ++ } + + return priv; + } + +From a32fbd0525ea6e21e73b03086e29862481761848 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:02:00 +0100 +Subject: [PATCH 3/7] framework-pkcs15.c: Reformat + + * Reasonable line lengths + * Correct indentation + * Add missing SHA224 mechanism +--- + src/pkcs11/framework-pkcs15.c | 40 +++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 14 deletions(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 85e12df66..3657bcbdd 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -5159,18 +5159,14 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + } + + #ifdef ENABLE_OPENSSL +- /* all our software hashes are in OpenSSL */ +- /* Only if card did not list the hashes, will we +- * help it a little, by adding all the OpenSSL hashes +- * that have PKCS#11 mechanisms. +- */ +- if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { +- rsa_flags |= SC_ALGORITHM_RSA_HASHES; +-#if OPENSSL_VERSION_NUMBER < 0x00908000L +- /* turn off hashes not in openssl 0.9.8 */ +- rsa_flags &= ~(SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512 | SC_ALGORITHM_RSA_HASH_SHA224); +-#endif +- } ++ /* all our software hashes are in OpenSSL */ ++ /* Only if card did not list the hashes, will we ++ * help it a little, by adding all the OpenSSL hashes ++ * that have PKCS#11 mechanisms. ++ */ ++ if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { ++ rsa_flags |= SC_ALGORITHM_RSA_HASHES; ++ } + #endif + + /* No need to Check for PKCS1 We support it in software and turned it on above so always added it */ +@@ -5182,32 +5182,44 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + * Either the card set the hashes or we helped it above */ + + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA224_RSA_PKCS, CKM_SHA224, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS, CKM_SHA256, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA256_RSA_PKCS, CKM_SHA256, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA384_RSA_PKCS, CKM_SHA384, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA384_RSA_PKCS, CKM_SHA384, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA512_RSA_PKCS, CKM_SHA512, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA512_RSA_PKCS, CKM_SHA512, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_MD5) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_MD5_RSA_PKCS, CKM_MD5, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_MD5_RSA_PKCS, CKM_MD5, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt); + if (rc != CKR_OK) + return rc; + } + +From 7461c259c96f086621a35baeb699cf3cdc2968dd Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:03:40 +0100 +Subject: [PATCH 4/7] framework-pkcs15.c: Add PKCS#1 mechanisms also if + SC_ALGORITHM_RSA_HASH_NONE is defined + +--- + src/pkcs11/framework-pkcs15.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 3657bcbdd..cac39b821 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -5164,7 +5164,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + * help it a little, by adding all the OpenSSL hashes + * that have PKCS#11 mechanisms. + */ +- if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { ++ if (!(rsa_flags & (SC_ALGORITHM_RSA_HASHES & ~SC_ALGORITHM_RSA_HASH_NONE))) { + rsa_flags |= SC_ALGORITHM_RSA_HASHES; + } + #endif + +From 56a9dab5c0a3bc91175266296a70aea94cb5747b Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:35:25 +0100 +Subject: [PATCH 5/7] p11test: Do not report incomplete key pairs + +--- + src/tests/p11test/p11test_case_pss_oaep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/tests/p11test/p11test_case_pss_oaep.c b/src/tests/p11test/p11test_case_pss_oaep.c +index d0b8392fd..019471192 100644 +--- a/src/tests/p11test/p11test_case_pss_oaep.c ++++ b/src/tests/p11test/p11test_case_pss_oaep.c +@@ -815,6 +815,10 @@ void pss_oaep_test(void **state) { + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + ++ /* Do not go through incomplete pairs */ ++ if (o->private_handle == CK_INVALID_HANDLE) ++ continue; ++ + /* Do not list non-RSA keys here */ + if (o->type != EVP_PK_RSA) + continue; + +From 21d6d8092c98e572c89853593f3f680d219a06d9 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:39:56 +0100 +Subject: [PATCH 6/7] framework-pkcs15.c: Add SHA224 mechanism for PKCS#1.5 + +--- + src/pkcs11/framework-pkcs15.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index cac39b821..6948e31d4 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -3781,6 +3781,9 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + case CKM_SHA1_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1; + break; ++ case CKM_SHA224_RSA_PKCS: ++ flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA224; ++ break; + case CKM_SHA256_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA256; + break; + +From 7d4fa67efc22bf085863ead342b9fc55513425f1 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 17:50:08 +0100 +Subject: [PATCH 7/7] padding: Fix error checking in RSA-PSS + +--- + src/libopensc/padding.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 75c92b651..f0e2263b8 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -345,7 +345,7 @@ static int sc_pkcs1_add_pss_padding(unsigned int hash, unsigned int mgf1_hash, + if (EVP_DigestInit_ex(ctx, mgf1_md, NULL) != 1 || + EVP_DigestUpdate(ctx, out + dblen, hlen) != 1 || /* H (Z parameter of MGF1) */ + EVP_DigestUpdate(ctx, buf, 4) != 1 || /* C */ +- EVP_DigestFinal_ex(ctx, mask, NULL)) { ++ EVP_DigestFinal_ex(ctx, mask, NULL) != 1) { + goto done; + } + /* this is no longer part of the MGF1, but actually + +From e5d8395a7b8e5d6d1493d893c31fac321f45433a Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 20 Nov 2018 09:29:53 +0100 +Subject: [PATCH] pkcs11-tool: Unbreak signature and verification in + pkcs11-tool + +--- + src/tools/pkcs11-tool.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index df4a0ef3..ff1c00ac 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -1758,6 +1758,9 @@ parse_pss_params(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, + pss_params->hashAlg = CKM_SHA512; + pss_params->mgf = CKG_MGF1_SHA512; + break; ++ ++ default: /* The non-RSA-PSS algorithms do not need any parameters */ ++ return 0; + } + + /* One of RSA-PSS mechanisms above: They need parameters */ +@@ -1820,8 +1823,6 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + memset(&mech, 0, sizeof(mech)); + mech.mechanism = opt_mechanism; + hashlen = parse_pss_params(session, key, &mech, &pss_params); +- if (hashlen == 0) +- util_fatal("Invalid RSA-PSS parameters"); + + if (opt_input == NULL) + fd = 0; +@@ -1832,11 +1833,10 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS) { +- if ((unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes) " +- "must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) { ++ util_fatal("For %s mechanism, message size (got %d bytes) " ++ "must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); + } + + rv = CKR_CANCEL; +@@ -1927,8 +1927,6 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + memset(&mech, 0, sizeof(mech)); + mech.mechanism = opt_mechanism; + hashlen = parse_pss_params(session, key, &mech, &pss_params); +- if (hashlen == 0) +- util_fatal("Invalid RSA-PSS parameters"); + + /* Open a signature file */ + if (opt_signature_file == NULL) +@@ -1952,11 +1950,10 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS) { +- if ((unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes)" +- " must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) { ++ util_fatal("For %s mechanism, message size (got %d bytes)" ++ " must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); + } + + rv = CKR_CANCEL; +-- +2.19.1 + +From d517d8e18d9c7f918e38de7e613e34f6b3d21f09 Mon Sep 17 00:00:00 2001 +From: Luka Logar +Date: Thu, 11 Oct 2018 11:22:15 +0200 +Subject: [PATCH] Fix minidriver padding + +Commit e5707b545e5a2dc33b0ca52a8bf63f36f71b3d85 broke signing using minidriver on Windows. + +More specifically changing #define SC_ALGORITHM_RSA_PAD_NONE from 0x00000000 to 0x00000001 caused a call to sc_pkcs1_encode() to fail as the padding algorithm was not specified anywhere in the CardSignData() implementation. It kind of worked as long as SC_ALGORITHM_RSA_PAD_NONE was 0x00000000, but the above mentioned commit broke this. + +Now padding algorithm has to be explicitly specified, otherwise a call to sc_pkcs1_encode() will fail. +--- + src/libopensc/padding.c | 2 +- + src/minidriver/minidriver.c | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 53a87c352e..934fc67d11 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -412,7 +412,7 @@ int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, + pad_algo = flags & SC_ALGORITHM_RSA_PADS; + sc_log(ctx, "hash algorithm 0x%X, pad algorithm 0x%X", hash_algo, pad_algo); + +- if ((pad_algo == SC_ALGORITHM_RSA_PAD_PKCS1 || !pad_algo) && ++ if ((pad_algo == SC_ALGORITHM_RSA_PAD_PKCS1 || pad_algo == SC_ALGORITHM_RSA_PAD_NONE) && + hash_algo != SC_ALGORITHM_RSA_HASH_NONE) { + i = sc_pkcs1_add_digest_info_prefix(hash_algo, in, in_len, out, &tmp_len); + if (i != SC_SUCCESS) { + +From ba2bcb3fd763a791750506ec30283cca0d1870cd Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 12 Dec 2018 10:55:39 +0100 +Subject: [PATCH 5/7] padding: Resotre the PAD_NONE if nothing else is + specified + +Patch from Doug Engert +--- + src/libopensc/padding.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 047b3bc82c..3456a6265a 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -410,6 +410,8 @@ int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, + + hash_algo = flags & SC_ALGORITHM_RSA_HASHES; + pad_algo = flags & SC_ALGORITHM_RSA_PADS; ++ if (pad_algo == 0) ++ pad_algo = SC_ALGORITHM_RSA_PAD_NONE; + sc_log(ctx, "hash algorithm 0x%X, pad algorithm 0x%X", hash_algo, pad_algo); + + if ((pad_algo == SC_ALGORITHM_RSA_PAD_PKCS1 || pad_algo == SC_ALGORITHM_RSA_PAD_NONE) && + +From 8c535c184f41dff417eb23069fec511f911f8ae6 Mon Sep 17 00:00:00 2001 +From: Frank Morgner +Date: Thu, 4 Oct 2018 15:59:11 +0200 +Subject: [PATCH] removed duplicate code for adding padding + +Fixes padding handling of SC_ALGORITHM_RSA_PAD_NONE introduced with +e5707b545e5a2dc33b0ca52a8bf63f36f71b3d85 +--- + src/libopensc/padding.c | 9 ++- + src/minidriver/minidriver.c | 144 +++++++++++++++--------------------- + 2 files changed, 64 insertions(+), 89 deletions(-) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 934fc67d11..75c92b651a 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -487,18 +487,19 @@ int sc_get_encoding_flags(sc_context_t *ctx, + *pflags = 0; + + } else if ((caps & SC_ALGORITHM_RSA_PAD_PSS) && +- (iflags & SC_ALGORITHM_RSA_PAD_PSS)) { ++ (iflags & SC_ALGORITHM_RSA_PAD_PSS)) { + *sflags |= SC_ALGORITHM_RSA_PAD_PSS; + + } else if (((caps & SC_ALGORITHM_RSA_RAW) && +- (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) +- || iflags & SC_ALGORITHM_RSA_PAD_PSS) { ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) ++ || iflags & SC_ALGORITHM_RSA_PAD_PSS ++ || iflags & SC_ALGORITHM_RSA_PAD_NONE) { + /* Use the card's raw RSA capability on the padded input */ + *sflags = SC_ALGORITHM_RSA_PAD_NONE; + *pflags = iflags; + + } else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && +- (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) { ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) { + /* A corner case - the card can partially do PKCS1, if we prepend the + * DigestInfo bit it will do the rest. */ + *sflags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; + +From b01beec4f82294d59b1cf737d5b74d0c194e98da Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 12 Dec 2018 11:56:31 +0100 +Subject: [PATCH 6/7] padding: Do not set wrong flags if the raw capability is + not available + +Thanks Doug Engert for pointing the issue out +--- + src/libopensc/padding.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 3456a6265a..4a8fc17b9c 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -492,10 +492,10 @@ int sc_get_encoding_flags(sc_context_t *ctx, + (iflags & SC_ALGORITHM_RSA_PAD_PSS)) { + *sflags |= SC_ALGORITHM_RSA_PAD_PSS; + +- } else if (((caps & SC_ALGORITHM_RSA_RAW) && +- (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) +- || iflags & SC_ALGORITHM_RSA_PAD_PSS +- || iflags & SC_ALGORITHM_RSA_PAD_NONE) { ++ } else if ((caps & SC_ALGORITHM_RSA_RAW) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1 ++ || iflags & SC_ALGORITHM_RSA_PAD_PSS ++ || iflags & SC_ALGORITHM_RSA_PAD_NONE)) { + /* Use the card's raw RSA capability on the padded input */ + *sflags = SC_ALGORITHM_RSA_PAD_NONE; + *pflags = iflags; + 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/SPECS/opensc.spec b/SPECS/opensc.spec new file mode 100644 index 0000000..0dec665 --- /dev/null +++ b/SPECS/opensc.spec @@ -0,0 +1,654 @@ +%define opensc_module "OpenSC PKCS #11 Module" +%define nssdb %{_sysconfdir}/pki/nssdb + +Name: opensc +Version: 0.19.0 +Release: 4%{?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 +# https://github.com/OpenSC/OpenSC/pull/1435 +# https://github.com/OpenSC/OpenSC/pull/1521 +# parts of +# https://github.com/OpenSC/OpenSC/pull/1556 +# https://github.com/OpenSC/OpenSC/pull/1503 +# https://github.com/OpenSC/OpenSC/pull/1505 +Patch2: opensc-0.19.0-rsa-pss.patch +# https://github.com/OpenSC/OpenSC/pull/1489 +Patch3: opensc-0.19.0-coverity.patch +# https://github.com/OpenSC/OpenSC/pull/1500 +Patch4: opensc-0.19.0-coolkey-matching.patch +# https://github.com/OpenSC/OpenSC/pull/1502 +Patch5: opensc-0.19.0-cac1.patch +Patch6: opensc-0.19.0-pinpad.patch +# https://github.com/OpenSC/OpenSC/pull/1549 +Patch7: 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 gcc +BuildRequires: desktop-file-utils +BuildRequires: bash-completion +Requires: pcsc-lite-libs%{?_isa} +Requires: pcsc-lite +Obsoletes: mozilla-opensc-signer < 0.12.0 +Obsoletes: opensc-devel < 0.12.0 +Obsoletes: coolkey <= 1.1.0-36 + +%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 +%patch2 -p1 -b .pss +%patch3 -p1 -b .coverity +%patch4 -p1 -b .coolkey-match +%patch5 -p1 -b .cac1 +%patch6 -p1 -b .pinpad +%patch7 -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 +sed -i -e 's/opensc.conf/opensc-%{_arch}.conf/g' src/libopensc/Makefile.in +sed -i -e 's|"/lib /usr/lib\b|"/%{_lib} %{_libdir}|' configure # lib64 rpaths +%configure --disable-static \ + --disable-assert \ + --enable-pcsc \ + --disable-tests \ + --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%{_sysconfdir}/opensc.conf +install -Dpm 644 etc/opensc.conf $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf +install -Dpm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/p11-kit/modules/opensc.module +# use NEWS file timestamp as reference for configuration file +touch -r NEWS $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf + +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 +%if 0%{?rhel} && 0%{?rhel} < 7 +rm -rf %{buildroot}%{_datadir}/bash-completion/ +%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* + +desktop-file-validate %{buildroot}/%{_datadir}/applications/org.opensc.notify.desktop + +%post +/sbin/ldconfig +# Remove our PKCS#11 module from NSS DB, if there is NSS installed, because +# it is already loaded by p11-kit-proxy. Using both of them can cause +# race conditions and hard-to-debug problems +# TODO Remove with F30 or so +if [ -x /usr/bin/modutil ]; then + isThere=`modutil -rawlist -dbdir %{nssdb} | grep %{opensc_module} || echo NO` + if [ ! "$isThere" == "NO" ]; then + modutil -delete %{opensc_module} -dbdir %{nssdb} -force || : + + fi + isThere=`modutil -rawlist -dbdir sql:%{nssdb} | grep %{opensc_module} || echo NO` + if [ ! "$isThere" == "NO" ]; then + modutil -delete %{opensc_module} -dbdir sql:%{nssdb} -force || : + fi +fi + +%postun +/sbin/ldconfig + +%files +%doc COPYING NEWS README* + +%if ! 0%{?rhel} || 0%{?rhel} >= 7 +%{_datadir}/bash-completion/* +%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}/opensc-notify +%{_bindir}/piv-tool +%{_bindir}/pkcs11-tool +%{_bindir}/pkcs15-crypt +%{_bindir}/pkcs15-init +%{_bindir}/pkcs15-tool +%{_bindir}/sc-hsm-tool +%{_bindir}/dnie-tool +%{_bindir}/westcos-tool +%{_bindir}/egk-tool +%{_datadir}/applications/org.opensc.notify.desktop +%{_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/opensc-notify.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/*.5* + + +%changelog +* Wed Dec 12 2018 Jakub Jelen - 0.19.0-4 +- Unbreak the Dual CAC cards in PIV driver (#1651748) +- Fix few more corner cases for handling different types of padding (#1595626) +- Unbreak signature verification in pkcs11-tool (#1651748) + +* Wed Oct 31 2018 Jakub Jelen - 0.19.0-3 +- Unbreak the RSA-PSS mechanisms (#1595626) +- Unbreak the signing using hashed mechanisms in CardOS and others (#1644338) + +* Mon Oct 22 2018 Jakub Jelen - 0.19.0-2 +- Avoid mismatching coolkey cards for muscle ones (#1588722) +- Implement legacy CAC1 driver (#1638052) +- Disable pinpad +- Fixup verification after RSA-PSS implementation + +* Tue Sep 25 2018 Jakub Jelen - 0.19.0-1 +- New upstream release fixing various CVE-2018-16418 - 16421, 16423 - 16427 +- Add support for RSA-PSS signatures + +* Fri Jul 13 2018 Fedora Release Engineering - 0.18.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Jul 12 2018 Jakub Jelen - 0.18.0-3 +- Do not add pkcs11 module to NSS after installation + (NSS is loading p11-kit modules by default) +- Remove pkcs11-switch since there is nothing to switch to + +* Mon May 21 2018 Jakub Jelen - 0.18.0-2 +- Backport a fix for C_WaitForSlotEvent crash (#1579933) + +* Thu May 17 2018 Jakub Jelen - 0.18.0-1 +- New upstream release (#1567503) + +* Wed Apr 04 2018 Jakub Jelen - 0.17.0-10 +- Install the PKCS#11 modules also to the new NSS DB +- Drop the pkcs11-switch as the coolkey is gone + +* Tue Apr 03 2018 Jakub Jelen - 0.17.0-9 +- Improved support for CloudHSM (#1562572) + +* Mon Mar 19 2018 Jakub Jelen - 0.17.0-8 +- Build requires gcc +- Backport a fix for feitian tokens (#1558099) + +* Fri Mar 02 2018 Jakub Jelen - 0.17.0-7 +- Obsolete coolkey +- Do not report bogus errors from pkcs11-switch +- Do not delete nonexisting modules during uninstall (#1526670) + +* Wed Feb 21 2018 Jakub Jelen - 0.17.0-6 +- PIV: Use Cardholder name in the token label +- Avoid infinite loop when reading CAC cards +- Properly parse multi-byte length in SimpleTLV +- Support CAC Alt tokens + +* Thu Feb 08 2018 Fedora Release Engineering - 0.17.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Dec 04 2017 Jakub Jelen - 0.17.0-4 +- Allow functionality of a new Estonia ID cards (#1519751) + +* Thu Aug 03 2017 Fedora Release Engineering - 0.17.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 0.17.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Jul 19 2017 Jakub Jelen - 0.17.0-1 +- New upstream release including support for Coolkey and CAC cards + +* Tue Feb 28 2017 Jakub Jelen - 0.16.0-5.20161016git0362439 +- Add PKCS#11 library to the NSS DB (#1421692) + +* Sat Feb 11 2017 Fedora Release Engineering - 0.16.0-4.20161016git0362439 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Igor Gnatenko - 0.16.0-3.20161016git0362439 +- Rebuild for readline 7.x + +* Mon Oct 31 2016 Jakub Jelen - 0.16.0-2.20161016git0362439 +- Updated to latest git to address openssl 1.1.0 compilation issues (#1388895) +- Do not own /etc/bash_completion.d directory (#1303441) + +* Tue Aug 02 2016 Jakub Jelen - 0.16.0-1 +- New upstream release 0.16.0 (#1306071) + +* Tue Jul 12 2016 Jakub Jelen - 0.15.0-6 +- Add support for 2048 key length (#1350588) +- Explicitly set CKA_PRIVATE to false when writing certificates (#1272127) + +* Thu Feb 04 2016 Fedora Release Engineering - 0.15.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Mon Jan 18 2016 Nikos Mavrogiannopoulos - 0.15.0-4 +- Fix a crash in accessing public key (#1298669) + +* Thu Nov 19 2015 Nikos Mavrogiannopoulos - 0.15.0-3 +- Export PKCS#11 symbols from spy library (#1283306) + +* Tue Aug 4 2015 Nikos Mavrogiannopoulos - 0.15.0-2 +- Updated fix for issue with C_Initialize after fork() (#1218797) + +* Tue Jul 14 2015 Nikos Mavrogiannopoulos - 0.15.0-1 +- Update to 0.15.0 (#1209682) +- Solve issue with C_Initialize after fork() (#1218797) + +* Thu Jun 18 2015 Fedora Release Engineering - 0.14.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Sun Aug 17 2014 Fedora Release Engineering - 0.14.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Tue Jul 01 2014 Nikos Mavrogiannopoulos - 0.14.0-1 +- new upstream version + +* Sat Jun 07 2014 Fedora Release Engineering - 0.13.0-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri Feb 28 2014 Nikos Mavrogiannopoulos - 0.13.0-12 +- Added fix for crash when calling pkcs11-tool with an invalid module (#1071368) +- Added fix for invalid parameters passed to module by pkcs11-tool + when importing a private key (#1071369) +- Configuration file opensc.conf was renamed to opensc-arch.conf to + avoid multi-arch issues. + +* Fri Jan 31 2014 Nikos Mavrogiannopoulos - 0.13.0-11 +- Corrected installation path of opensc.module (#1060053) + +* Mon Jan 06 2014 Nikos Mavrogiannopoulos - 0.13.0-10 +- Applied myeid related patch (#1048576) + +* Thu Jan 02 2014 Nikos Mavrogiannopoulos - 0.13.0-9 +- Applied epass2003 related patch (#981462) + +* Mon Dec 23 2013 Nikos Mavrogiannopoulos - 0.13.0-8 +- Compile using the --enable-sm option (related but does not fix #981462) + +* Wed Dec 18 2013 Nikos Mavrogiannopoulos - 0.13.0-7 +- Ensure that pcsc-lite is depended on (#1029133) + +* Mon Sep 23 2013 Stef Walter - 0.13.0-6 +- Install p11-kit config file to the right place (#999190) + +* Sat Aug 03 2013 Fedora Release Engineering - 0.13.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* 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.