diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am
index 49d122682f..a9f200c959 100644
--- a/src/libopensc/Makefile.am
+++ b/src/libopensc/Makefile.am
@@ -48,14 +48,14 @@ libopensc_la_SOURCES_BASE = \
card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \
card-dnie.c cwa14890.c cwa-dnie.c \
card-isoApplet.c card-masktech.c card-gids.c card-jpki.c \
- card-npa.c card-esteid2018.c \
+ card-npa.c card-esteid2018.c card-idprime.c \
\
pkcs15-openpgp.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-gemsafeGPK.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \
pkcs15-oberthur.c pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
- pkcs15-coolkey.c pkcs15-din-66291.c \
+ pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \
pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \
compression.c p15card-helper.c sm.c \
aux-data.c
@@ -131,14 +131,14 @@ TIDY_FILES = \
card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \
cwa14890.c cwa-dnie.c \
card-isoApplet.c card-masktech.c card-jpki.c \
- card-npa.c card-esteid2018.c \
+ card-npa.c card-esteid2018.c card-idprime.c \
\
pkcs15-openpgp.c \
pkcs15-tcos.c pkcs15-esteid.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c \
pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \
pkcs15-oberthur.c pkcs15-itacns.c pkcs15-sc-hsm.c \
- pkcs15-coolkey.c pkcs15-din-66291.c \
+ pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \
pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \
compression.c p15card-helper.c sm.c \
aux-data.c \
diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak
index 487fbeb4a6..2e3c30c22b 100644
--- a/src/libopensc/Makefile.mak
+++ b/src/libopensc/Makefile.mak
@@ -27,7 +27,7 @@ OBJECTS = \
card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj cwa-dnie.obj cwa14890.obj \
card-sc-hsm.obj card-dnie.obj card-isoApplet.obj pkcs15-coolkey.obj \
card-masktech.obj card-gids.obj card-jpki.obj \
- card-npa.obj card-esteid2018.obj \
+ card-npa.obj card-esteid2018.obj card-idprime.obj \
\
pkcs15-openpgp.obj pkcs15-starcert.obj \
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-gemsafeGPK.obj \
@@ -35,7 +35,7 @@ OBJECTS = \
pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \
pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \
- pkcs15-esteid2018.obj \
+ pkcs15-esteid2018.obj pkcs15-idprime.obj \
compression.obj p15card-helper.obj sm.obj \
aux-data.obj \
$(TOPDIR)\win32\versioninfo.res
diff --git a/src/libopensc/card-cac.c b/src/libopensc/card-cac.c
index d59b4337c8..2c9361df88 100644
--- a/src/libopensc/card-cac.c
+++ b/src/libopensc/card-cac.c
@@ -54,6 +54,7 @@
#endif
#include "iso7816.h"
#include "card-cac-common.h"
+#include "pkcs15.h"
/*
* CAC hardware and APDU constants
diff --git a/src/libopensc/card-cac1.c b/src/libopensc/card-cac1.c
index 08d62b62cc..67035d64e6 100644
--- a/src/libopensc/card-cac1.c
+++ b/src/libopensc/card-cac1.c
@@ -54,6 +54,7 @@
#endif
#include "iso7816.h"
#include "card-cac-common.h"
+#include "pkcs15.h"
/*
* CAC hardware and APDU constants
diff --git a/src/libopensc/card-idprime.c b/src/libopensc/card-idprime.c
new file mode 100644
index 0000000000..7399830afd
--- /dev/null
+++ b/src/libopensc/card-idprime.c
@@ -0,0 +1,803 @@
+/*
+ * card-idprime.c: Support for Gemalto IDPrime smart cards
+ *
+ * Copyright (c) 2019 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen@redhat.com>
+ *
+ * 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 "internal.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef ENABLE_ZLIB
+#include "compression.h"
+#endif
+
+#include "cardctl.h"
+#include "pkcs15.h"
+
+static const struct sc_card_operations *iso_ops = NULL;
+
+static struct sc_card_operations idprime_ops;
+static struct sc_card_driver idprime_drv = {
+ "Gemalto IDPrime",
+ "idprime",
+ &idprime_ops,
+ NULL, 0, NULL
+};
+
+/* This ATR says, there is no EF.DIR nor EF.ATR so ISO discovery mechanisms
+ * are not useful here */
+static const struct sc_atr_table idprime_atrs[] = {
+ { "3b:7f:96:00:00:80:31:80:65:b0:84:41:3d:f6:12:0f:fe:82:90:00",
+ "ff:ff:00:ff:ff:ff:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff",
+ "Gemalto IDPrime MD 8840, 3840, 3810, 840 and 830 Cards",
+ SC_CARD_TYPE_IDPRIME_GENERIC, 0, NULL },
+};
+
+static const sc_path_t idprime_path = {
+ "", 0,
+ 0, 0, SC_PATH_TYPE_DF_NAME,
+ { "\xA0\x00\x00\x00\x18\x80\x00\x00\x00\x06\x62", 11 }
+};
+
+/* data structures to store meta data about IDPrime objects */
+typedef struct idprime_object {
+ int fd;
+ unsigned char key_reference;
+ u8 df[2];
+ unsigned short length;
+} idprime_object_t;
+
+/*
+ * IDPrime private data per card state
+ */
+typedef struct idprime_private_data {
+ 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 */
+ size_t file_size; /* this is real file size since IDPrime is quite strict about lengths */
+ list_t pki_list; /* list of pki containers */
+ idprime_object_t *pki_current; /* current pki object _ctl function */
+ int tinfo_present; /* Token Info Label object is present*/
+ u8 tinfo_df[2]; /* DF of object with Token Info Label */
+} idprime_private_data_t;
+
+/* For SimCList autocopy, we need to know the size of the data elements */
+static size_t idprime_list_meter(const void *el) {
+ return sizeof(idprime_object_t);
+}
+
+void idprime_free_private_data(idprime_private_data_t *priv)
+{
+ free(priv->cache_buf);
+ list_destroy(&priv->pki_list);
+ free(priv);
+ return;
+}
+
+idprime_private_data_t *idprime_new_private_data(void)
+{
+ idprime_private_data_t *priv;
+
+ priv = calloc(1, sizeof(idprime_private_data_t));
+ if (priv == NULL)
+ return NULL;
+
+ /* Initialize PKI Applets list */
+ if (list_init(&priv->pki_list) != 0 ||
+ list_attributes_copy(&priv->pki_list, idprime_list_meter, 1) != 0) {
+ idprime_free_private_data(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+int idprime_add_object_to_list(list_t *list, const idprime_object_t *object)
+{
+ if (list_append(list, object) < 0)
+ return SC_ERROR_INTERNAL;
+ return SC_SUCCESS;
+}
+
+/* This selects main IDPrime AID which is used for communication with
+ * the card */
+static int idprime_select_idprime(sc_card_t *card)
+{
+ return iso_ops->select_file(card, &idprime_path, NULL);
+}
+
+/* This select some index file, which is useful for enumerating other files
+ * on the card */
+static int idprime_select_index(sc_card_t *card)
+{
+ int r;
+ sc_file_t *file = NULL;
+ sc_path_t index_path;
+
+ /* First, we need to make sure the IDPrime AID is selected */
+ r = idprime_select_idprime(card);
+ if (r != SC_SUCCESS) {
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+
+ /* Returns FCI with expected length of data */
+ sc_format_path("0101", &index_path);
+ r = iso_ops->select_file(card, &index_path, &file);
+ if (r == SC_SUCCESS) {
+ r = file->size;
+ }
+ sc_file_free(file);
+ /* Ignore too large files */
+ if (r > MAX_FILE_SIZE) {
+ r = SC_ERROR_INVALID_DATA;
+ }
+ return r;
+}
+
+static int idprime_process_index(sc_card_t *card, idprime_private_data_t *priv, int length)
+{
+ u8 *buf = NULL;
+ int r = SC_ERROR_OUT_OF_MEMORY;
+ int i, num_entries;
+ idprime_object_t new_object;
+
+ buf = malloc(length);
+ if (buf == NULL) {
+ goto done;
+ }
+
+ r = iso_ops->read_binary(card, 0, buf, length, 0);
+ if (r < 1) {
+ r = SC_ERROR_WRONG_LENGTH;
+ goto done;
+ }
+
+ /* First byte shows the number of entries, each of them 21 bytes long */
+ num_entries = buf[0];
+ if (r < num_entries*21 + 1) {
+ r = SC_ERROR_INVALID_DATA;
+ goto done;
+ }
+ new_object.fd = 0;
+ for (i = 0; i < num_entries; i++) {
+ u8 *start = &buf[i*21+1];
+
+ /* First two bytes specify the object DF */
+ new_object.df[0] = start[0];
+ new_object.df[1] = start[1];
+ /* Second two bytes refer to the object size */
+ new_object.length = bebytes2ushort(&start[2]);
+ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "df=%s, len=%u",
+ sc_dump_hex(new_object.df, sizeof(new_object.df)), new_object.length);
+ /* in minidriver, mscp/kxcNN or kscNN lists certificates */
+ if (((memcmp(&start[4], "ksc", 3) == 0) || memcmp(&start[4], "kxc", 3) == 0)
+ && (memcmp(&start[12], "mscp", 5) == 0)) {
+ new_object.fd++;
+ if (card->type == SC_CARD_TYPE_IDPRIME_V2) {
+ /* The key reference starts from 0x11 */
+ new_object.key_reference = 0x10 + new_object.fd;
+ } else {
+ /* The key reference is one bigger than the value found here for some reason */
+ new_object.key_reference = start[8] + 1;
+ }
+ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found certificate with fd=%d, key_ref=%d",
+ new_object.fd, new_object.key_reference);
+ idprime_add_object_to_list(&priv->pki_list, &new_object);
+
+ /* This looks like non-standard extension listing pkcs11 token info label in my card */
+ } else if ((memcmp(&start[4], "tinfo", 6) == 0) && (memcmp(&start[12], "p11", 4) == 0)) {
+ memcpy(priv->tinfo_df, new_object.df, sizeof(priv->tinfo_df));
+ priv->tinfo_present = 1;
+ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Found p11/tinfo object");
+ }
+ }
+ r = SC_SUCCESS;
+done:
+ free(buf);
+ LOG_FUNC_RETURN(card->ctx, r);
+}
+
+/* CPLC has 42 bytes, but we get it with 3B header */
+#define CPLC_LENGTH 45
+static int idprime_init(sc_card_t *card)
+{
+ int r;
+ unsigned long flags;
+ idprime_private_data_t *priv = NULL;
+ struct sc_apdu apdu;
+ u8 rbuf[CPLC_LENGTH];
+ size_t rbuflen = sizeof(rbuf);
+
+ /* We need to differentiate the OS version since they behave slightly differently */
+ sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0xCA, 0x9F, 0x7F);
+ apdu.resp = rbuf;
+ apdu.resplen = rbuflen;
+ apdu.le = rbuflen;
+ r = sc_transmit_apdu(card, &apdu);
+ card->type = SC_CARD_TYPE_IDPRIME_GENERIC;
+ if (r == SC_SUCCESS && apdu.resplen == CPLC_LENGTH) {
+ /* We are interested in the OS release level here */
+ switch (rbuf[11]) {
+ case 0x01:
+ card->type = SC_CARD_TYPE_IDPRIME_V1;
+ sc_log(card->ctx, "Detected IDPrime applet version 1");
+ break;
+ case 0x02:
+ card->type = SC_CARD_TYPE_IDPRIME_V2;
+ sc_log(card->ctx, "Detected IDPrime applet version 2");
+ break;
+ default:
+ sc_log(card->ctx, "Unknown OS version received: %d", rbuf[11]);
+ break;
+ }
+ } else {
+ sc_log(card->ctx, "Failed to get CPLC data or invalid length returned, "
+ "err=%d, len=%"SC_FORMAT_LEN_SIZE_T"u",
+ r, apdu.resplen);
+ }
+
+ /* Now, select and process the index file */
+ r = idprime_select_index(card);
+ if (r <= 0) {
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+
+ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Index file found");
+
+ priv = idprime_new_private_data();
+ if (!priv) {
+ return SC_ERROR_OUT_OF_MEMORY;
+ }
+
+ r = idprime_process_index(card, priv, r);
+ if (r != SC_SUCCESS) {
+ idprime_free_private_data(priv);
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+
+ card->drv_data = priv;
+
+ switch (card->type) {
+ case SC_CARD_TYPE_IDPRIME_V1:
+ card->name = "Gemalto IDPrime (OSv1)";
+ break;
+ case SC_CARD_TYPE_IDPRIME_V2:
+ card->name = "Gemalto IDPrime (OSv2)";
+ break;
+ case SC_CARD_TYPE_IDPRIME_GENERIC:
+ default:
+ card->name = "Gemalto IDPrime (generic)";
+ break;
+ }
+ card->cla = 0x00;
+
+ /* Set up algorithm info. */
+ flags = SC_ALGORITHM_RSA_PAD_PKCS1
+ | SC_ALGORITHM_RSA_PAD_PSS
+ | SC_ALGORITHM_RSA_PAD_OAEP
+ /* SHA-1 mechanisms are not allowed in the card I have */
+ | (SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512)
+ | (SC_ALGORITHM_MGF1_SHA256 | SC_ALGORITHM_MGF1_SHA384 | SC_ALGORITHM_MGF1_SHA512)
+ ;
+
+ _sc_card_add_rsa_alg(card, 1024, flags, 0);
+ _sc_card_add_rsa_alg(card, 2048, flags, 0);
+
+ card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
+
+ LOG_FUNC_RETURN(card->ctx, 0);
+}
+
+static int idprime_finish(sc_card_t *card)
+{
+ idprime_private_data_t * priv = card->drv_data;
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+ if (priv) {
+ idprime_free_private_data(priv);
+ }
+ return SC_SUCCESS;
+}
+
+static int idprime_match_card(sc_card_t *card)
+{
+ int i, r;
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+ i = _sc_match_atr(card, idprime_atrs, &card->type);
+ if (i < 0)
+ return 0;
+
+ r = idprime_select_index(card);
+ return (r > 0);
+}
+
+/* initialize getting a list and return the number of elements in the list */
+static int idprime_get_init_and_get_count(list_t *list, idprime_object_t **entry, int *countp)
+{
+ if (countp == NULL || entry == NULL) {
+ return SC_ERROR_INVALID_ARGUMENTS;
+ }
+ *countp = list_size(list);
+ list_iterator_start(list);
+ *entry = list_iterator_next(list);
+ return SC_SUCCESS;
+}
+
+/* finalize the list iterator */
+static int idprime_final_iterator(list_t *list)
+{
+ list_iterator_stop(list);
+ return SC_SUCCESS;
+}
+
+/* fill in the prkey_info for the current object on the list and advance to the next object */
+static int idprime_fill_prkey_info(list_t *list, idprime_object_t **entry, sc_pkcs15_prkey_info_t *prkey_info)
+{
+ memset(prkey_info, 0, sizeof(sc_pkcs15_prkey_info_t));
+ if (*entry == NULL) {
+ return SC_ERROR_FILE_END_REACHED;
+ }
+
+ prkey_info->path.len = sizeof((*entry)->df);
+ memcpy(prkey_info->path.value, (*entry)->df, sizeof((*entry)->df));
+ prkey_info->path.type = SC_PATH_TYPE_FILE_ID;
+ /* Do not specify the length -- it will be read from the FCI */
+ prkey_info->path.count = -1;
+
+ /* TODO figure out the IDs as the original driver? */
+ prkey_info->id.value[0] = ((*entry)->fd >> 8) & 0xff;
+ prkey_info->id.value[1] = (*entry)->fd & 0xff;
+ prkey_info->id.len = 2;
+ prkey_info->key_reference = (*entry)->key_reference;
+ *entry = list_iterator_next(list);
+ return SC_SUCCESS;
+}
+
+#define IDPRIME_CARDID_LEN 16
+
+static int idprime_get_serial(sc_card_t* card, sc_serial_number_t* serial)
+{
+ sc_path_t cardid_path;
+ sc_file_t *file = NULL;
+ u8 buf[IDPRIME_CARDID_LEN];
+ int r;
+
+ LOG_FUNC_CALLED(card->ctx);
+
+ /* XXX this is assumed to be cardid for windows. It can be read from the index file */
+ sc_format_path("0201", &cardid_path);
+ r = iso_ops->select_file(card, &cardid_path, &file);
+ if (r != SC_SUCCESS || file->size != IDPRIME_CARDID_LEN) { /* The cardid is always 16 B */
+ sc_file_free(file);
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
+ }
+
+ r = iso_ops->read_binary(card, 0, buf, file->size, 0);
+ sc_file_free(file);
+ if (r < 1) {
+ LOG_FUNC_RETURN(card->ctx, r);
+ } else if (r != IDPRIME_CARDID_LEN) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
+ }
+
+ serial->len = MIN(IDPRIME_CARDID_LEN, SC_MAX_SERIALNR);
+ memcpy(serial->value, buf, serial->len);
+ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int idprime_get_token_name(sc_card_t* card, char** tname)
+{
+ idprime_private_data_t * priv = card->drv_data;
+ sc_path_t tinfo_path = {"\x00\x00", 2, 0, 0, SC_PATH_TYPE_PATH, {"", 0}};
+ sc_file_t *file = NULL;
+ u8 buf[2];
+ int r;
+
+ LOG_FUNC_CALLED(card->ctx);
+
+ if (tname == NULL) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+ }
+
+ if (!priv->tinfo_present) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+ }
+
+ memcpy(tinfo_path.value, priv->tinfo_df, 2);
+ r = iso_ops->select_file(card, &tinfo_path, &file);
+ if (r != SC_SUCCESS || file->size == 0) {
+ sc_file_free(file);
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+ }
+
+ /* First two bytes lists 0x01, the second indicates length */
+ r = iso_ops->read_binary(card, 0, buf, 2, 0);
+ if (r < 2 || buf[1] > file->size) { /* make sure we do not overrun */
+ sc_file_free(file);
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+ sc_file_free(file);
+
+ *tname = malloc(buf[1]);
+ if (*tname == NULL) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+ }
+
+ r = iso_ops->read_binary(card, 2, (unsigned char *)*tname, buf[1], 0);
+ if (r < 1) {
+ free(*tname);
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+
+ if ((*tname)[r-1] != '\0') {
+ (*tname)[r-1] = '\0';
+ }
+ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int idprime_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+{
+ idprime_private_data_t * priv = card->drv_data;
+
+ LOG_FUNC_CALLED(card->ctx);
+ sc_log(card->ctx, "cmd=%ld ptr=%p", cmd, ptr);
+
+ if (priv == NULL) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+ }
+ switch (cmd) {
+ case SC_CARDCTL_GET_SERIALNR:
+ return idprime_get_serial(card, (sc_serial_number_t *) ptr);
+ case SC_CARDCTL_IDPRIME_GET_TOKEN_NAME:
+ return idprime_get_token_name(card, (char **) ptr);
+ case SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS:
+ return idprime_get_init_and_get_count(&priv->pki_list, &priv->pki_current,
+ (int *)ptr);
+ case SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT:
+ return idprime_fill_prkey_info(&priv->pki_list, &priv->pki_current,
+ (sc_pkcs15_prkey_info_t *)ptr);
+ case SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS:
+ return idprime_final_iterator(&priv->pki_list);
+ }
+
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+}
+
+#define HEADER_LEN 4
+
+static int idprime_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out)
+{
+ int r, len;
+ idprime_private_data_t * priv = card->drv_data;
+ u8 data[HEADER_LEN];
+ size_t data_len = HEADER_LEN;
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+ /* 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;
+
+ r = iso_ops->select_file(card, in_path, file_out);
+ if (r == SC_SUCCESS && priv && file_out != NULL) {
+ /* Try to read first bytes of the file to fix FCI in case of
+ * compressed certififcate */
+ len = iso_ops->read_binary(card, 0, data, data_len, 0);
+ if (len == HEADER_LEN && data[0] == 0x01 && data[1] == 0x00) {
+ /* Cache the real file size for the caching read_binary() */
+ priv->file_size = (*file_out)->size;
+ /* Fix the information in the file structure to not confuse upper layers */
+ (*file_out)->size = (data[3]<<8) | data[2];
+ }
+ }
+ /* Return the exit code of the select command */
+ return r;
+}
+
+// used to read existing certificates
+static int idprime_read_binary(sc_card_t *card, unsigned int offset,
+ unsigned char *buf, size_t count, unsigned long flags)
+{
+ struct idprime_private_data *priv = card->drv_data;
+ int r;
+ int size;
+
+ sc_log(card->ctx, "called; %"SC_FORMAT_LEN_SIZE_T"u bytes at offset %d",
+ count, offset);
+
+ if (!priv->cached && offset == 0) {
+ // this function is called to read and uncompress the certificate
+ u8 buffer[SC_MAX_EXT_APDU_BUFFER_SIZE];
+ if (sizeof(buffer) < count) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+ }
+ /* Read what was reported by FCI from select command */
+ r = iso_ops->read_binary(card, 0, buffer, priv->file_size, flags);
+ if (r < 0) {
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+ if (r < 4) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
+ }
+ if (buffer[0] == 1 && buffer[1] == 0) {
+#ifdef ENABLE_ZLIB
+ size_t expectedsize = buffer[2] + buffer[3] * 0x100;
+ r = sc_decompress_alloc(&priv->cache_buf, &(priv->cache_buf_len),
+ buffer+4, priv->file_size-4, COMPRESSION_AUTO);
+ if (r != SC_SUCCESS) {
+ sc_log(card->ctx, "Zlib error: %d", r);
+ LOG_FUNC_RETURN(card->ctx, r);
+ }
+ if (priv->cache_buf_len != expectedsize) {
+ sc_log(card->ctx,
+ "expected size: %"SC_FORMAT_LEN_SIZE_T"u real size: %"SC_FORMAT_LEN_SIZE_T"u",
+ expectedsize, priv->cache_buf_len);
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
+ }
+#else
+ sc_log(card->ctx, "compression not supported, no zlib");
+ return SC_ERROR_NOT_SUPPORTED;
+#endif /* ENABLE_ZLIB */
+ } else {
+ /* assuming uncompressed certificate */
+ priv->cache_buf = malloc(r);
+ if (priv->cache_buf == NULL) {
+ return SC_ERROR_OUT_OF_MEMORY;
+ }
+ memcpy(priv->cache_buf, buffer, r);
+ priv->cache_buf_len = r;
+ }
+ priv->cached = 1;
+ }
+ if (offset >= priv->cache_buf_len) {
+ return 0;
+ }
+ size = (int) MIN((priv->cache_buf_len - offset), count);
+ memcpy(buf, priv->cache_buf + offset, size);
+ return size;
+}
+
+static int
+idprime_set_security_env(struct sc_card *card,
+ const struct sc_security_env *env, int se_num)
+{
+ int r;
+ struct sc_security_env new_env;
+
+ if (card == NULL || env == NULL) {
+ return SC_ERROR_INVALID_ARGUMENTS;
+ }
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+ /* The card requires algorithm reference here */
+ new_env = *env;
+ new_env.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
+ /* SHA-1 mechanisms are not allowed in the card I have available */
+ switch (env->operation) {
+ case SC_SEC_OPERATION_DECIPHER:
+ if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_OAEP) {
+ if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
+ new_env.algorithm_ref = 0x1D;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
+ new_env.algorithm_ref = 0x4D;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
+ new_env.algorithm_ref = 0x5D;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
+ new_env.algorithm_ref = 0x6D;
+ }
+ } else { /* RSA-PKCS without hashing */
+ new_env.algorithm_ref = 0x1A;
+ }
+ break;
+ case SC_SEC_OPERATION_SIGN:
+ if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) {
+ if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
+ new_env.algorithm_ref = 0x45;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
+ new_env.algorithm_ref = 0x55;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
+ new_env.algorithm_ref = 0x65;
+ }
+ } else { /* RSA-PKCS */
+ if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
+ new_env.algorithm_ref = 0x42;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
+ new_env.algorithm_ref = 0x52;
+ } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
+ new_env.algorithm_ref = 0x62;
+ } else { /* RSA-PKCS without hashing */
+ new_env.algorithm_ref = 0x02;
+ }
+ }
+ break;
+ default:
+ return SC_ERROR_INVALID_ARGUMENTS;
+ }
+ r = iso_ops->set_security_env(card,
+ (const struct sc_security_env *) &new_env, se_num);
+
+ LOG_FUNC_RETURN(card->ctx, r);
+}
+
+/* These are mostly ISO versions updated to IDPrime specifics */
+static int
+idprime_compute_signature(struct sc_card *card,
+ const u8 * data, size_t datalen, u8 * out, size_t outlen)
+{
+ int r;
+ struct sc_apdu apdu;
+ u8 *p;
+ u8 sbuf[128]; /* For SHA-512 we need 64 + 2 bytes */
+ u8 rbuf[4096]; /* needs work. for 3072 keys, needs 384+2 or so */
+ size_t rbuflen = sizeof(rbuf);
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+ /* We should be signing hashes only so we should not reach this limit */
+ if (datalen + 2 > sizeof(sbuf)) {
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+ }
+
+ p = sbuf;
+ *(p++) = 0x90;
+ *(p++) = datalen;
+ memcpy(p, data, datalen);
+ p += datalen;
+
+ /* INS: 0x2A PERFORM SECURITY OPERATION
+ * P1: 0x90 Hash code
+ * P2: 0xA0 Input template for the computation of a hash-code (the template is hashed) */
+ sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x90, 0xA0);
+ apdu.resp = rbuf;
+ apdu.resplen = rbuflen;
+ apdu.le = datalen;
+
+ apdu.data = sbuf;
+ apdu.lc = p - sbuf;
+ apdu.datalen = p - sbuf;
+
+ r = sc_transmit_apdu(card, &apdu);
+ LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+ /* This just returns the passed data (hash code) (for verification?) */
+ if (apdu.resplen != datalen || memcmp(rbuf, data, datalen) != 0) {
+ sc_log(card->ctx, "The initial APDU did not return the same data");
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+ }
+ /* INS: 0x2A PERFORM SECURITY OPERATION
+ * P1: 0x9E Resp: Digital Signature
+ * P2: 0x9A Cmd: Input for Digital Signature */
+ sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x2A, 0x9E, 0x9A);
+ apdu.resp = out;
+ apdu.resplen = outlen;
+ apdu.le = outlen;
+ if (apdu.le > sc_get_max_recv_size(card)) {
+ /* The lower layers will automatically do a GET RESPONSE, if possible.
+ * All other workarounds must be carried out by the upper layers. */
+ apdu.le = sc_get_max_recv_size(card);
+ }
+
+ apdu.data = NULL;
+ apdu.datalen = 0;
+ apdu.lc = 0;
+ r = sc_transmit_apdu(card, &apdu);
+ LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+ if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
+ LOG_FUNC_RETURN(card->ctx, apdu.resplen);
+
+ r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+ LOG_TEST_RET(card->ctx, r, "Card returned error");
+
+ LOG_FUNC_RETURN(card->ctx, r);
+}
+
+/* These are mostly ISO versions updated to IDPrime specifics */
+static int
+idprime_decipher(struct sc_card *card,
+ const u8 * crgram, size_t crgram_len,
+ u8 * out, size_t outlen)
+{
+ int r;
+ struct sc_apdu apdu;
+ u8 *sbuf = NULL;
+
+ if (card == NULL || crgram == NULL || out == NULL) {
+ return SC_ERROR_INVALID_ARGUMENTS;
+ }
+ LOG_FUNC_CALLED(card->ctx);
+ sc_log(card->ctx,
+ "IDPrime decipher: in-len %"SC_FORMAT_LEN_SIZE_T"u, out-len %"SC_FORMAT_LEN_SIZE_T"u",
+ crgram_len, outlen);
+
+ sbuf = malloc(crgram_len + 1);
+ if (sbuf == NULL)
+ return SC_ERROR_OUT_OF_MEMORY;
+
+ /* INS: 0x2A PERFORM SECURITY OPERATION
+ * P1: 0x80 Resp: Plain value
+ * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */
+ sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86);
+ apdu.resp = out;
+ apdu.resplen = outlen;
+ apdu.le = outlen;
+
+ sbuf[0] = 0x81; /* padding indicator byte, 0x81 = Proprietary */
+ memcpy(sbuf + 1, crgram, crgram_len);
+ apdu.data = sbuf;
+ apdu.lc = crgram_len + 1;
+ if (apdu.lc > sc_get_max_send_size(card)) {
+ /* The lower layers will automatically do chaining */
+ apdu.flags |= SC_APDU_FLAGS_CHAINING;
+ }
+ if (apdu.le > sc_get_max_recv_size(card)) {
+ /* The lower layers will automatically do a GET RESPONSE, if possible.
+ * All other workarounds must be carried out by the upper layers. */
+ apdu.le = sc_get_max_recv_size(card);
+ }
+ apdu.datalen = crgram_len + 1;
+
+ r = sc_transmit_apdu(card, &apdu);
+ sc_mem_clear(sbuf, crgram_len + 1);
+ free(sbuf);
+ LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+ if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
+ LOG_FUNC_RETURN(card->ctx, apdu.resplen);
+ else
+ LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
+}
+
+
+static struct sc_card_driver * sc_get_driver(void)
+{
+ if (iso_ops == NULL) {
+ iso_ops = sc_get_iso7816_driver()->ops;
+ }
+
+ idprime_ops = *iso_ops;
+ idprime_ops.match_card = idprime_match_card;
+ idprime_ops.init = idprime_init;
+ idprime_ops.finish = idprime_finish;
+
+ idprime_ops.read_binary = idprime_read_binary;
+ idprime_ops.select_file = idprime_select_file;
+ idprime_ops.card_ctl = idprime_card_ctl;
+ idprime_ops.set_security_env = idprime_set_security_env;
+ idprime_ops.compute_signature = idprime_compute_signature;
+ idprime_ops.decipher = idprime_decipher;
+
+ return &idprime_drv;
+}
+
+struct sc_card_driver * sc_get_idprime_driver(void)
+{
+ return sc_get_driver();
+}
diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h
index ac1969256b..7bba7e6687 100644
--- a/src/libopensc/cardctl.h
+++ b/src/libopensc/cardctl.h
@@ -303,6 +303,16 @@ enum {
SC_CARDCTL_GIDS_INITIALIZE,
SC_CARDCTL_GIDS_SET_ADMIN_KEY,
SC_CARDCTL_GIDS_AUTHENTICATE_ADMIN,
+
+ /*
+ * IDPrime specific calls
+ */
+ SC_CARDCTL_IDPRIME_BASE = _CTL_PREFIX('I', 'D', 'P'),
+ SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS,
+ SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT,
+ SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS,
+ SC_CARDCTL_IDPRIME_GET_TOKEN_NAME,
+
};
enum {
diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
index 24d73c094a..cb0501c3aa 100644
--- a/src/libopensc/cards.h
+++ b/src/libopensc/cards.h
@@ -234,6 +234,7 @@ enum {
/* JPKI cards */
SC_CARD_TYPE_JPKI_BASE = 31000,
+ /* Coolkey cards */
SC_CARD_TYPE_COOLKEY_BASE = 32000,
SC_CARD_TYPE_COOLKEY_GENERIC,
@@ -258,6 +259,12 @@ enum {
SC_CARD_TYPE_RUTOKEN_ECP_SC,
SC_CARD_TYPE_RUTOKEN_LITE,
SC_CARD_TYPE_RUTOKEN_LITE_SC,
+
+ /* IDPrime cards */
+ SC_CARD_TYPE_IDPRIME_BASE = 37000,
+ SC_CARD_TYPE_IDPRIME_V1,
+ SC_CARD_TYPE_IDPRIME_V2,
+ SC_CARD_TYPE_IDPRIME_GENERIC,
};
extern sc_card_driver_t *sc_get_default_driver(void);
@@ -301,6 +308,7 @@ 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);
extern sc_card_driver_t *sc_get_esteid2018_driver(void);
+extern sc_card_driver_t *sc_get_idprime_driver(void);
#ifdef __cplusplus
}
diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c
index 40f573ed0f..4c5adc6e5f 100644
--- a/src/libopensc/ctx.c
+++ b/src/libopensc/ctx.c
@@ -128,6 +128,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
{ "esteid2018", (void *(*)(void)) sc_get_esteid2018_driver },
+ { "idprime", (void *(*)(void)) sc_get_idprime_driver },
/* Here should be placed drivers that need some APDU transactions in the
* driver's `match_card()` function. */
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index d8ec42174e..10bea0a013 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.h
@@ -107,12 +107,13 @@ extern "C" {
* 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_PADS 0x0000003F
#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 /* PKCS#1 v2.0 PSS */
+#define SC_ALGORITHM_RSA_PAD_OAEP 0x00000020 /* PKCS#1 v2.0 OAEP */
/* If the card is willing to produce a cryptogram with the following
* hash values, set these flags accordingly. The interpretation of the hash
diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c
index 4a8fc17b9c..5bcb2bb8d9 100644
--- a/src/libopensc/padding.c
+++ b/src/libopensc/padding.c
@@ -499,6 +499,7 @@ int sc_get_encoding_flags(sc_context_t *ctx,
/* Use the card's raw RSA capability on the padded input */
*sflags = SC_ALGORITHM_RSA_PAD_NONE;
*pflags = iflags;
+ /* TODO emulate the OAEP decryption */
} else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
(iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
diff --git a/src/libopensc/pkcs15-cac.c b/src/libopensc/pkcs15-cac.c
index d637dedf19..e8c13d5fea 100644
--- a/src/libopensc/pkcs15-cac.c
+++ b/src/libopensc/pkcs15-cac.c
@@ -84,89 +84,6 @@ static const char * cac_get_name(int type)
return ("CAC");
}
-/*
- * These could move to a helper file for other cards that wish to use usage as a way of getting flags
- */
-
-/* Only certain usages are valid for a given algorithm, return all the usages that the algorithm supports so we
- * can use it as a filter for all the public and private key usages */
-static unsigned int
-cac_alg_flags_from_algorithm(int algorithm)
-{
- switch (algorithm) {
- case SC_ALGORITHM_RSA:
- return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP |
- SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
- SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
- SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
- SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
- case SC_ALGORITHM_DSA:
- return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
- SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
-#ifdef SC_ALGORITHM_DH
- case SC_ALGORITHM_DH:
- return SC_PKCS15_PRKEY_USAGE_DERIVE ;
-#endif
- case SC_ALGORITHM_EC:
- return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
- SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
- case SC_ALGORITHM_GOSTR3410:
- return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
- SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
- }
- return 0;
-}
-
-/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */
-#define CAC_X509_USAGE_SIGNATURE \
- (SC_X509_DIGITAL_SIGNATURE | \
- SC_X509_NON_REPUDIATION | \
- SC_X509_KEY_CERT_SIGN | \
- SC_X509_CRL_SIGN)
-#define CAC_X509_USAGE_DERIVE \
- SC_X509_KEY_AGREEMENT
-#define CAC_X509_USAGE_UNWRAP \
- (SC_X509_KEY_ENCIPHERMENT | \
- SC_X509_KEY_AGREEMENT)
-#define CAC_X509_USAGE_DECRYPT \
- (SC_X509_DATA_ENCIPHERMENT | \
- SC_X509_ENCIPHER_ONLY)
-#define CAC_X509_USAGE_NONREPUDIATION \
- SC_X509_NON_REPUDIATION
-
-/* map a cert usage and algorithm to public and private key usages */
-static int
-cac_map_usage(unsigned int cert_usage, int algorithm, unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr, int allow_nonrepudiation)
-{
- unsigned int pub_usage = 0, pr_usage = 0;
- unsigned int alg_flags = cac_alg_flags_from_algorithm(algorithm);
-
- if (cert_usage & CAC_X509_USAGE_SIGNATURE) {
- pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
- pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
- }
- if (cert_usage & CAC_X509_USAGE_DERIVE) {
- pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
- pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
- }
- if (cert_usage & (CAC_X509_USAGE_DECRYPT|CAC_X509_USAGE_UNWRAP)) {
- pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
- pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
- }
- if (allow_nonrepudiation && (cert_usage & CAC_X509_USAGE_NONREPUDIATION)) {
- pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
- pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
- }
- /* filter usages algorithm */
- if (pub_usage_ptr) {
- *pub_usage_ptr = pub_usage & alg_flags;
- }
- if (pr_usage_ptr) {
- *pr_usage_ptr = pr_usage & alg_flags;
- }
- return SC_SUCCESS;
-}
-
static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
{
static const pindata pins[] = {
@@ -407,9 +324,9 @@ static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
if (r < 0) {
- usage = 0xd9ULL; /* basic default usage */
+ usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */
}
- cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
+ sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
sc_dump_hex(cert_info.id.value, cert_info.id.len),
usage, pubkey_info.usage, prkey_info.usage);
diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c
index 8606d14af0..7850fad8d8 100644
--- a/src/libopensc/pkcs15-cert.c
+++ b/src/libopensc/pkcs15-cert.c
@@ -257,6 +257,8 @@ sc_pkcs15_get_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert,
{ NULL, 0, 0, 0, NULL, NULL }
};
+ LOG_FUNC_CALLED(ctx);
+
for (next_ext = cert->extensions, next_ext_len = cert->extensions_len; next_ext_len; ) {
/* unwrap the set and point to the next ava */
ext = sc_asn1_skip_tag(ctx, &next_ext, &next_ext_len,
@@ -324,6 +326,8 @@ sc_pkcs15_get_bitstring_extension(struct sc_context *ctx,
{ NULL, 0, 0, 0, NULL, NULL }
};
+ LOG_FUNC_CALLED(ctx);
+
r = sc_pkcs15_get_extension(ctx, cert, type, &bit_string, &bit_string_len, is_critical);
LOG_TEST_RET(ctx, r, "Get extension error");
@@ -550,6 +554,88 @@ sc_pkcs15_encode_cdf_entry(sc_context_t *ctx, const struct sc_pkcs15_object *obj
return r;
}
+/* Only certain usages are valid for a given algorithm, return all the usages
+ * that the algorithm supports so we can use it as a filter for all
+ * the public and private key usages
+ */
+static unsigned int
+sc_pkcs15_alg_flags_from_algorithm(int algorithm)
+{
+ switch (algorithm) {
+ case SC_ALGORITHM_RSA:
+ return SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_WRAP |
+ SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
+ SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
+ SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
+ SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+ case SC_ALGORITHM_DSA:
+ return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
+ SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+#ifdef SC_ALGORITHM_DH
+ case SC_ALGORITHM_DH:
+ return SC_PKCS15_PRKEY_USAGE_DERIVE ;
+#endif
+ case SC_ALGORITHM_EC:
+ return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
+ SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+ case SC_ALGORITHM_GOSTR3410:
+ return SC_PKCS15_PRKEY_USAGE_DERIVE | SC_PKCS15_PRKEY_USAGE_VERIFY|
+ SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+ }
+ return 0;
+}
+
+/* These are the cert key usage bits that map to various PKCS #11 (and thus PKCS #15) flags */
+#define SC_PKCS15_X509_USAGE_SIGNATURE \
+ (SC_X509_DIGITAL_SIGNATURE | \
+ SC_X509_NON_REPUDIATION | \
+ SC_X509_KEY_CERT_SIGN | \
+ SC_X509_CRL_SIGN)
+#define SC_PKCS15_X509_USAGE_DERIVE \
+ SC_X509_KEY_AGREEMENT
+#define SC_PKCS15_X509_USAGE_UNWRAP \
+ (SC_X509_KEY_ENCIPHERMENT | \
+ SC_X509_KEY_AGREEMENT)
+#define SC_PKCS15_X509_USAGE_DECRYPT \
+ (SC_X509_DATA_ENCIPHERMENT | \
+ SC_X509_ENCIPHER_ONLY)
+#define SC_PKCS15_X509_USAGE_NONREPUDIATION \
+ SC_X509_NON_REPUDIATION
+
+/* map a cert usage and algorithm to public and private key usages */
+int
+sc_pkcs15_map_usage(unsigned int cert_usage, int algorithm,
+ unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr,
+ int allow_nonrepudiation)
+{
+ unsigned int pub_usage = 0, pr_usage = 0;
+ unsigned int alg_flags = sc_pkcs15_alg_flags_from_algorithm(algorithm);
+
+ if (cert_usage & SC_PKCS15_X509_USAGE_SIGNATURE) {
+ pub_usage |= SC_PKCS15_PRKEY_USAGE_VERIFY|SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
+ pr_usage |= SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
+ }
+ if (cert_usage & SC_PKCS15_X509_USAGE_DERIVE) {
+ pub_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
+ pr_usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
+ }
+ if (cert_usage & (SC_PKCS15_X509_USAGE_DECRYPT|SC_PKCS15_X509_USAGE_UNWRAP)) {
+ pub_usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
+ pr_usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
+ }
+ if (allow_nonrepudiation && (cert_usage & SC_PKCS15_X509_USAGE_NONREPUDIATION)) {
+ pub_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+ pr_usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
+ }
+ /* filter usages algorithm */
+ if (pub_usage_ptr) {
+ *pub_usage_ptr = pub_usage & alg_flags;
+ }
+ if (pr_usage_ptr) {
+ *pr_usage_ptr = pr_usage & alg_flags;
+ }
+ return SC_SUCCESS;
+}
void
sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert)
diff --git a/src/libopensc/pkcs15-idprime.c b/src/libopensc/pkcs15-idprime.c
new file mode 100644
index 0000000000..d882696997
--- /dev/null
+++ b/src/libopensc/pkcs15-idprime.c
@@ -0,0 +1,286 @@
+/*
+ * partial PKCS15 emulation for IDPrime cards.
+ *
+ * We can not use the ISO code, since the EF.DIR and EF.ATR for
+ * object discovery are missing
+ *
+ * Copyright (C) 2019, Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen@redhat.com>
+ * 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 <string.h>
+#include <stdlib.h>
+#include "internal.h"
+#include "cardctl.h"
+#include "pkcs15.h"
+
+#define CERT_LABEL_TEMPLATE "Certificate %d"
+#define PUBKEY_LABEL_TEMPLATE "Public key %d"
+#define PRIVKEY_LABEL_TEMPLATE "Private key %d"
+
+static int idprime_detect_card(sc_pkcs15_card_t *p15card)
+{
+ sc_card_t *card = p15card->card;
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+ if (card->type < SC_CARD_TYPE_IDPRIME_BASE
+ || card->type >= SC_CARD_TYPE_IDPRIME_BASE+1000)
+ return SC_ERROR_INVALID_CARD;
+ return SC_SUCCESS;
+}
+
+static int sc_pkcs15emu_idprime_init(sc_pkcs15_card_t *p15card)
+{
+ int r, i;
+ sc_card_t *card = p15card->card;
+ sc_serial_number_t serial;
+ char buf[SC_MAX_SERIALNR * 2 + 1];
+ int count;
+ char *token_name = NULL;
+ struct sc_pkcs15_auth_info pin_info;
+ struct sc_pkcs15_object pin_obj;
+ const char pin_label[] = "PIN";
+ const char *pin_id = "11";
+
+ /* oid for key usage */
+ static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }};
+ unsigned int usage;
+
+ SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+ /* could read this off card if needed */
+ p15card->tokeninfo->label = strdup("IDPrime");
+ p15card->tokeninfo->manufacturer_id = strdup("Gemalto");
+
+ /*
+ * get serial number
+ */
+ memset(&serial, 0, sizeof(serial));
+ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
+ if (r < 0) {
+ sc_log(card->ctx, "sc_card_ctl rc=%d", r);
+ p15card->tokeninfo->serial_number = strdup("00000000");
+ } else {
+ sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
+ p15card->tokeninfo->serial_number = strdup(buf);
+ }
+ /* set pin */
+ sc_log(card->ctx, "IDPrime adding pin...");
+ memset(&pin_info, 0, sizeof(pin_info));
+ memset(&pin_obj, 0, sizeof(pin_obj));
+
+ pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
+ sc_pkcs15_format_id(pin_id, &pin_info.auth_id);
+ pin_info.attrs.pin.reference = 0x11;
+ pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED;
+ pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
+ pin_info.attrs.pin.min_length = 4;
+ pin_info.attrs.pin.stored_length = 0;
+ pin_info.attrs.pin.max_length = 16;
+ pin_info.tries_left = -1;
+
+ sc_log(card->ctx, "IDPrime Adding pin with label=%s", pin_label);
+ strncpy(pin_obj.label, pin_label, SC_PKCS15_MAX_LABEL_SIZE - 1);
+ pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
+
+ r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
+ if (r < 0)
+ LOG_FUNC_RETURN(card->ctx, r);
+
+ /*
+ * get token name if provided
+ */
+ r = sc_card_ctl(card, SC_CARDCTL_IDPRIME_GET_TOKEN_NAME, &token_name);
+ if (r < 0) {
+ /* On failure we will get the token name from certificates later */
+ sc_log(card->ctx, "sc_card_ctl rc=%d", r);
+ } else {
+ free(p15card->tokeninfo->label);
+ p15card->tokeninfo->label = token_name;
+ sc_log(card->ctx, "IDPrime setting token label = %s", token_name);
+ }
+ /*
+ * certs, pubkeys and priv keys are related and we assume
+ * they are in order
+ * We need to read the cert, get modulus and keylen
+ * We use those for the pubkey, and priv key objects.
+ */
+ sc_log(card->ctx, "IDPrime adding certs, pub and priv keys...");
+ r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, &count);
+ LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");
+
+ for (i = 0; i < count; i++) {
+ struct sc_pkcs15_prkey_info prkey_info;
+ struct sc_pkcs15_cert_info cert_info;
+ struct sc_pkcs15_pubkey_info pubkey_info;
+ struct sc_pkcs15_object cert_obj;
+ struct sc_pkcs15_object pubkey_obj;
+ struct sc_pkcs15_object prkey_obj;
+ sc_pkcs15_der_t cert_der;
+ sc_pkcs15_cert_t *cert_out = NULL;
+
+ r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, &prkey_info);
+ LOG_TEST_RET(card->ctx, r, "Can not get next object");
+
+ memset(&cert_info, 0, sizeof(cert_info));
+ memset(&pubkey_info, 0, sizeof(pubkey_info));
+ /* prkey_info cleaned by the card_ctl call */
+ memset(&cert_obj, 0, sizeof(cert_obj));
+ memset(&pubkey_obj, 0, sizeof(pubkey_obj));
+ memset(&prkey_obj, 0, sizeof(prkey_obj));
+
+ cert_info.id = prkey_info.id;
+ pubkey_info.id = prkey_info.id;
+ cert_info.path = prkey_info.path;
+ /* For private keys, we no longer care for the path, just
+ * the key reference later used in the security environment */
+ prkey_info.path.len = 0;
+ prkey_info.path.aid.len = 0;
+ pubkey_info.key_reference = prkey_info.key_reference;
+ sc_log(card->ctx, "Key ref r=%x", prkey_info.key_reference);
+
+ pubkey_info.native = 1;
+ prkey_info.native = 1;
+
+ snprintf(cert_obj.label, SC_PKCS15_MAX_LABEL_SIZE, CERT_LABEL_TEMPLATE, i+1);
+ snprintf(pubkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PUBKEY_LABEL_TEMPLATE, i+1);
+ snprintf(prkey_obj.label, SC_PKCS15_MAX_LABEL_SIZE, PRIVKEY_LABEL_TEMPLATE, i+1);
+ prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
+ sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id);
+
+ r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);
+
+ if (r) {
+ sc_log(card->ctx, "No cert found,i=%d", i);
+ continue;
+ }
+ cert_info.path.count = cert_der.len;
+
+ sc_log(card->ctx,
+ "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n",
+ cert_der.len, cert_info.path.count, r);
+ sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len);
+
+ /* cache it using the PKCS15 emulation objects */
+ /* as it does not change */
+ if (cert_der.value) {
+ cert_info.value.value = cert_der.value;
+ cert_info.value.len = cert_der.len;
+ cert_info.path.len = 0; /* use in mem cert from now on */
+ }
+
+ /* following will find the cached cert in cert_info */
+ r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+ if (r < 0 || cert_out->key == NULL) {
+ sc_log(card->ctx, "Failed to read/parse the certificate r=%d",r);
+ if (cert_out != NULL)
+ sc_pkcs15_free_certificate(cert_out);
+ free(cert_der.value);
+ continue;
+ }
+
+ r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
+ if (r < 0) {
+ sc_log(card->ctx, " Failed to add cert obj r=%d",r);
+ sc_pkcs15_free_certificate(cert_out);
+ free(cert_der.value);
+ continue;
+ }
+ /* set the token name to the name of the CN of the first certificate */
+ if (!token_name) {
+ u8 * cn_name = NULL;
+ size_t cn_len = 0;
+ static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
+ r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject,
+ cert_out->subject_len, &cn_oid, &cn_name, &cn_len);
+ if (r == SC_SUCCESS) {
+ token_name = malloc (cn_len+1);
+ if (!token_name) {
+ free(cn_name);
+ r = SC_ERROR_OUT_OF_MEMORY;
+ goto fail;
+ }
+ memcpy(token_name, cn_name, cn_len);
+ free(cn_name);
+ token_name[cn_len] = '\0';
+ free(p15card->tokeninfo->label);
+ p15card->tokeninfo->label = token_name;
+ }
+ }
+
+
+ r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key,
+ &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len);
+ if (r < 0)
+ goto fail;
+ pubkey_obj.emulated = cert_out->key;
+
+ r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
+ if (r < 0) {
+ usage = SC_X509_DATA_ENCIPHERMENT|SC_X509_DIGITAL_SIGNATURE; /* basic default usage */
+ }
+ sc_pkcs15_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
+ sc_log(card->ctx, "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
+ sc_dump_hex(cert_info.id.value, cert_info.id.len),
+ usage, pubkey_info.usage, prkey_info.usage);
+ if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
+ sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
+ sc_pkcs15_free_certificate(cert_out);
+ continue;
+ } else {
+ pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
+ prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
+ sc_log(card->ctx, "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
+ r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
+ if (r < 0)
+ goto fail;
+ sc_log(card->ctx, "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
+ r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
+ if (r < 0)
+ goto fail;
+ }
+
+ cert_out->key = NULL;
+fail:
+ sc_pkcs15_free_certificate(cert_out);
+ if (r < 0)
+ LOG_FUNC_RETURN(card->ctx, r); /* should not fail */
+
+ }
+ r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count);
+ LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");
+
+ LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card,
+ struct sc_aid *aid)
+{
+ sc_card_t *card = p15card->card;
+ sc_context_t *ctx = card->ctx;
+
+ LOG_FUNC_CALLED(ctx);
+
+ if (idprime_detect_card(p15card))
+ return SC_ERROR_WRONG_CARD;
+ return sc_pkcs15emu_idprime_init(p15card);
+}
diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c
index facb0a607c..279a001e9d 100644
--- a/src/libopensc/pkcs15-syn.c
+++ b/src/libopensc/pkcs15-syn.c
@@ -43,22 +43,23 @@ struct sc_pkcs15_emulator_handler builtin_emulators[] = {
{ "itacns", sc_pkcs15emu_itacns_init_ex },
{ "PIV-II", sc_pkcs15emu_piv_init_ex },
{ "cac", sc_pkcs15emu_cac_init_ex },
+ { "idprime", sc_pkcs15emu_idprime_init_ex },
{ "gemsafeGPK", sc_pkcs15emu_gemsafeGPK_init_ex },
{ "gemsafeV1", sc_pkcs15emu_gemsafeV1_init_ex },
{ "actalis", sc_pkcs15emu_actalis_init_ex },
{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
{ "tccardos", sc_pkcs15emu_tccardos_init_ex },
- { "entersafe", sc_pkcs15emu_entersafe_init_ex },
+ { "entersafe", sc_pkcs15emu_entersafe_init_ex },
{ "pteid", sc_pkcs15emu_pteid_init_ex },
{ "oberthur", sc_pkcs15emu_oberthur_init_ex },
{ "sc-hsm", sc_pkcs15emu_sc_hsm_init_ex },
- { "dnie", sc_pkcs15emu_dnie_init_ex },
- { "gids", sc_pkcs15emu_gids_init_ex },
- { "iasecc", sc_pkcs15emu_iasecc_init_ex },
- { "jpki", sc_pkcs15emu_jpki_init_ex },
+ { "dnie", sc_pkcs15emu_dnie_init_ex },
+ { "gids", sc_pkcs15emu_gids_init_ex },
+ { "iasecc", sc_pkcs15emu_iasecc_init_ex },
+ { "jpki", sc_pkcs15emu_jpki_init_ex },
{ "coolkey", sc_pkcs15emu_coolkey_init_ex },
- { "din66291", sc_pkcs15emu_din_66291_init_ex },
- { "esteid2018", sc_pkcs15emu_esteid2018_init_ex },
+ { "din66291", sc_pkcs15emu_din_66291_init_ex },
+ { "esteid2018", sc_pkcs15emu_esteid2018_init_ex },
{ NULL, NULL }
};
diff --git a/src/libopensc/pkcs15-syn.h b/src/libopensc/pkcs15-syn.h
index 6811b3dab1..ccaf693ca4 100644
--- a/src/libopensc/pkcs15-syn.h
+++ b/src/libopensc/pkcs15-syn.h
@@ -53,6 +53,7 @@ int sc_pkcs15emu_iasecc_init_ex(sc_pkcs15_card_t *, struct sc_aid *);
int sc_pkcs15emu_jpki_init_ex(sc_pkcs15_card_t *, struct sc_aid *);
int sc_pkcs15emu_coolkey_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *);
int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *);
+int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *);
struct sc_pkcs15_emulator_handler {
const char *name;
diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h
index f2ccc42aed..df1435ce92 100644
--- a/src/libopensc/pkcs15.h
+++ b/src/libopensc/pkcs15.h
@@ -754,6 +754,9 @@ int sc_pkcs15_get_name_from_dn(struct sc_context *ctx,
const u8 *dn, size_t dn_len,
const struct sc_object_id *type,
u8 **name, size_t *name_len);
+int sc_pkcs15_map_usage(unsigned int cert_usage, int algorithm,
+ unsigned int *pub_usage_ptr, unsigned int *pr_usage_ptr,
+ int allow_nonrepudiation);
int sc_pkcs15_get_extension(struct sc_context *ctx,
struct sc_pkcs15_cert *cert,
const struct sc_object_id *type,
diff --git a/src/libopensc/simpletlv.h b/src/libopensc/simpletlv.h
index a952779733..6bcd4f0856 100644
--- a/src/libopensc/simpletlv.h
+++ b/src/libopensc/simpletlv.h
@@ -29,7 +29,6 @@ extern "C" {
#endif
#include "libopensc/opensc.h"
-#include "libopensc/pkcs15.h"
/*
* Create a tag/length file in Simple TLV based on the val_len content length
diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c
index 22081ffef1..e94eeeffec 100644
--- a/src/pkcs11/framework-pkcs15.c
+++ b/src/pkcs11/framework-pkcs15.c
@@ -3976,7 +3976,7 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj,
/* 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 "
+ sc_log(context, "Invalid data length for the selected "
"PSS parameters");
return rv;
}
@@ -4179,6 +4179,39 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj,
case CKM_RSA_X_509:
flags |= SC_ALGORITHM_RSA_RAW;
break;
+ case CKM_RSA_PKCS_OAEP:
+ flags |= SC_ALGORITHM_RSA_PAD_OAEP;
+
+ /* 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;
+ }
+
+ switch (((CK_RSA_PKCS_OAEP_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;
+ }
+
+ /* The MGF parameter was already verified in SignInit() */
+ flags |= mgf2flags(((CK_RSA_PKCS_OAEP_PARAMS*)pMechanism->pParameter)->mgf);
+ break;
default:
return CKR_MECHANISM_INVALID;
}
@@ -4352,6 +4385,7 @@ pkcs15_prkey_init_params(struct sc_pkcs11_session *session,
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 };
+ const CK_RSA_PKCS_OAEP_PARAMS *oaep_params;
switch (pMechanism->mechanism) {
case CKM_RSA_PKCS_PSS:
@@ -4407,6 +4441,26 @@ pkcs15_prkey_init_params(struct sc_pkcs11_session *session,
/* TODO support different salt lengths */
break;
+ case CKM_RSA_PKCS_OAEP:
+ if (!pMechanism->pParameter ||
+ pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS))
+ return CKR_MECHANISM_PARAM_INVALID;
+
+ oaep_params = (CK_RSA_PKCS_OAEP_PARAMS*)pMechanism->pParameter;
+ switch (oaep_params->mgf) {
+ case CKG_MGF1_SHA1:
+ case CKG_MGF1_SHA224:
+ case CKG_MGF1_SHA256:
+ case CKG_MGF1_SHA384:
+ case CKG_MGF1_SHA512:
+ /* OK */
+ break;
+ default:
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ /* TODO support different salt lengths */
+ /* TODO is there something more to check */
+ break;
}
return CKR_OK;
}
@@ -5619,6 +5673,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
#ifdef ENABLE_OPENSSL
rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS;
+ /* TODO support OAEP decryption & encryption using OpenSSL */
#endif
}
@@ -5699,6 +5754,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
}
if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) {
+ CK_FLAGS old_flags = mech_info.flags;
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);
@@ -5735,6 +5791,18 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
if (rc != CKR_OK)
return rc;
}
+ mech_info.flags = old_flags;
+ }
+
+ if (rsa_flags & SC_ALGORITHM_RSA_PAD_OAEP) {
+ CK_FLAGS old_flags = mech_info.flags;
+ mech_info.flags &= ~(CKF_SIGN|CKF_VERIFY|CKF_SIGN_RECOVER|CKF_VERIFY_RECOVER);
+ mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_OAEP, &mech_info, CKK_RSA, NULL, NULL);
+ rc = sc_pkcs11_register_mechanism(p11card, mt);
+ if (rc != CKR_OK) {
+ return rc;
+ }
+ mech_info.flags = old_flags;
}
if (rsa_flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c
index 358cad40fd..983d8dcbdf 100644
--- a/src/pkcs11/mechanism.c
+++ b/src/pkcs11/mechanism.c
@@ -811,6 +811,15 @@ sc_pkcs11_decr_init(struct sc_pkcs11_session *session,
}
rv = mt->decrypt_init(operation, key);
+ /* 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 */
+ LOG_FUNC_RETURN(context, (int) rv);
+ }
+ }
+
if (rv != CKR_OK)
session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
diff --git a/src/tests/p11test/p11test_case_common.c b/src/tests/p11test/p11test_case_common.c
index bd4b39af74..22e639cf49 100644
--- a/src/tests/p11test/p11test_case_common.c
+++ b/src/tests/p11test/p11test_case_common.c
@@ -422,7 +422,7 @@ int search_objects(test_certs_t *objects, token_info_t *info,
CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE_PTR object_handles = NULL;
unsigned long i = 0, objects_length = 0;
- int j;
+ int j, ret = -1;
/* FindObjects first
* https://wiki.oasis-open.org/pkcs11/CommonBugs
@@ -439,16 +439,18 @@ int search_objects(test_certs_t *objects, token_info_t *info,
break;
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjects: rv = 0x%.8lX\n", rv);
- return -1;
+ goto out;
}
/* store handle */
if (i >= objects_length) {
+ CK_OBJECT_HANDLE_PTR new_object_handles = NULL;
objects_length += 4; // do not realloc after each row
- object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE));
- if (object_handles == NULL) {
+ new_object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE));
+ if (new_object_handles == NULL) {
fail_msg("Realloc failed. Need to store object handles.\n");
- return -1;
+ goto out;
}
+ object_handles = new_object_handles;
}
object_handles[i++] = object_handle;
}
@@ -458,8 +460,7 @@ int search_objects(test_certs_t *objects, token_info_t *info,
if (rv != CKR_OK) {
fprintf(stderr, "C_FindObjectsFinal: rv = 0x%.8lX\n", rv);
fail_msg("Could not find certificate.\n");
- free(object_handles);
- return -1;
+ goto out;
}
for (i = 0; i < objects_length; i++) {
@@ -476,8 +477,7 @@ int search_objects(test_certs_t *objects, token_info_t *info,
continue;
} else if (rv != CKR_OK) {
fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv);
- free(object_handles);
- return -1;
+ goto out;
}
/* Allocate memory to hold the data we want */
@@ -487,8 +487,7 @@ int search_objects(test_certs_t *objects, token_info_t *info,
template[j].pValue = malloc(template[j].ulValueLen);
if (template[j].pValue == NULL) {
fail_msg("malloc failed");
- free(object_handles);
- return -1;
+ goto out;
}
}
/* Call again to get actual attribute */
@@ -496,8 +495,7 @@ int search_objects(test_certs_t *objects, token_info_t *info,
&(template[j]), 1);
if (rv != CKR_OK) {
fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv);
- free(object_handles);
- return -1;
+ goto out;
}
}
@@ -506,8 +504,10 @@ int search_objects(test_certs_t *objects, token_info_t *info,
for (j = 0; j < template_size; j++)
free(template[j].pValue);
}
+ ret = 0;
+out:
free(object_handles);
- return 0;
+ return ret;
}
void search_for_all_objects(test_certs_t *objects, token_info_t *info)
diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c
index f829332fd8..52b570d9bf 100644
--- a/src/tools/opensc-tool.c
+++ b/src/tools/opensc-tool.c
@@ -594,6 +594,7 @@ static int list_algorithms(void)
{ SC_ALGORITHM_RSA_PAD_PKCS1, "pkcs1" },
{ SC_ALGORITHM_RSA_PAD_ANSI, "ansi" },
{ SC_ALGORITHM_RSA_PAD_PSS, "pss" },
+ { SC_ALGORITHM_RSA_PAD_OAEP, "oaep" },
{ SC_ALGORITHM_RSA_PAD_ISO9796, "iso9796" },
{ SC_ALGORITHM_RSA_HASH_SHA1, "sha1" },
{ SC_ALGORITHM_RSA_HASH_MD5, "MD5" },
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 92c8d8a506..6a8e27ee69 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -2127,9 +2127,15 @@ static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
case CKM_RSA_PKCS_OAEP:
oaep_params.hashAlg = opt_hash_alg;
switch (opt_hash_alg) {
+ case CKM_SHA_1:
+ oaep_params.mgf = CKG_MGF1_SHA1;
+ break;
case CKM_SHA224:
oaep_params.mgf = CKG_MGF1_SHA224;
break;
+ default:
+ oaep_params.hashAlg = CKM_SHA256;
+ /* fall through */
case CKM_SHA256:
oaep_params.mgf = CKG_MGF1_SHA256;
break;
@@ -2139,12 +2145,6 @@ static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
case CKM_SHA512:
oaep_params.mgf = CKG_MGF1_SHA512;
break;
- default:
- oaep_params.hashAlg = CKM_SHA_1;
- /* fall through */
- case CKM_SHA_1:
- oaep_params.mgf = CKG_MGF1_SHA1;
- break;
}
break;
case CKM_RSA_X_509: