aboutsummaryrefslogtreecommitdiff
path: root/pkcs11.c
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-10-13 08:38:41 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-10-13 08:38:41 +0000
commitce98fd24bd72d479805cb121ca8e118826f1ed76 (patch)
treeb109113870455d2c5595a0833301f234353578e3 /pkcs11.c
parentRenamed plugin to plugins to work around (diff)
downloadopenvpn-ce98fd24bd72d479805cb121ca8e118826f1ed76.tar.xz
Merged PKCS#11 patch.
Pre-2.1_beta3 git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@604 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'pkcs11.c')
-rw-r--r--pkcs11.c2392
1 files changed, 2392 insertions, 0 deletions
diff --git a/pkcs11.c b/pkcs11.c
new file mode 100644
index 0000000..25ad525
--- /dev/null
+++ b/pkcs11.c
@@ -0,0 +1,2392 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * The routines in this file deal with providing private key cryptography
+ * using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+ *
+ */
+
+#if defined(WIN32)
+#include "config-win32.h"
+#else
+#include "config.h"
+#endif
+
+#if defined(USE_CRYPTO) && defined(USE_SSL) && defined(ENABLE_PKCS11)
+
+#include "syshead.h"
+#include "error.h"
+#include "misc.h"
+#include "ssl.h"
+
+#if !defined(IN)
+#define IN
+#endif
+#if !defined(OUT)
+#define OUT
+#endif
+
+#if defined(WIN32)
+#include "cryptoki-win32.h"
+#else
+#include "cryptoki.h"
+#endif
+
+#include "pkcs11.h"
+
+/*===========================================
+ * Constants
+ */
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
+# define RSA_get_default_method RSA_get_default_openssl_method
+#else
+# ifdef HAVE_ENGINE_GET_DEFAULT_RSA
+# include <openssl/engine.h>
+# if OPENSSL_VERSION_NUMBER < 0x0090704fL
+# define BROKEN_OPENSSL_ENGINE
+# endif
+# endif
+#endif
+
+#define PKCS11_MAX_ATTRIBUTE_SIZE (10*1024)
+
+/*===========================================
+ * Types
+ */
+
+typedef struct pkcs11_provider_s {
+ struct pkcs11_provider_s *next;
+
+ bool fEnabled;
+
+#if defined(WIN32)
+ HANDLE hLibrary;
+#else
+ void *hLibrary;
+#endif
+ CK_FUNCTION_LIST_PTR f;
+ bool fShouldFinalize;
+ char *szSignMode;
+} *pkcs11_provider_t;
+
+typedef struct pkcs11_session_s {
+
+ pkcs11_provider_t provider;
+
+ unsigned char *certificate;
+ int certificate_size;
+ unsigned char *certificate_id;
+ int certificate_id_size;
+
+ char *szPIN;
+ bool fLoginFailed;
+
+ CK_SLOT_ID slot;
+ bool fKeySignRecover;
+
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE key;
+} *pkcs11_session_t;
+
+/*===========================================
+ * Low level prototypes
+ */
+
+static
+void
+_fixupFixedString (
+ IN const char * const szSource,
+ OUT char * const szTarget, // MUST BE >= nLength+1
+ IN const int nLength // FIXED STRING LENGTH
+);
+static
+void
+_hexToBinary (
+ IN const char * const szSource,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+);
+static
+CK_RV
+_pkcs11_getSlotById (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szSlot
+);
+static
+CK_RV
+_pkcs11_getSlotByName (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szName
+);
+static
+CK_RV
+_pkcs11_getSlotByLabel (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szLabel
+);
+static
+CK_RV
+_pkcs11_getObjectById (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_OBJECT_CLASS class,
+ IN const unsigned char * const id,
+ IN const int id_size,
+ OUT CK_OBJECT_HANDLE * const handle
+);
+static
+CK_RV
+_pkcs11_loadCertificate (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szIdType,
+ IN const char * const szId
+);
+static
+CK_RV
+_pkcs11_loadKeyProperties (
+ IN const pkcs11_session_t pkcs11_session
+);
+static
+bool
+_isBetterCertificate (
+ IN const unsigned char * const pCurrent,
+ IN const int nCurrentSize,
+ IN const unsigned char * const pNew,
+ IN const int nNewSize
+);
+
+/*=========================================
+ * Simplified functions prototypes
+ */
+
+static
+CK_RV
+pkcs11_addProvider (
+ IN const char * const szProvider,
+ IN const char * const szSignMode
+);
+static
+CK_RV
+pkcs11_finalize ();
+static
+CK_RV
+pkcs11_createSession (
+ IN const char * const szSlotType,
+ IN const char * const szSlot,
+ IN const char * const szIdType,
+ IN const char * const szId,
+ IN const char * const szPIN,
+ IN const bool fProtectedAuthentication,
+ OUT pkcs11_session_t * const pkcs11_session
+);
+static
+CK_RV
+pkcs11_freeSession (
+ IN const pkcs11_session_t pkcs11_session
+);
+static
+CK_RV
+pkcs11_login (
+ IN const pkcs11_session_t pkcs11_session
+);
+static
+CK_RV
+pkcs11_logout (
+ IN const pkcs11_session_t pkcs11_session
+);
+static
+CK_RV
+pkcs11_sign (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+);
+static
+CK_RV
+pkcs11_signRecover (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+);
+static
+CK_RV
+pkcs11_decrypt (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+);
+static
+CK_RV
+pkcs11_getCertificate (
+ IN const pkcs11_session_t pkcs11_session,
+ OUT char * const certificate,
+ IN OUT int * const certificate_size
+);
+static
+char *
+pkcs11_getMessage (
+ IN const int rv
+);
+
+/*==========================================
+ * Static data
+ */
+
+static pkcs11_provider_t pkcs11_provider = NULL;
+
+/*==========================================
+ * Internal utility functions
+ */
+
+static
+void
+_fixupFixedString (
+ IN const char * const szSource,
+ OUT char * const szTarget, // MUST BE >= nLength+1
+ IN const int nLength // FIXED STRING LENGTH
+) {
+ char *p;
+
+ ASSERT (szSource!=NULL);
+ ASSERT (szTarget!=NULL);
+
+ p = szTarget+nLength;
+ memmove (szTarget, szSource, nLength);
+ *p = '\0';
+ p--;
+ while (p >= szTarget && *p == ' ') {
+ *p = '\0';
+ p--;
+ }
+}
+
+static
+void
+_hexToBinary (
+ IN const char * const szSource,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+) {
+ int target_max_size;
+ const char *p;
+ char buf[3] = {'\0', '\0', '\0'};
+ int i = 0;
+
+ ASSERT (szSource!=NULL);
+ ASSERT (target!=NULL);
+ ASSERT (target_size!=NULL);
+
+ target_max_size = *target_size;
+ p = szSource;
+ *target_size = 0;
+
+ while (*p != '\0' && *target_size < target_max_size) {
+ if (isxdigit (*p)) {
+ buf[i%2] = *p;
+
+ if ((i%2) == 1) {
+ int v;
+ sscanf (buf, "%x", &v);
+ target[*target_size] = v & 0xff;
+ (*target_size)++;
+ }
+
+ i++;
+ }
+ p++;
+ }
+}
+
+static
+bool
+_isBetterCertificate (
+ IN const unsigned char * const pCurrent,
+ IN const int nCurrentSize,
+ IN const unsigned char * const pNew,
+ IN const int nNewSize
+) {
+ /*
+ * This function compare the notBefore
+ * and select the most recent certificate
+ * it does not deal with timezones...
+ * When openssl will have ASN1_TIME compare function
+ * it should be used.
+ */
+
+ X509 *x509Current = NULL, *x509New = NULL;
+ char szNotBeforeCurrent[1024], szNotBeforeNew[1024];
+
+ /*
+ * First certificae
+ * always select
+ */
+ if (nCurrentSize == 0) {
+ return true;
+ }
+
+ szNotBeforeCurrent[0] = '\0';
+ szNotBeforeNew[0] = '\0';
+
+ x509Current = X509_new ();
+ x509New = X509_new ();
+
+ if (x509Current != NULL && x509New != NULL) {
+ const unsigned char *p1, *p2;
+
+ p1 = pCurrent;
+ p2 = pNew;
+ if (
+ d2i_X509 (&x509Current, (unsigned char **)&p1, nCurrentSize) &&
+ d2i_X509 (&x509New, (unsigned char **)&p2, nNewSize)
+ ) {
+ ASN1_TIME *notBeforeCurrent = X509_get_notBefore (x509Current);
+ ASN1_TIME *notBeforeNew = X509_get_notBefore (x509New);
+
+ if (
+ notBeforeCurrent != NULL &&
+ notBeforeNew != NULL &&
+ notBeforeCurrent->length < (int) sizeof (szNotBeforeCurrent) - 1 &&
+ notBeforeNew->length < (int) sizeof (szNotBeforeNew) - 1
+ ) {
+ memmove (szNotBeforeCurrent, notBeforeCurrent->data, notBeforeCurrent->length);
+ szNotBeforeCurrent[notBeforeCurrent->length] = '\0';
+ memmove (szNotBeforeNew, notBeforeNew->data, notBeforeNew->length);
+ szNotBeforeNew[notBeforeNew->length] = '\0';
+ }
+ }
+ }
+
+ if (x509Current != NULL) {
+ X509_free (x509Current);
+ x509Current = NULL;
+ }
+ if (x509New != NULL) {
+ X509_free (x509New);
+ x509New = NULL;
+ }
+
+ return strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0;
+}
+
+/*========================================
+ * Low level PKCS#11 functions
+ */
+
+static
+CK_RV
+_pkcs11_getSlotById (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szSlot
+) {
+ pkcs11_provider_t provider;
+ int provider_number;
+ int slot_number;
+ int i;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (szSlot!=NULL);
+
+ if (strchr (szSlot, ':') == NULL) {
+ provider_number = 0;
+ slot_number = atoi (szSlot);
+ }
+ else {
+ sscanf (szSlot, "%d:%d", &provider_number, &slot_number);
+ }
+
+ for (
+ i=0, provider=pkcs11_provider;
+ i < provider_number && provider != NULL;
+ i++, provider = provider->next
+ );
+
+ if (
+ provider == NULL ||
+ (
+ provider != NULL &&
+ !provider->fEnabled
+ )
+ ) {
+ return CKR_SLOT_ID_INVALID;
+ }
+
+ pkcs11_session->provider = provider;
+ pkcs11_session->slot = slot_number;
+ return CKR_OK;
+}
+
+static
+CK_RV
+_pkcs11_getSlotByName (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szName
+) {
+ CK_SLOT_ID slots[1024];
+ CK_ULONG slotnum;
+ CK_SLOT_ID s;
+ CK_RV rv;
+
+ pkcs11_provider_t provider;
+ bool fFound = false;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (szName!=NULL);
+
+ for (
+ provider = pkcs11_provider;
+ (
+ provider != NULL &&
+ !fFound
+ );
+ provider = provider->next
+ ) {
+ if (!provider->fEnabled) {
+ continue;
+ }
+
+ slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+ if (
+ (rv = provider->f->C_GetSlotList (
+ TRUE,
+ slots,
+ &slotnum
+ )) == CKR_OK
+ ) {
+ for (s=0;!fFound && s<slotnum;s++) {
+ CK_SLOT_INFO info;
+
+ if (
+ (rv = provider->f->C_GetSlotInfo (
+ slots[s],
+ &info
+ )) == CKR_OK
+ ) {
+ char szCurrentName[sizeof (info.slotDescription)+1];
+
+ _fixupFixedString (
+ info.slotDescription,
+ szCurrentName,
+ sizeof (info.slotDescription)
+ );
+
+ if (!strcmp (szCurrentName, szName)) {
+ fFound = true;
+ pkcs11_session->provider = provider;
+ pkcs11_session->slot = slots[s];
+ }
+ }
+ }
+ }
+ }
+
+ return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
+}
+
+static
+CK_RV
+_pkcs11_getSlotByLabel (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szLabel
+) {
+ CK_SLOT_ID slots[1024];
+ CK_ULONG slotnum;
+ CK_SLOT_ID s;
+ CK_RV rv;
+
+ pkcs11_provider_t provider;
+ bool fFound = false;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (szLabel!=NULL);
+
+ for (
+ provider = pkcs11_provider;
+ (
+ provider != NULL &&
+ !fFound
+ );
+ provider = provider->next
+ ) {
+ if (!provider->fEnabled) {
+ continue;
+ }
+
+ slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+ if (
+ (rv = provider->f->C_GetSlotList (
+ TRUE,
+ slots,
+ &slotnum
+ )) == CKR_OK
+ ) {
+ for (s=0;!fFound && s<slotnum;s++) {
+ CK_TOKEN_INFO info;
+
+ if (
+ (rv = provider->f->C_GetTokenInfo (
+ slots[s],
+ &info
+ )) == CKR_OK
+ ) {
+ char szCurrentLabel[sizeof (info.label)+1];
+
+ _fixupFixedString (
+ info.label,
+ szCurrentLabel,
+ sizeof (info.label)
+ );
+
+ if (!strcmp (szCurrentLabel, szLabel)) {
+ fFound = true;
+ pkcs11_session->provider = provider;
+ pkcs11_session->slot = slots[s];
+ }
+ }
+ }
+ }
+ }
+
+ return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
+}
+
+static
+CK_RV
+_pkcs11_getObjectById (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_OBJECT_CLASS class,
+ IN const unsigned char * const id,
+ IN const int id_size,
+ OUT CK_OBJECT_HANDLE * const handle
+) {
+ CK_ULONG count;
+ bool fFound = false;
+ CK_RV rv;
+
+ CK_ATTRIBUTE filter[] = {
+ {CKA_CLASS, (void *)&class, sizeof (class)},
+ {CKA_ID, (void *)id, id_size}
+ };
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (id!=NULL);
+ ASSERT (handle!=NULL);
+
+ if (
+ (rv = pkcs11_session->provider->f->C_FindObjectsInit (
+ pkcs11_session->session,
+ filter,
+ sizeof (filter) / sizeof (CK_ATTRIBUTE)
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ if (
+ (rv = pkcs11_session->provider->f->C_FindObjects (
+ pkcs11_session->session,
+ handle,
+ 1,
+ &count
+ )) == CKR_OK
+ ) {
+ if (count > 0) {
+ fFound = true;
+ }
+ }
+
+ pkcs11_session->provider->f->C_FindObjectsFinal (
+ pkcs11_session->session
+ );
+
+ return fFound ? CKR_OK : CKR_FUNCTION_REJECTED;
+}
+
+static
+CK_RV
+_pkcs11_loadCertificate (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const char * const szIdType,
+ IN const char * const szId
+) {
+ CK_OBJECT_HANDLE objects[10];
+ CK_ULONG objects_found;
+ CK_RV rv;
+
+ unsigned char selected_id[PKCS11_MAX_ATTRIBUTE_SIZE];
+ int selected_id_size = 0;
+ unsigned char selected_certificate[PKCS11_MAX_ATTRIBUTE_SIZE];
+ int selected_certificate_size = 0;
+
+ CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+ unsigned char cert_filter_by[PKCS11_MAX_ATTRIBUTE_SIZE];
+ CK_ATTRIBUTE cert_filter[] = {
+ {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
+ {0, cert_filter_by, 0}
+ };
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (szIdType!=NULL);
+ ASSERT (szId!=NULL);
+
+ if (!strcmp (szIdType, "label")) {
+ cert_filter[1].type = CKA_LABEL;
+ cert_filter[1].ulValueLen = (CK_ULONG)(
+ strlen (szId) < sizeof (cert_filter_by) ?
+ strlen (szId) :
+ sizeof (cert_filter_by)
+ );
+ memmove (
+ cert_filter_by,
+ szId,
+ cert_filter[1].ulValueLen
+ );
+ }
+ else if (!strcmp (szIdType, "id")) {
+ int s = sizeof (cert_filter_by);
+
+ cert_filter[1].type = CKA_ID;
+ _hexToBinary (
+ szId,
+ cert_filter_by,
+ &s
+ );
+ cert_filter[1].ulValueLen = s;
+ }
+ else if (!strcmp (szIdType, "subject")) {
+ memmove (&cert_filter[1], &cert_filter[0], sizeof (CK_ATTRIBUTE));
+ }
+ else {
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ if (
+ (rv = pkcs11_session->provider->f->C_FindObjectsInit (
+ pkcs11_session->session,
+ cert_filter,
+ sizeof (cert_filter) / sizeof (CK_ATTRIBUTE)
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ while (
+ (rv = pkcs11_session->provider->f->C_FindObjects (
+ pkcs11_session->session,
+ objects,
+ sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
+ &objects_found
+ )) == CKR_OK &&
+ objects_found > 0
+ ) {
+ CK_ULONG i;
+
+ for (i=0;i<objects_found;i++) {
+ unsigned char attrs_id[PKCS11_MAX_ATTRIBUTE_SIZE];
+ unsigned char attrs_value[PKCS11_MAX_ATTRIBUTE_SIZE];
+ CK_ATTRIBUTE attrs[] = {
+ {CKA_ID, attrs_id, sizeof (attrs_id)},
+ {CKA_VALUE, attrs_value, sizeof (attrs_value)}
+ };
+
+ if (
+ pkcs11_session->provider->f->C_GetAttributeValue (
+ pkcs11_session->session,
+ objects[i],
+ attrs,
+ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+ ) == CKR_OK
+ ) {
+ bool fSelected = false;
+
+ if (!strcmp (szIdType, "subject")) {
+ X509 *x509 = NULL;
+ char szSubject[1024];
+ unsigned char *p;
+
+ x509 = X509_new ();
+
+ p = attrs_value;
+ if (d2i_X509 (&x509, &p, attrs[1].ulValueLen)) {
+ X509_NAME_oneline (
+ X509_get_subject_name (x509),
+ szSubject,
+ sizeof (szSubject)
+ );
+ szSubject[sizeof (szSubject) - 1] = '\0';
+ }
+
+ if (x509 != NULL) {
+ X509_free (x509);
+ x509 = NULL;
+ }
+
+ if (!strcmp (szId, szSubject)) {
+ fSelected = true;
+ }
+ }
+ else {
+ fSelected = true;
+ }
+
+ if (
+ fSelected &&
+ _isBetterCertificate (
+ selected_certificate,
+ selected_certificate_size,
+ attrs_value,
+ attrs[1].ulValueLen
+ )
+ ) {
+ selected_certificate_size = attrs[1].ulValueLen;
+ memmove (
+ selected_certificate,
+ attrs_value,
+ selected_certificate_size
+ );
+ selected_id_size = attrs[0].ulValueLen;
+ memmove (
+ selected_id,
+ attrs_id,
+ selected_id_size
+ );
+ }
+ }
+ }
+ }
+
+ pkcs11_session->provider->f->C_FindObjectsFinal (
+ pkcs11_session->session
+ );
+
+ if (selected_certificate_size == 0) {
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+
+ if ((pkcs11_session->certificate = (unsigned char *)malloc (selected_certificate_size)) == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+ pkcs11_session->certificate_size = selected_certificate_size;
+ memmove (
+ pkcs11_session->certificate,
+ selected_certificate,
+ selected_certificate_size
+ );
+ if ((pkcs11_session->certificate_id = (unsigned char *)malloc (selected_id_size)) == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+ pkcs11_session->certificate_id_size = selected_id_size;
+ memmove (
+ pkcs11_session->certificate_id,
+ selected_id,
+ selected_id_size
+ );
+
+ return CKR_OK;
+}
+
+static
+CK_RV
+_pkcs11_loadKeyProperties (
+ IN const pkcs11_session_t pkcs11_session
+) {
+ CK_OBJECT_HANDLE key;
+ CK_RV rv;
+
+ CK_BBOOL key_attrs_sign_recover;
+ CK_BBOOL key_attrs_sign;
+ CK_ATTRIBUTE key_attrs[] = {
+ {CKA_SIGN, &key_attrs_sign_recover, sizeof (key_attrs_sign_recover)},
+ {CKA_SIGN_RECOVER, &key_attrs_sign, sizeof (key_attrs_sign)}
+ };
+
+ ASSERT (pkcs11_session!=NULL);
+
+ if (!strcmp (pkcs11_session->provider->szSignMode, "recover")) {
+ pkcs11_session->fKeySignRecover = true;
+ }
+ else if (!strcmp (pkcs11_session->provider->szSignMode, "sign")) {
+ pkcs11_session->fKeySignRecover = false;
+ }
+ else {
+ if (
+ (rv = _pkcs11_getObjectById (
+ pkcs11_session,
+ CKO_PRIVATE_KEY,
+ pkcs11_session->certificate_id,
+ pkcs11_session->certificate_id_size,
+ &key
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ if (
+ pkcs11_session->provider->f->C_GetAttributeValue (
+ pkcs11_session->session,
+ key,
+ key_attrs,
+ sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
+ ) == CKR_OK
+ ) {
+ if (key_attrs_sign_recover != CK_FALSE) {
+ pkcs11_session->fKeySignRecover = true;
+ }
+ else if (key_attrs_sign != CK_FALSE) {
+ pkcs11_session->fKeySignRecover = false;
+ }
+ else {
+ return CKR_KEY_TYPE_INCONSISTENT;
+ }
+ }
+
+ }
+
+ return CKR_OK;
+}
+
+/*=======================================
+ * Simplified PKCS#11 functions
+ */
+
+static
+CK_RV
+pkcs11_addProvider (
+ IN const char * const szProvider,
+ IN const char * const szSignMode
+) {
+ pkcs11_provider_t provider = NULL;
+ CK_C_GetFunctionList gfl = NULL;
+ CK_RV rv = CKR_OK;
+
+ ASSERT (szProvider!=NULL);
+
+ if (
+ rv == CKR_OK &&
+ (provider = (pkcs11_provider_t)malloc (sizeof (struct pkcs11_provider_s))) == NULL
+ ) {
+ rv = CKR_HOST_MEMORY;
+ }
+
+ if (rv == CKR_OK) {
+ memset (provider, 0, sizeof (struct pkcs11_provider_s));
+ if (szSignMode == NULL) {
+ provider->szSignMode = strdup ("auto");
+ }
+ else {
+ provider->szSignMode = strdup (szSignMode);
+ }
+ if (provider->szSignMode == NULL) {
+ rv = CKR_HOST_MEMORY;
+ }
+ }
+
+ if (rv == CKR_OK) {
+#if defined(WIN32)
+ provider->hLibrary = LoadLibrary (szProvider);
+#else
+ provider->hLibrary = dlopen (szProvider, RTLD_NOW);
+#endif
+ if (provider->hLibrary == NULL) {
+ rv = CKR_FUNCTION_FAILED;
+ }
+ }
+
+ if (rv == CKR_OK) {
+#if defined(WIN32)
+ gfl = (CK_C_GetFunctionList)GetProcAddress (
+ provider->hLibrary,
+ "C_GetFunctionList"
+ );
+#else
+ gfl = (CK_C_GetFunctionList)dlsym (
+ provider->hLibrary,
+ "C_GetFunctionList"
+ );
+#endif
+ if (gfl == NULL) {
+ rv = CKR_FUNCTION_FAILED;
+ }
+ }
+
+ if (rv == CKR_OK) {
+ rv = gfl (&provider->f);
+ }
+
+ if (rv == CKR_OK) {
+ if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) {
+ if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+ rv = CKR_OK;
+ }
+ }
+ else {
+ provider->fShouldFinalize = true;
+ }
+ }
+
+ if (rv == CKR_OK) {
+ provider->fEnabled = true;
+ }
+
+ if (provider != NULL) {
+ if (pkcs11_provider == NULL) {
+ pkcs11_provider = provider;
+ }
+ else {
+ pkcs11_provider_t last = NULL;
+
+ for (
+ last = pkcs11_provider;
+ last->next != NULL;
+ last = last->next
+ );
+ last->next = provider;
+ }
+ }
+
+ return rv;
+}
+
+static
+CK_RV
+pkcs11_finalize () {
+
+ pkcs11_provider_t last = NULL;
+
+ for (
+ ;
+ pkcs11_provider != NULL;
+ pkcs11_provider = pkcs11_provider->next
+ ) {
+ if (last != NULL) {
+ free (last);
+ }
+ last = pkcs11_provider;
+
+ if (pkcs11_provider->szSignMode != NULL) {
+ free (pkcs11_provider->szSignMode);
+ pkcs11_provider->szSignMode = NULL;
+ }
+
+ if (pkcs11_provider->fShouldFinalize) {
+ pkcs11_provider->f->C_Finalize (NULL);
+ pkcs11_provider->fShouldFinalize = false;
+ }
+
+ if (pkcs11_provider->f != NULL) {
+ pkcs11_provider->f = NULL;
+ }
+
+ if (pkcs11_provider->hLibrary != NULL) {
+#if defined(WIN32)
+ FreeLibrary (pkcs11_provider->hLibrary);
+#else
+ dlclose (pkcs11_provider->hLibrary);
+#endif
+ pkcs11_provider->hLibrary = NULL;
+ }
+ }
+
+ if (last != NULL) {
+ free (last);
+ }
+
+ return CKR_OK;
+}
+
+static
+CK_RV
+pkcs11_createSession (
+ IN const char * const szSlotType,
+ IN const char * const szSlot,
+ IN const char * const szIdType,
+ IN const char * const szId,
+ IN const char * const szPIN,
+ IN const bool fProtectedAuthentication,
+ OUT pkcs11_session_t * const p_pkcs11_session
+) {
+ pkcs11_session_t pkcs11_session;
+ CK_RV rv = CKR_OK;
+
+ ASSERT (szSlotType!=NULL);
+ ASSERT (szSlot!=NULL);
+ ASSERT (szIdType!=NULL);
+ ASSERT (szId!=NULL);
+ ASSERT (szPIN!=NULL);
+ ASSERT (p_pkcs11_session!=NULL);
+
+ if (
+ rv == CKR_OK &&
+ (pkcs11_session = (pkcs11_session_t)malloc (sizeof (struct pkcs11_session_s))) == NULL
+ ) {
+ rv = CKR_HOST_MEMORY;
+ }
+
+ if (rv == CKR_OK) {
+ *p_pkcs11_session = pkcs11_session;
+ memset (pkcs11_session, 0, sizeof (struct pkcs11_session_s));
+ }
+
+ if (
+ rv == CKR_OK &&
+ !fProtectedAuthentication
+ ) {
+ if ((pkcs11_session->szPIN = strdup (szPIN)) == NULL) {
+ rv = CKR_HOST_MEMORY;
+ }
+ }
+
+ if (rv == CKR_OK) {
+ pkcs11_session->fLoginFailed = false;
+ pkcs11_session->key = -1;
+ pkcs11_session->session = -1;
+
+ if (!strcmp (szSlotType, "id")) {
+ rv = _pkcs11_getSlotById (pkcs11_session, szSlot);
+ }
+ else if (!strcmp (szSlotType, "name")) {
+ rv = _pkcs11_getSlotByName (pkcs11_session, szSlot);
+ }
+ else if (!strcmp (szSlotType, "label")) {
+ rv = _pkcs11_getSlotByLabel (pkcs11_session, szSlot);
+ }
+ else {
+ rv = CKR_ARGUMENTS_BAD;
+ }
+ }
+
+ if (rv == CKR_OK) {
+ rv = pkcs11_login (
+ pkcs11_session
+ );
+ }
+
+ if (rv == CKR_OK) {
+ rv = _pkcs11_loadCertificate (
+ pkcs11_session,
+ szIdType,
+ szId
+ );
+ }
+
+ if (rv == CKR_OK) {
+ rv = _pkcs11_loadKeyProperties (
+ pkcs11_session
+ );
+ }
+
+ pkcs11_logout (
+ pkcs11_session
+ );
+
+ return rv;
+}
+
+CK_RV
+pkcs11_freeSession (
+ IN const pkcs11_session_t pkcs11_session
+) {
+ if (pkcs11_session != NULL) {
+ pkcs11_logout (pkcs11_session);
+
+ if (pkcs11_session->szPIN != NULL) {
+ free (pkcs11_session->szPIN);
+ }
+ if (pkcs11_session->certificate != NULL) {
+ free (pkcs11_session->certificate);
+ }
+ if (pkcs11_session->certificate_id != NULL) {
+ free (pkcs11_session->certificate_id);
+ }
+
+ free (pkcs11_session);
+ }
+
+ return CKR_OK;
+}
+
+static
+CK_RV
+pkcs11_login (
+ IN const pkcs11_session_t pkcs11_session
+) {
+ CK_RV rv = CKR_OK;
+
+ ASSERT (pkcs11_session!=NULL);
+
+ pkcs11_logout (pkcs11_session);
+
+ if (rv == CKR_OK) {
+ rv = pkcs11_session->provider->f->C_OpenSession (
+ pkcs11_session->slot,
+ CKF_SERIAL_SESSION,
+ NULL_PTR,
+ NULL_PTR,
+ &pkcs11_session->session
+ );
+ }
+
+ /*
+ * Do not lock the token
+ */
+ if (
+ rv == CKR_OK &&
+ pkcs11_session->fLoginFailed
+ ) {
+ rv = CKR_PIN_INVALID;
+ }
+
+ if (
+ rv == CKR_OK &&
+ (rv = pkcs11_session->provider->f->C_Login (
+ pkcs11_session->session,
+ CKU_USER,
+ pkcs11_session->szPIN,
+ pkcs11_session->szPIN == NULL ? 0 : (CK_ULONG)strlen (pkcs11_session->szPIN)
+ )) != CKR_OK
+ ) {
+ if (rv == CKR_USER_ALREADY_LOGGED_IN) {
+ rv = CKR_OK;
+ }
+ else {
+ pkcs11_session->fLoginFailed = true;
+ }
+ }
+
+ if (
+ rv == CKR_OK &&
+ pkcs11_session->certificate_id != NULL
+ ) {
+ rv = _pkcs11_getObjectById (
+ pkcs11_session,
+ CKO_PRIVATE_KEY,
+ pkcs11_session->certificate_id,
+ pkcs11_session->certificate_id_size,
+ &pkcs11_session->key
+ );
+ }
+
+ if (rv != CKR_OK) {
+ pkcs11_logout (pkcs11_session);
+ }
+
+ return rv;
+}
+
+static
+CK_RV
+pkcs11_logout (
+ IN const pkcs11_session_t pkcs11_session
+) {
+ ASSERT (pkcs11_session!=NULL);
+
+ if (pkcs11_session->session != (unsigned int)-1) {
+ pkcs11_session->provider->f->C_Logout (pkcs11_session->session);
+ pkcs11_session->provider->f->C_CloseSession (pkcs11_session->session);
+ pkcs11_session->key = -1;
+ pkcs11_session->session = -1;
+ }
+
+ return CKR_OK;
+}
+
+static
+CK_RV
+pkcs11_sign (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+) {
+ CK_MECHANISM mech = {
+ mech_type, NULL, 0
+ };
+ CK_ULONG size;
+ CK_RV rv;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (source!=NULL);
+ ASSERT (target_size!=NULL);
+
+ if (
+ (rv = pkcs11_session->provider->f->C_SignInit (
+ pkcs11_session->session,
+ &mech,
+ pkcs11_session->key
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ size = *target_size;
+ rv = pkcs11_session->provider->f->C_Sign (
+ pkcs11_session->session,
+ (CK_BYTE_PTR)source,
+ source_size,
+ (CK_BYTE_PTR)target,
+ &size
+ );
+
+ *target_size = (int)size;
+
+ return rv;
+}
+
+static
+CK_RV
+pkcs11_signRecover (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+) {
+ CK_MECHANISM mech = {
+ mech_type, NULL, 0
+ };
+ CK_ULONG size;
+ CK_RV rv;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (source!=NULL);
+ ASSERT (target_size!=NULL);
+
+ if (
+ (rv = pkcs11_session->provider->f->C_SignRecoverInit (
+ pkcs11_session->session,
+ &mech,
+ pkcs11_session->key
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ size = *target_size;
+ rv = pkcs11_session->provider->f->C_SignRecover (
+ pkcs11_session->session,
+ (CK_BYTE_PTR)source,
+ source_size,
+ (CK_BYTE_PTR)target,
+ &size
+ );
+
+ *target_size = (int)size;
+
+ return rv;
+}
+
+static
+CK_RV
+pkcs11_decrypt (
+ IN const pkcs11_session_t pkcs11_session,
+ IN const CK_MECHANISM_TYPE mech_type,
+ IN const unsigned char * const source,
+ IN const int source_size,
+ OUT unsigned char * const target,
+ IN OUT int * const target_size
+) {
+ CK_MECHANISM mech = {
+ mech_type, NULL, 0
+ };
+ CK_ULONG size;
+ CK_RV rv;
+
+ ASSERT (pkcs11_session!=NULL);
+ ASSERT (source!=NULL);
+ ASSERT (target_size!=NULL);
+
+ if (
+ (rv = pkcs11_session->provider->f->C_DecryptInit (
+ pkcs11_session->session,
+ &mech,
+ pkcs11_session->key
+ )) != CKR_OK
+ ) {
+ return rv;
+ }
+
+ size = *target_size;
+ rv = pkcs11_session->provider->f->C_Decrypt (
+ pkcs11_session->session,
+ (CK_BYTE_PTR)source,
+ source_size,
+ (CK_BYTE_PTR)target,
+ &size
+ );
+
+ *target_size = (int)size;
+
+ return rv;
+}
+
+static
+CK_RV
+pkcs11_getCertificate (
+ IN const pkcs11_session_t pkcs11_session,
+ OUT char * const certificate,
+ IN OUT int * const certificate_size
+) {
+ ASSERT (certificate_size!=NULL);
+
+ *certificate_size = pkcs11_session->certificate_size;
+
+ if (certificate == NULL) {
+ return CKR_OK;
+ }
+
+ if (*certificate_size > pkcs11_session->certificate_size) {
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ memmove (certificate, pkcs11_session->certificate, *certificate_size);
+
+ return CKR_OK;
+}
+
+static
+char *
+pkcs11_getMessage (
+ IN const int rv
+) {
+ switch (rv) {
+ case CKR_OK: return "CKR_OK";
+ case CKR_CANCEL: return "CKR_CANCEL";
+ case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY";
+ case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID";
+ case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR";
+ case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED";
+ case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD";
+ case CKR_NO_EVENT: return "CKR_NO_EVENT";
+ case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS";
+ case CKR_CANT_LOCK: return "CKR_CANT_LOCK";
+ case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY";
+ case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE";
+ case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID";
+ case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID";
+ case CKR_DATA_INVALID: return "CKR_DATA_INVALID";
+ case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE";
+ case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR";
+ case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY";
+ case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED";
+ case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID";
+ case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE";
+ case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED";
+ case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL";
+ case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED";
+ case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID";
+ case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE";
+ case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT";
+ case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED";
+ case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED";
+ case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED";
+ case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE";
+ case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED";
+ case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE";
+ case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE";
+ case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID";
+ case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID";
+ case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID";
+ case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE";
+ case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED";
+ case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT";
+ case CKR_PIN_INVALID: return "CKR_PIN_INVALID";
+ case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE";
+ case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED";
+ case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED";
+ case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED";
+ case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT";
+ case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID";
+ case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
+ case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY";
+ case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS";
+ case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS";
+ case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS";
+ case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID";
+ case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE";
+ case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE";
+ case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT";
+ case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT";
+ case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED";
+ case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED";
+ case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
+ case CKR_UNWRAPPING_KEY_SIZE_RANGE: return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
+ case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
+ case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN";
+ case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN";
+ case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED";
+ case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID";
+ case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
+ case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES";
+ case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID";
+ case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE";
+ case CKR_WRAPPING_KEY_HANDLE_INVALID: return "CKR_WRAPPING_KEY_HANDLE_INVALID";
+ case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE";
+ case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
+ case CKR_RANDOM_SEED_NOT_SUPPORTED: return "CKR_RANDOM_SEED_NOT_SUPPORTED";
+ case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG";
+ case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID";
+ case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL";
+ case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID";
+ case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE";
+ case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE";
+ case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED";
+ case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
+ case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD";
+ case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED";
+ case CKR_FUNCTION_REJECTED: return "CKR_FUNCTION_REJECTED";
+ case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED";
+ default: return "Unknown PKCS#11 error";
+ }
+}
+
+/*==========================================
+ * openvpn interface
+ */
+
+typedef struct openssl_session_s {
+ int (*orig_finish)(RSA *rsa);
+ pkcs11_session_t pkcs11_session;
+} *openssl_session_t;
+
+static
+pkcs11_session_t
+_openssl_get_pkcs11_session (const RSA *rsa) {
+ openssl_session_t session;
+
+ ASSERT (rsa!=NULL);
+ session = (openssl_session_t)RSA_get_app_data (rsa);
+ ASSERT (session!=NULL);
+ ASSERT (session->pkcs11_session!=NULL);
+
+ return session->pkcs11_session;
+}
+
+static
+int
+openssl_pkcs11_priv_enc (
+ int flen,
+ const unsigned char *from,
+ unsigned char *to,
+ RSA *rsa,
+ int padding
+) {
+ msg(M_WARN, "PKCS#11: Private key encryption not supported");
+ return -1;
+}
+
+static
+int
+openssl_pkcs11_priv_dec (
+ int flen, const unsigned char *from,
+ unsigned char *to,
+ RSA *rsa,
+ int padding
+) {
+ pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
+ CK_RV rv = CKR_OK;
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_priv_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
+ flen,
+ from,
+ to,
+ rsa,
+ padding
+ );
+
+ ASSERT (from!=NULL);
+ ASSERT (to!=NULL);
+
+ msg (
+ D_SHOW_PKCS11,
+ "PKCS#11: Performing decryption using private key"
+ );
+
+ if (padding != RSA_PKCS1_PADDING) {
+ rv = CKR_ARGUMENTS_BAD;
+ }
+
+ if (
+ rv == CKR_OK &&
+ (rv = pkcs11_login (pkcs11_session)) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot login to token %ld:'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ rv == CKR_OK &&
+ (rv = pkcs11_decrypt (
+ pkcs11_session,
+ CKM_RSA_PKCS,
+ from,
+ flen,
+ to,
+ &flen
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot decrypt using private key %ld:'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ pkcs11_logout (pkcs11_session);
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_priv_dec - return rv=%ld",
+ rv
+ );
+
+ return rv == CKR_OK ? 1 : -1;
+}
+
+static
+int
+openssl_pkcs11_sign (
+ int type,
+ const unsigned char *m,
+ unsigned int m_len,
+ unsigned char *sigret,
+ unsigned int *siglen,
+ const RSA *rsa
+) {
+ pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
+ CK_RV rv = CKR_OK;
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_priv_sign entered - type=%d, m=%p, m_len=%u, signret=%p, signlen=%p, rsa=%p",
+ type,
+ m,
+ m_len,
+ sigret,
+ siglen,
+ rsa
+ );
+
+ ASSERT (m!=NULL);
+ ASSERT (siglen!=NULL);
+
+ msg (
+ D_SHOW_PKCS11,
+ "PKCS#11: Performing signature"
+ );
+
+ *siglen = RSA_size(rsa);
+
+ if (
+ rv == CKR_OK &&
+ (rv = pkcs11_login (pkcs11_session)) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot login to token %ld:'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ if (rv == CKR_OK) {
+ if (pkcs11_session->fKeySignRecover) {
+ if (
+ (rv = pkcs11_signRecover (
+ pkcs11_session,
+ CKM_RSA_PKCS,
+ m,
+ m_len,
+ sigret,
+ siglen
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11_getMessage (rv));
+ }
+ }
+ else {
+ if (
+ (rv = pkcs11_sign (
+ pkcs11_session,
+ CKM_RSA_PKCS,
+ m,
+ m_len,
+ sigret,
+ siglen
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11_getMessage (rv));
+ }
+ }
+ }
+
+ pkcs11_logout (pkcs11_session);
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_priv_sign - return rv=%ld",
+ rv
+ );
+
+ return rv == CKR_OK ? 1 : -1;
+}
+
+static
+int
+openssl_pkcs11_finish(RSA *rsa) {
+ pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
+ openssl_session_t openssl_session;
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_finish - entered - rsa=%p",
+ rsa
+ );
+
+ openssl_session = (openssl_session_t)RSA_get_app_data (rsa);
+
+ RSA_set_app_data (rsa, NULL);
+ pkcs11_freeSession (pkcs11_session);
+
+ if (openssl_session->orig_finish != NULL) {
+ openssl_session->orig_finish (rsa);
+
+#ifdef BROKEN_OPENSSL_ENGINE
+ {
+ /* We get called TWICE here, once for
+ * releasing the key and also for
+ * releasing the engine.
+ * To prevent endless recursion, FIRST
+ * clear rsa->engine, THEN call engine->finish
+ */
+ ENGINE *e = rsa->engine;
+ rsa->engine = NULL;
+ if (e) {
+ ENGINE_finish(e);
+ }
+ }
+#endif
+ }
+
+ free (openssl_session);
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: openssl_pkcs11_finish - return"
+ );
+
+ return 1;
+}
+
+static RSA_METHOD *
+openssl_pkcs11_get_rsa_method(RSA *rsa)
+{
+ static RSA_METHOD smart_rsa;
+ const RSA_METHOD *def = RSA_get_default_method();
+
+ ASSERT (rsa);
+
+ /* use the OpenSSL version */
+ memmove (&smart_rsa, def, sizeof(smart_rsa));
+
+ /* save original */
+ ((openssl_session_t)RSA_get_app_data (rsa))->orig_finish = def->finish;
+
+ smart_rsa.name = "pkcs11";
+ smart_rsa.rsa_priv_enc = openssl_pkcs11_priv_enc;
+ smart_rsa.rsa_priv_dec = openssl_pkcs11_priv_dec;
+ smart_rsa.rsa_sign = openssl_pkcs11_sign;
+ smart_rsa.finish = openssl_pkcs11_finish;
+ smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY;
+ return &smart_rsa;
+}
+
+
+#ifdef BROKEN_OPENSSL_ENGINE
+static void broken_openssl_init() __attribute__ ((constructor));
+static void broken_openssl_init()
+{
+ SSL_library_init();
+ ENGINE_load_openssl();
+ ENGINE_register_all_RSA();
+}
+#endif
+
+int
+SSL_CTX_use_pkcs11 (
+ IN OUT SSL_CTX * const ssl_ctx,
+ IN const char * const pkcs11_slot_type,
+ IN const char * const pkcs11_slot,
+ IN const char * const pkcs11_id_type,
+ IN const char * const pkcs11_id,
+ IN const char * const pin,
+ IN const bool pkcs11_protected_authentication
+) {
+ X509 *x509 = NULL;
+ RSA *rsa = NULL;
+ EVP_PKEY *pubkey = NULL;
+ openssl_session_t openssl_session = NULL;
+ bool fShouldFreeOpenSSLSession = true;
+ CK_RV rv = CKR_OK;
+
+ unsigned char certificate[10*1024];
+ int certificate_size;
+ unsigned char *p;
+ bool fOK = true;
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_slot_type='%s', pkcs11_slot='%s', pkcs11_id_type='%s', pkcs11_id='%s', pkcs11_protected_authentication=%d",
+ ssl_ctx,
+ pkcs11_slot_type,
+ pkcs11_slot,
+ pkcs11_id_type,
+ pkcs11_id,
+ pkcs11_protected_authentication ? 1 : 0
+ );
+
+ ASSERT (ssl_ctx!=NULL);
+ ASSERT (pkcs11_slot_type!=NULL);
+ ASSERT (pkcs11_slot!=NULL);
+ ASSERT (pkcs11_id_type!=NULL);
+ ASSERT (pkcs11_id!=NULL);
+ if (!pkcs11_protected_authentication) {
+ ASSERT (pin!=NULL);
+ }
+
+ if (
+ fOK &&
+ (openssl_session = (openssl_session_t)malloc (sizeof (struct openssl_session_s))) == NULL
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot allocate memory");
+ }
+
+ if (fOK) {
+ memset (openssl_session, 0, sizeof (struct openssl_session_s));
+ }
+
+ if (
+ fOK &&
+ (rv = pkcs11_createSession (
+ pkcs11_slot_type,
+ pkcs11_slot,
+ pkcs11_id_type,
+ pkcs11_id,
+ pin,
+ pkcs11_protected_authentication,
+ &openssl_session->pkcs11_session
+ )) != CKR_OK
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot set parameters %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ fOK &&
+ (x509 = X509_new ()) == NULL
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Unable to allocate certificate object");
+ }
+
+ certificate_size = sizeof (certificate);
+ if (
+ fOK &&
+ (rv = pkcs11_getCertificate (
+ openssl_session->pkcs11_session,
+ certificate,
+ &certificate_size
+ )) != CKR_OK
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ p = certificate;
+ if (
+ fOK &&
+ !d2i_X509 (&x509, &p, certificate_size)
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Unable to parse X.509 certificate");
+ }
+
+ if (
+ fOK &&
+ (pubkey = X509_get_pubkey (x509)) == NULL
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot get public key");
+ }
+
+ if (
+ fOK &&
+ pubkey->type != EVP_PKEY_RSA
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Invalid public key algorithm");
+ }
+
+ if (
+ fOK &&
+ (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot get RSA key");
+ }
+
+ if (fOK) {
+ RSA_set_app_data (rsa, openssl_session);
+ RSA_set_method (rsa, openssl_pkcs11_get_rsa_method (rsa));
+ rsa->flags |= RSA_FLAG_SIGN_VER;
+
+ // it will be freed when rsa usage count will be zero
+ fShouldFreeOpenSSLSession = false;
+ }
+
+#ifdef BROKEN_OPENSSL_ENGINE
+ if (fOK) {
+ if (!rsa->engine)
+ rsa->engine = ENGINE_get_default_RSA();
+
+ ENGINE_set_RSA(ENGINE_get_default_RSA(), openssl_pkcs11_get_rsa_method(rsa));
+ msg(M_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled");
+ }
+#endif
+
+ if (
+ fOK &&
+ !SSL_CTX_use_certificate (ssl_ctx, x509)
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot set certificate for openssl");
+ }
+
+ if (
+ fOK &&
+ !SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa)
+ ) {
+ fOK = false;
+ msg (M_WARN, "PKCS#11: Cannot set private key for openssl");
+ }
+
+ /*
+ * openssl objects have reference
+ * count, so release them
+ */
+ if (pubkey != NULL) {
+ EVP_PKEY_free (pubkey);
+ pubkey = NULL;
+ }
+
+ if (x509 != NULL) {
+ X509_free (x509);
+ x509 = NULL;
+ }
+
+ if (rsa != NULL) {
+ RSA_free (rsa);
+ rsa = NULL;
+ }
+
+ if (fShouldFreeOpenSSLSession) {
+ if (openssl_session != NULL) {
+ if (openssl_session->pkcs11_session != NULL) {
+ pkcs11_freeSession (openssl_session->pkcs11_session);
+ }
+ free (openssl_session);
+ openssl_session = NULL;
+ }
+ }
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: SSL_CTX_use_pkcs11 - return fOK=%d, rv=%ld",
+ fOK ? 1 : 0,
+ rv
+ );
+
+ return fOK;
+}
+
+void
+add_pkcs11 (
+ IN const char * const provider,
+ IN const char * const sign_mode
+) {
+ CK_RV rv;
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: add_pkcs11 - entered - provider='%s', sign_mode='%s'",
+ provider,
+ sign_mode == NULL ? "default" : sign_mode
+ );
+
+ msg (
+ M_INFO,
+ "PKCS#11: Adding PKCS#11 provider '%s'",
+ provider
+ );
+
+ if ((rv = pkcs11_addProvider (provider, sign_mode)) != CKR_OK) {
+ msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11_getMessage (rv));
+ }
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: add_pkcs11 - return"
+ );
+}
+
+void
+free_pkcs11 () {
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: free_pkcs11 - entered"
+ );
+
+ pkcs11_finalize ();
+
+ msg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: free_pkcs11 - return"
+ );
+}
+
+void
+show_pkcs11_slots (
+ IN const int msglev,
+ IN const int warnlev,
+ IN const char * const provider
+) {
+ CK_INFO info;
+ CK_SLOT_ID slots[1024];
+ CK_ULONG slotnum;
+ CK_SLOT_ID s;
+ CK_RV rv;
+
+ ASSERT (provider!=NULL);
+
+ if (
+ (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ (rv = pkcs11_provider->f->C_GetInfo (&info)) != CKR_OK
+ ) {
+ msg (warnlev, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+ else {
+ char szManufacturerID[sizeof (info.manufacturerID)+1];
+
+ _fixupFixedString (
+ info.manufacturerID,
+ szManufacturerID,
+ sizeof (info.manufacturerID)
+ );
+
+ msg (
+ msglev,
+ (
+ "Provider Information:\n"
+ "\tcryptokiVersion: %u.%u\n"
+ "\tmanufacturerID: %s\n"
+ "\tflags: %d\n"
+ ),
+ info.cryptokiVersion.major,
+ info.cryptokiVersion.minor,
+ szManufacturerID,
+ (unsigned)info.flags
+ );
+ }
+
+ slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+ if (
+ (rv = pkcs11_provider->f->C_GetSlotList (
+ FALSE,
+ slots,
+ &slotnum
+ )) != CKR_OK
+ ) {
+ msg (warnlev, "PKCS#11: Cannot get slot list %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+ else {
+ msg (
+ msglev,
+ (
+ "The following slots are available for use with this provider.\n"
+ "Each slot shown below may be used as a parameter to a\n"
+ "--pkcs11-slot-type and --pkcs11-slot options.\n"
+ "\n"
+ "Slots: (id - name)"
+ )
+ );
+ for (s=0;s<slotnum;s++) {
+ CK_SLOT_INFO info;
+
+ if (
+ (rv = pkcs11_provider->f->C_GetSlotInfo (
+ slots[s],
+ &info
+ )) == CKR_OK
+ ) {
+ char szCurrentName[sizeof (info.slotDescription)+1];
+
+ _fixupFixedString (
+ info.slotDescription,
+ szCurrentName,
+ sizeof (info.slotDescription)
+ );
+
+ msg (msglev, "\t%lu - %s", slots[s], szCurrentName);
+ }
+ }
+ }
+
+ pkcs11_finalize ();
+}
+
+void
+show_pkcs11_objects (
+ IN const int msglev,
+ IN const int warnlev,
+ IN const char * const provider,
+ IN const char * const slot,
+ IN const char * const pin
+) {
+ CK_OBJECT_HANDLE objects[10];
+ CK_SESSION_HANDLE session;
+ CK_ULONG objects_found;
+ CK_TOKEN_INFO info;
+ CK_SLOT_ID s;
+ CK_RV rv;
+
+ ASSERT (provider!=NULL);
+ ASSERT (slot!=NULL);
+ ASSERT (pin!=NULL);
+
+ s = atoi (slot);
+
+ if (
+ (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ (rv = pkcs11_provider->f->C_GetTokenInfo (
+ s,
+ &info
+ )) != CKR_OK
+ ) {
+ msg (warnlev, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
+ }
+ else {
+ char szLabel[sizeof (info.label)+1];
+ char szManufacturerID[sizeof (info.manufacturerID)+1];
+ char szModel[sizeof (info.model)+1];
+ char szSerialNumber[sizeof (info.serialNumber)+1];
+
+ _fixupFixedString (
+ info.label,
+ szLabel,
+ sizeof (info.label)
+ );
+ _fixupFixedString (
+ info.manufacturerID,
+ szManufacturerID,
+ sizeof (info.manufacturerID)
+ );
+ _fixupFixedString (
+ info.model,
+ szModel,
+ sizeof (info.model)
+ );
+ _fixupFixedString (
+ info.serialNumber,
+ szSerialNumber,
+ sizeof (info.serialNumber)
+ );
+
+ msg (
+ msglev,
+ (
+ "Token Information:\n"
+ "\tlabel:\t\t%s\n"
+ "\tmanufacturerID:\t%s\n"
+ "\tmodel:\t\t%s\n"
+ "\tserialNumber:\t%s\n"
+ "\tflags:\t\t%08x\n"
+ "\n"
+ "You can access this token using\n"
+ "--pkcs11-slot-type \"label\" --pkcs11-slot \"%s\" options.\n"
+ ),
+ szLabel,
+ szManufacturerID,
+ szModel,
+ szSerialNumber,
+ (unsigned)info.flags,
+ szLabel
+ );
+ }
+
+ if (
+ (rv = pkcs11_provider->f->C_OpenSession (
+ s,
+ CKF_SERIAL_SESSION,
+ NULL_PTR,
+ NULL_PTR,
+ &session
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot open session to slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ (rv = pkcs11_provider->f->C_Login (
+ session,
+ CKU_USER,
+ (CK_CHAR_PTR)pin,
+ (CK_ULONG)strlen (pin)
+ )) != CKR_OK &&
+ rv != CKR_USER_ALREADY_LOGGED_IN
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot login to token on slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
+ }
+
+ if (
+ (rv = pkcs11_provider->f->C_FindObjectsInit (
+ session,
+ NULL,
+ 0
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot query objects for token on slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
+ }
+
+ msg (
+ msglev,
+ "The following objects are available for use with this token.\n"
+ "Each object shown below may be used as a parameter to\n"
+ "--pkcs11-id-type and --pkcs11-id options.\n"
+ );
+
+ while (
+ (rv = pkcs11_provider->f->C_FindObjects (
+ session,
+ objects,
+ sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
+ &objects_found
+ )) == CKR_OK &&
+ objects_found > 0
+ ) {
+ CK_ULONG i;
+
+ for (i=0;i<objects_found;i++) {
+ CK_OBJECT_CLASS attrs_class;
+ unsigned char attrs_id[PKCS11_MAX_ATTRIBUTE_SIZE];
+ unsigned char attrs_label[PKCS11_MAX_ATTRIBUTE_SIZE];
+ CK_ATTRIBUTE attrs[] = {
+ {CKA_CLASS, &attrs_class, sizeof (attrs_class)},
+ {CKA_ID, attrs_id, sizeof (attrs_id)},
+ {CKA_LABEL, attrs_label, sizeof (attrs_label)-1}
+ };
+
+ if (
+ pkcs11_provider->f->C_GetAttributeValue (
+ session,
+ objects[i],
+ attrs,
+ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+ ) == CKR_OK
+ ) {
+ int id_len = attrs[1].ulValueLen;
+ int j;
+
+ attrs_label[attrs[2].ulValueLen] = 0;
+
+ msg (
+ msglev,
+ (
+ "Object\n"
+ "\tLabel:\t\t%s\n"
+ "\tId:"
+ ),
+ attrs_label
+ );
+
+
+ for (j=0;j<id_len;j+=16) {
+ char szLine[3*16+1];
+ int k;
+
+ szLine[0] = '\0';
+ for (k=0;k<16 && j+k<id_len;k++) {
+ sprintf (szLine+strlen (szLine), "%02x ", attrs_id[j+k]);
+ }
+
+ msg (msglev, "\t\t%s", szLine);
+ }
+
+ if (attrs_class == CKO_CERTIFICATE) {
+ unsigned char certificate[PKCS11_MAX_ATTRIBUTE_SIZE];
+ CK_ATTRIBUTE attrs_cert[] = {
+ {CKA_VALUE, certificate, sizeof (certificate)}
+ };
+
+ msg (msglev, "\tType:\t\tCertificate");
+
+ if (
+ pkcs11_provider->f->C_GetAttributeValue (
+ session,
+ objects[i],
+ attrs_cert,
+ sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
+ ) == CKR_OK
+ ) {
+ X509 *x509 = NULL;
+ BIO *bioSerial = NULL;
+
+ char szSubject[1024];
+ char szSerial[1024];
+ char szNotBefore[1024];
+
+ szSubject[0] = '\0';
+ szSerial[0] = '\0';
+ szNotBefore[0] = '\0';
+
+ if ((x509 = X509_new ()) == NULL) {
+ msg (warnlev, "Cannot create x509 context");
+ }
+ else {
+ unsigned char *p;
+
+ p = certificate;
+ if (d2i_X509 (&x509, &p, attrs_cert[0].ulValueLen)) {
+
+ ASN1_TIME *notBefore = X509_get_notBefore (x509);
+ if (notBefore != NULL && notBefore->length < (int) sizeof (szNotBefore) - 1) {
+ memmove (szNotBefore, notBefore->data, notBefore->length);
+ szNotBefore[notBefore->length] = '\0';
+ }
+
+ X509_NAME_oneline (
+ X509_get_subject_name (x509),
+ szSubject,
+ sizeof (szSubject)
+ );
+ szSubject[sizeof (szSubject) - 1] = '\0';
+ }
+ }
+
+ if ((bioSerial = BIO_new (BIO_s_mem ())) == NULL) {
+ msg (warnlev, "Cannot create BIO context");
+ }
+ else {
+ int n;
+
+ i2a_ASN1_INTEGER(bioSerial, X509_get_serialNumber (x509));
+ n = BIO_read (bioSerial, szSerial, sizeof (szSerial)-1);
+ if (n<0) {
+ szSerial[0] = '\0';
+ }
+ else {
+ szSerial[n] = '\0';
+ }
+ }
+
+
+ if (x509 != NULL) {
+ X509_free (x509);
+ x509 = NULL;
+ }
+ if (bioSerial != NULL) {
+ BIO_free_all (bioSerial);
+ bioSerial = NULL;
+ }
+
+ msg (
+ msglev,
+ (
+ "\tsubject:\t%s\n"
+ "\tserialNumber:\t%s\n"
+ "\tnotBefore:\t%s"
+ ),
+ szSubject,
+ szSerial,
+ szNotBefore
+ );
+ }
+ }
+ else if (attrs_class == CKO_PRIVATE_KEY) {
+ CK_BBOOL sign_recover;
+ CK_BBOOL sign;
+ CK_ATTRIBUTE attrs_key[] = {
+ {CKA_SIGN, &sign_recover, sizeof (sign_recover)},
+ {CKA_SIGN_RECOVER, &sign, sizeof (sign)}
+ };
+
+ msg (msglev, "\tType:\t\tPrivate Key");
+
+ if (
+ pkcs11_provider->f->C_GetAttributeValue (
+ session,
+ objects[i],
+ attrs_key,
+ sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
+ ) == CKR_OK
+ ) {
+ msg (
+ msglev,
+ (
+ "\tSign:\t\t%s\n"
+ "\tSign Recover:\t%s"
+ ),
+ sign ? "TRUE" : "FALSE",
+ sign_recover ? "TRUE" : "FALSE"
+ );
+ }
+ }
+ else {
+ msg (msglev, "\tType:\t\tUnsupported");
+ }
+ }
+ }
+ }
+ pkcs11_provider->f->C_FindObjectsFinal (session);
+ pkcs11_provider->f->C_Logout (session);
+ pkcs11_provider->f->C_CloseSession (session);
+ pkcs11_finalize ();
+}
+
+#else
+static void dummy (void) {}
+#endif /* USE_OPENSC && USE_SSL && USE_CRYPTO */