Blame SOURCES/opensc-0.19.0-idprime.patch

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