|
|
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:
|