From 18597b93f7b43f63173f373fbd8548f2d08e25bb Mon Sep 17 00:00:00 2001 From: james Date: Wed, 5 Apr 2006 07:17:02 +0000 Subject: I've recently worked on a better version of pkcs11-helper. I've also merged it into QCA (Qt Cryptographic Architecture), so that KDE 4 will finally be able to use smartcards. The changes allows the following features: 1. Thread safe, is activated if USE_PTHREAD. 2. Slot event - Will allow us in the future to disconnect VPN when smartcard is removed. In order to support this OpenVPN must support threading... At least SIGUSR1 from a different thread. Threading should be supported in both Windows and Linux. -- currently disabled. When I talk about threading support it is just support in configuration script and that the method that SIGUSR1 self can be called from a different thread. I already handle the monitor threads. 3. Certificate enumeration - Will allow us to finally have one configuration file for all users! When you add the plugin GUI stuff you talked about, we will be able to display a list of available certificates for the user to select. -- currently disabled. 4. Data object manipulation - Will allow us to store tls-auth on the smartcard as well. -- currently disabled. 5. Many other minor improvements. Alon Bar-Lev git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@990 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 5 +- openvpn.8 | 101 +- options.c | 70 +- options.h | 6 +- pkcs11-helper-config.h | 67 +- pkcs11-helper.c | 10902 +++++++++++++++++++++++++++++++++++++---------- pkcs11-helper.h | 884 +++- pkcs11.c | 315 +- pkcs11.h | 11 +- ssl.c | 2 +- 10 files changed, 9716 insertions(+), 2647 deletions(-) diff --git a/init.c b/init.c index 589cd03..de0a40b 100644 --- a/init.c +++ b/init.c @@ -140,9 +140,10 @@ context_init_1 (struct context *c) #if defined(ENABLE_PKCS11) if (c->first_time) { int i; - pkcs11_initialize (c->options.pkcs11_pin_cache_period); + pkcs11_initialize (true, c->options.pkcs11_pin_cache_period); for (i=0;ioptions.pkcs11_providers[i] != NULL;i++) - pkcs11_addProvider (c->options.pkcs11_providers[i], c->options.pkcs11_sign_mode[i]); + pkcs11_addProvider (c->options.pkcs11_providers[i], c->options.pkcs11_protected_authentication[i], + c->options.pkcs11_sign_mode[i], c->options.pkcs11_cert_private[i]); } #endif diff --git a/openvpn.8 b/openvpn.8 index e87609d..499d802 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -205,15 +205,15 @@ openvpn \- secure IP tunnel daemon. [\ \fB\-\-ping\-restart\fR\ \fIn\fR\ ] [\ \fB\-\-ping\-timer\-rem\fR\ ] [\ \fB\-\-ping\fR\ \fIn\fR\ ] +[\ \fB\-\-pkcs11\-cert\-private\fR\ \fI[0|1]...\fR\ ] +[\ \fB\-\-pkcs11\-id\fR\ \fIname\fR\ ] +[\ \fB\-\-pkcs11\-id\-type\fR\ \fItype\fR\ ] +[\ \fB\-\-pkcs11\-pin\-cache\fR\ \fIseconds\fR\ ] +[\ \fB\-\-pkcs11\-protected\-authentication\fR\ \fI[0|1]...\fR\ ] [\ \fB\-\-pkcs11\-providers\fR\ \fIprovider...\fR\ ] [\ \fB\-\-pkcs11\-sign\-mode\fR\ \fImode...\fR\ ] -[\ \fB\-\-pkcs11\-slot\-type\fR\ \fItype\fR\ ] [\ \fB\-\-pkcs11\-slot\fR\ \fIname\fR\ ] -[\ \fB\-\-pkcs11\-id\-type\fR\ \fItype\fR\ ] -[\ \fB\-\-pkcs11\-id\fR\ \fIname\fR\ ] -[\ \fB\-\-pkcs11\-pin\-cache\fR\ \fIseconds\fR\ ] -[\ \fB\-\-pkcs11\-protected\-authentication\fR\ ] -[\ \fB\-\-pkcs11\-cert\-private\fR\ ] +[\ \fB\-\-pkcs11\-slot\-type\fR\ \fItype\fR\ ] [\ \fB\-\-pkcs12\fR\ \fIfile\fR\ ] [\ \fB\-\-plugin\fR\ \fImodule\-pathname\ init\-string\fR\ ] [\ \fB\-\-port\fR\ \fIport\fR\ ] @@ -257,8 +257,8 @@ openvpn \- secure IP tunnel daemon. [\ \fB\-\-show\-ciphers\fR\ ] [\ \fB\-\-show\-digests\fR\ ] [\ \fB\-\-show\-engines\fR\ ] -[\ \fB\-\-show\-pkcs11\-slots\fR\ \fIprovider\fR\ ] [\ \fB\-\-show\-pkcs11\-objects\fR\ \fIprovider\ slot\fR\ ] +[\ \fB\-\-show\-pkcs11\-slots\fR\ \fIprovider\fR\ ] [\ \fB\-\-show\-net\-up\fR\ ] [\ \fB\-\-show\-net\fR\ ] [\ \fB\-\-show\-tls\fR\ ] @@ -3620,6 +3620,39 @@ and .B --key. .\"********************************************************* .TP +.B --pkcs11-cert-private [0|1]... +Set if access to certificate object should be performed after login. +Every provider has its own setting. +.\"********************************************************* +.TP +.B --pkcs11-id name +Specify a name of the object to search for. +.\"********************************************************* +.TP +.B --pkcs11-id-type type +Specify how to locate the correct objects. Type can be one of the following: + +.B 'id' +-- Locate by the id attribte, name should be hex encoded string. +.br +.B 'label' +-- Locate by the label attribute, name should be string. +.br +.B 'subject' +-- Locate by certificate subject attribute, name should be string. +.br +.\"********************************************************* +.TP +.B --pkcs11-pin-cache seconds +Specify how many seconds the PIN can be cached, the default is until the token is removed. +.\"********************************************************* +.TP +.B --pkcs11-protected-authentication [0|1]... +Use PKCS#11 protected authentication path, useful for biometric and external +keypad devices. +Every provider has its own setting. +.\"********************************************************* +.TP .B --pkcs11-providers provider... Specify a RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki) providers to load. @@ -3636,21 +3669,30 @@ for each provider. Mode can be one of the following: .B 'auto' (default) -- Try to determind automatically. .br +.B 'sign' +-- Use Sign. +.br .B 'recover' -- Use SignRecover. .br -.B 'sign' --- Use Sign. +.B 'any' +-- Use Sign and if not supported use SignRecover. .br .\"********************************************************* .TP +.B --pkcs11-slot name +Specify a name of the slot to search for. +.\"********************************************************* +.TP .B --pkcs11-slot-type type Specify how to locate the correct slot. Type can be one of the following: .B 'id' --- Locate the slot by a numeric id. The format is [provider:]id, for example, slot 2 of provider 1 -is encoded as 1:2. If you have only one provider you can omit the provider number. -The provider number is set by the order specified in the --pkcs11-providers option. +-- Locate the slot by a numeric id. The format is [provider:]id, for example, slot 2 of provider a.so +should be encoded as a.so:2. If you have only one provider you can omit the provider name. +The provider name is set by the name specified in the +.B --pkcs11-providers +option. .br .B 'name' -- Locate the slot by its name. @@ -3660,41 +3702,6 @@ The provider number is set by the order specified in the --pkcs11-providers opti .br .\"********************************************************* .TP -.B --pkcs11-slot name -Specify a name of the slot to search for. -.\"********************************************************* -.TP -.B --pkcs11-id-type type -Specify how to locate the correct objects. Type can be one of the following: - -.B 'id' --- Locate by the id attribte, name should be hex encoded string. -.br -.B 'label' --- Locate by the label attribute, name should be string. -.br -.B 'subject' --- Locate by certificate subject attribute, name should be string. -.br -.\"********************************************************* -.TP -.B --pkcs11-id name -Specify a name of the object to search for. -.\"********************************************************* -.TP -.B --pkcs11-pin-cache seconds -Specify how many seconds the PIN can be cached, the default is until the token is removed. -.\"********************************************************* -.TP -.B --pkcs11-protected-authentication -Use PKCS#11 protected authentication path, useful for biometric and external -keypad devices. -.\"********************************************************* -.TP -.B --pkcs11-cert-private -Set if access to certificate object should be performed after login. -.\"********************************************************* -.TP .B --cryptoapicert select-string Load the certificate and private key from the Windows Certificate System Store (Windows Only). diff --git a/options.c b/options.c index a889eb5..793ae66 100644 --- a/options.c +++ b/options.c @@ -492,12 +492,19 @@ static const char usage_message[] = "\n" "PKCS#11 Options:\n" "--pkcs11-providers provider ... : PKCS#11 provider to load.\n" + "--pkcs11-protected-authentication [0|1] ... : Use PKCS#11 protected authentication\n" + " path. Set for each provider.\n" "--pkcs11-sign-mode mode ... : PKCS#11 signature method.\n" " auto : Try to determind automatically (default).\n" - " recover : Use SignRecover.\n" " sign : Use Sign.\n" + " recover : Use SignRecover.\n" + " any : Use Sign and then SignRecover.\n" + "--pkcs11-cert-private [0|1] ... : Set if login should be performed before\n" + " certificate can be accessed. Set for each provider.\n" + "--pkcs11-pin-cache seconds : Number of seconds to cache PIN. The default is -1\n" + " cache until token is removed.\n" "--pkcs11-slot-type method : Slot locate method:\n" - " id : By slot id (numeric [prov#:]slot#).\n" + " id : By slot id (numeric [prov:]slot#).\n" " name : By slot name.\n" " label : By the card label that resides in slot.\n" "--pkcs11-slot name : The slot name.\n" @@ -506,11 +513,6 @@ static const char usage_message[] = " label : By the object label (string).\n" " subject : By certificate subject (String).\n" "--pkcs11-id name : The object name.\n" - "--pkcs11-pin-cache seconds : Number of seconds to cache PIN. The default is -1\n" - " cache until token removed.\n" - "--pkcs11-protected-authentication : Use PKCS#11 protected authentication path.\n" - "--pkcs11-cert-private : Set if login should be performed before\n" - " certificate can be accessed.\n" #endif /* ENABLE_PKCS11 */ "\n" "SSL Library information:\n" @@ -688,8 +690,6 @@ init_options (struct options *o) #endif #ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period = -1; - o->pkcs11_protected_authentication = false; - o->pkcs11_cert_private = false; #endif /* ENABLE_PKCS11 */ } @@ -1263,18 +1263,26 @@ show_settings (const struct options *o) for (i=0;ipkcs11_providers[i] != NULL;i++) SHOW_PARM (pkcs11_providers, o->pkcs11_providers[i], "%s"); } + { + int i; + for (i=0;ipkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); + } { int i; for (i=0;ipkcs11_sign_mode[i] != NULL;i++) SHOW_PARM (pkcs11_sign_mode, o->pkcs11_sign_mode[i], "%s"); } + { + int i; + for (i=0;ipkcs11_cert_private[i] ? "ENABLED" : "DISABLED", "%s"); + } + SHOW_INT (pkcs11_pin_cache_period); SHOW_STR (pkcs11_slot_type); SHOW_STR (pkcs11_slot); SHOW_STR (pkcs11_id_type); SHOW_STR (pkcs11_id); - SHOW_INT (pkcs11_pin_cache_period); - SHOW_BOOL (pkcs11_protected_authentication); - SHOW_BOOL (pkcs11_cert_private); #endif /* ENABLE_PKCS11 */ #if P2MP @@ -5080,6 +5088,15 @@ add_option (struct options *options, for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) options->pkcs11_providers[j-1] = p[j]; } + else if (streq (p[0], "pkcs11-protected-authentication")) + { + int j; + + VERIFY_PERMISSION (OPT_P_GENERAL); + + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + options->pkcs11_protected_authentication[j-1] = atoi (p[j]) != 0 ? 1 : 0; + } else if (streq (p[0], "pkcs11-sign-mode") && p[1]) { int j; @@ -5089,6 +5106,20 @@ add_option (struct options *options, for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) options->pkcs11_sign_mode[j-1] = p[j]; } + else if (streq (p[0], "pkcs11-cert-private")) + { + int j; + + VERIFY_PERMISSION (OPT_P_GENERAL); + + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + options->pkcs11_cert_private[j-1] = atoi (p[j]) != 0 ? 1 : 0; + } + else if (streq (p[0], "pkcs11-pin-cache") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_pin_cache_period = atoi (p[1]); + } else if (streq (p[0], "pkcs11-slot-type") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -5109,21 +5140,6 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->pkcs11_id = p[1]; } - else if (streq (p[0], "pkcs11-pin-cache") && p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_pin_cache_period = atoi (p[1]); - } - else if (streq (p[0], "pkcs11-protected-authentication")) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_protected_authentication = true; - } - else if (streq (p[0], "pkcs11-cert-private")) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_cert_private = true; - } #endif #ifdef TUNSETPERSIST else if (streq (p[0], "rmtun")) diff --git a/options.h b/options.h index 4bf1139..4349f7d 100644 --- a/options.h +++ b/options.h @@ -409,13 +409,13 @@ struct options #ifdef ENABLE_PKCS11 const char *pkcs11_providers[MAX_PARMS]; const char *pkcs11_sign_mode[MAX_PARMS]; + bool pkcs11_protected_authentication[MAX_PARMS]; + bool pkcs11_cert_private[MAX_PARMS]; + int pkcs11_pin_cache_period; const char *pkcs11_slot_type; const char *pkcs11_slot; const char *pkcs11_id_type; const char *pkcs11_id; - int pkcs11_pin_cache_period; - bool pkcs11_protected_authentication; - bool pkcs11_cert_private; #endif #ifdef WIN32 diff --git a/pkcs11-helper-config.h b/pkcs11-helper-config.h index f5d4608..d3276ed 100644 --- a/pkcs11-helper-config.h +++ b/pkcs11-helper-config.h @@ -22,10 +22,10 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __PKCS11_HELPER_CONFIG_H -#define __PKCS11_HELPER_CONFIG_H +#ifndef __PKCS11H_HELPER_CONFIG_H +#define __PKCS11H_HELPER_CONFIG_H -#if!defined(PKCS11H_NO_NEED_INCLUDE_CONFIG) +#if !defined(PKCS11H_NO_NEED_INCLUDE_CONFIG) #if defined(WIN32) #include "config-win32.h" @@ -38,33 +38,26 @@ #endif /* PKCS11H_NO_NEED_INCLUDE_CONFIG */ #ifdef ENABLE_PKCS11 -#define PKCS11H_ENABLE_HELPER +#define ENABLE_PKCS11H_HELPER #endif -#ifdef PKCS11H_ENABLE_HELPER +#ifdef ENABLE_PKCS11H_HELPER #include "error.h" #include "misc.h" #include "ssl.h" -#define PKCS11ASSERT ASSERT -#define PKCS11LOG msg -#define PKCS11DLOG dmsg -#define PKCS11_LOG_DEBUG2 D_PKCS11_DEBUG -#define PKCS11_LOG_DEBUG1 D_SHOW_PKCS11 -#define PKCS11_LOG_INFO M_INFO -#define PKCS11_LOG_WARN M_WARN -#define PKCS11_LOG_ERROR M_FATAL +#undef PKCS11H_USE_CYGWIN /* cygwin is not supported in openvpn */ -#undef PKCS11_USE_CYGWIN - -#if !defined(false) -#define false 0 +#if !defined(FALSE) +#define FALSE false #endif -#if !defined(true) -#define true (!false) +#if !defined(TRUE) +#define TRUE true #endif +typedef bool PKCS11H_BOOL; + #if !defined(IN) #define IN #endif @@ -72,18 +65,34 @@ #define OUT #endif -#define PKCS11_PRM_SLOT_TYPE "--pkcs11-slot-type" -#define PKCS11_PRM_SLOT_ID "--pkcs11-slot" -#define PKCS11_PRM_OBJ_TYPE "--pkcs11-id-type" -#define PKCS11_PRM_OBJ_ID "--pkcs11-id" - -#define PKCS11_TIME openvpn_time - -#if defined(WIN32) || defined(PKCS11_USE_CYGWIN) +#ifdef ENABLE_DEBUG +#define ENABLE_PKCS11H_DEBUG +#endif +#ifdef USE_PTHREAD +#define ENABLE_PKCS11H_THREADING +#endif +#undef ENABLE_PKCS11H_TOKEN +#undef ENABLE_PKCS11H_DATA +#define ENABLE_PKCS11H_CERTIFICATE +#define ENABLE_PKCS11H_LOCATE +#undef ENABLE_PKCS11H_ENUM +#undef ENABLE_PKCS11H_SLOTEVENT +#define ENABLE_PKCS11H_OPENSSL +#define ENABLE_PKCS11H_STANDALONE + +#define PKCS11H_PRM_SLOT_TYPE "--pkcs11-slot-type" +#define PKCS11H_PRM_SLOT_ID "--pkcs11-slot" +#define PKCS11H_PRM_OBJ_TYPE "--pkcs11-id-type" +#define PKCS11H_PRM_OBJ_ID "--pkcs11-id" + +#define PKCS11H_ASSERT ASSERT +#define PKCS11H_TIME openvpn_time + +#if defined(WIN32) || defined(PKCS11H_USE_CYGWIN) #include "cryptoki-win32.h" #else #include "cryptoki.h" #endif -#endif /* PKCS11H_ENABLE_HELPER */ -#endif /* __PKCS11_HELPER_CONFIG_H */ +#endif /* PKCS11_ENABLE_HELPER */ +#endif /* __PKCS11H_HELPER_CONFIG_H */ diff --git a/pkcs11-helper.c b/pkcs11-helper.c index 04af86a..111dbdb 100644 --- a/pkcs11-helper.c +++ b/pkcs11-helper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Alon Bar-Lev + * Copyright (c) 2005-2006 Alon Bar-Lev * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifi- @@ -36,7 +36,7 @@ #include "pkcs11-helper-config.h" -#if defined(PKCS11H_ENABLE_HELPER) +#if defined(ENABLE_PKCS11H_HELPER) #include "pkcs11-helper.h" @@ -44,12 +44,6 @@ * Constants */ -#if OPENSSL_VERSION_NUMBER < 0x00908000L -typedef unsigned char *pkcs11_openssl_d2i_t; -#else -typedef const unsigned char *pkcs11_openssl_d2i_t; -#endif - #if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE) # define RSA_get_default_method RSA_get_default_openssl_method #else @@ -65,69 +59,382 @@ typedef const unsigned char *pkcs11_openssl_d2i_t; #define PKCS11H_INVALID_SESSION_HANDLE ((CK_SESSION_HANDLE)-1) #define PKCS11H_INVALID_OBJECT_HANDLE ((CK_OBJECT_HANDLE)-1) +#define PKCS11H_DEFAULT_SLOTEVENT_POLL 5000 +#define PKCS11H_DEFAULT_MAX_LOGIN_RETRY 3 +#define PKCS11H_DEFAULT_PIN_CACHE_PERIOD PKCS11H_PIN_CACHE_INFINITE + +enum _pkcs11h_private_op_e { + _pkcs11h_private_op_sign=0, + _pkcs11h_private_op_sign_recover, + _pkcs11h_private_op_decrypt +}; + +/*=========================================== + * Macros + */ + +#define PKCS11H_MSG_LEVEL_TEST(flags) (((unsigned int)flags) <= s_pkcs11h_loglevel) + +#if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) +# define PKCS11H_LOG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE) +# ifdef ENABLE_PKCS11H_DEBUG +# define PKCS11H_DEBUG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE) +# else +# define PKCS11H_DEBUG(flags, ...) +# endif +#elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__) +# define PKCS11H_LOG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE) +# ifdef ENABLE_PKCS11H_DEBUG +# define PKCS11H_DEBUG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE) +# else +# define PKCS11H_DEBUG(flags, args...) +# endif +#else +# define PKCS11H_LOG _pkcs11h_log +# define PKCS11H_DEBUG _pkcs11h_log +#endif + /*=========================================== - * Low level prototypes + * Types */ +struct pkcs11h_provider_s; +struct pkcs11h_session_s; +struct pkcs11h_data_s; +typedef struct pkcs11h_provider_s *pkcs11h_provider_t; +typedef struct pkcs11h_session_s *pkcs11h_session_t; +typedef struct pkcs11h_data_s *pkcs11h_data_t; + +#if OPENSSL_VERSION_NUMBER < 0x00908000L +typedef unsigned char *pkcs11_openssl_d2i_t; +#else +typedef const unsigned char *pkcs11_openssl_d2i_t; +#endif + +#if defined(ENABLE_PKCS11H_THREADING) + +#define PKCS11H_COND_INFINITE 0xffffffff + +#if defined(WIN32) +#define PKCS11H_THREAD_NULL NULL +typedef HANDLE pkcs11h_cond_t; +typedef HANDLE pkcs11h_mutex_t; +typedef HANDLE pkcs11h_thread_t; +#else +#define PKCS11H_THREAD_NULL 0l +typedef pthread_mutex_t pkcs11h_mutex_t; +typedef pthread_t pkcs11h_thread_t; + +typedef struct { + pthread_cond_t cond; + pthread_mutex_t mut; +} pkcs11h_cond_t; + +typedef struct __pkcs11h_mutex_entry_s { + struct __pkcs11h_mutex_entry_s *next; + pkcs11h_mutex_t *p_mutex; + PKCS11H_BOOL fLocked; +} *__pkcs11h_mutex_entry_t; +#endif + +typedef void * (*pkcs11h_thread_start_t)(void *); + +typedef struct { + pkcs11h_thread_start_t start; + void *data; +} __pkcs11h_thread_data_t; + +#endif /* ENABLE_PKCS11H_THREADING */ + +struct pkcs11h_provider_s { + pkcs11h_provider_t next; + + PKCS11H_BOOL fEnabled; + char szReferenceName[1024]; + char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1]; + +#if defined(WIN32) + HANDLE hLibrary; +#else + void *hLibrary; +#endif + + CK_FUNCTION_LIST_PTR f; + PKCS11H_BOOL fShouldFinalize; + PKCS11H_BOOL fProtectedAuthentication; + PKCS11H_BOOL fCertIsPrivate; + unsigned maskSignMode; + int nSlotEventMethod; + int nSlotEventPollInterval; + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + pkcs11h_thread_t threadSlotEvent; +#endif +}; + +struct pkcs11h_session_s { + pkcs11h_session_t next; + + int nReferenceCount; + PKCS11H_BOOL fValid; + + pkcs11h_provider_t provider; + + pkcs11h_token_id_t token_id; + + CK_SESSION_HANDLE hSession; + + PKCS11H_BOOL fProtectedAuthenticationSupported; + int nPINCachePeriod; + time_t timePINExpire; + +#if defined(ENABLE_PKCS11H_ENUM) +#if defined(ENABLE_PKCS11H_CERTIFICATE) + pkcs11h_certificate_id_list_t cached_certs; + PKCS11H_BOOL fTouch; +#endif +#endif + +#if defined(ENABLE_PKCS11H_THREADING) + pkcs11h_mutex_t mutexSession; +#endif +}; + +#if defined (ENABLE_PKCS11H_CERTIFICATE) + +struct pkcs11h_certificate_s { + + pkcs11h_certificate_id_t id; + int nPINCachePeriod; + + unsigned maskSignMode; + + pkcs11h_session_t session; + CK_OBJECT_HANDLE hKey; + + PKCS11H_BOOL fOperationActive; + +#if defined(ENABLE_PKCS11H_THREADING) + pkcs11h_mutex_t mutexCertificate; +#endif +}; + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +struct pkcs11h_data_s { + PKCS11H_BOOL fInitialized; + int nPINCachePeriod; + + pkcs11h_provider_t providers; + pkcs11h_session_t sessions; + + struct { + void *log_data; + void *slotevent_data; + void *token_prompt_data; + void *pin_prompt_data; + pkcs11h_hook_log_t log; + pkcs11h_hook_slotevent_t slotevent; + pkcs11h_hook_token_prompt_t token_prompt; + pkcs11h_hook_pin_prompt_t pin_prompt; + } hooks; + + PKCS11H_BOOL fProtectedAuthentication; + int nMaxLoginRetries; + +#if defined(ENABLE_PKCS11H_THREADING) + pkcs11h_mutex_t mutexGlobal; + pkcs11h_mutex_t mutexSession; + pkcs11h_mutex_t mutexCache; +#endif + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + PKCS11H_BOOL fSlotEventInitialized; + PKCS11H_BOOL fSlotEventShouldTerminate; + PKCS11H_BOOL fSlotEventSkipEvent; + pkcs11h_cond_t condSlotEvent; + pkcs11h_thread_t threadSlotEvent; +#endif +}; + +#if defined(ENABLE_PKCS11H_OPENSSL) +struct pkcs11h_openssl_session_s { + int nReferenceCount; + PKCS11H_BOOL fInitialized; + X509 *x509; + RSA_METHOD smart_rsa; + int (*orig_finish)(RSA *rsa); + pkcs11h_certificate_t certificate; +}; +#endif + +/*======================================================================* + * MEMORY INTERFACE + *======================================================================*/ + +static +CK_RV +_pkcs11h_malloc ( + OUT const void ** const p, + IN const size_t s +); +static +CK_RV +_pkcs11h_free ( + IN const void ** const p +); +static +CK_RV +_pkcs11h_dupmem ( + OUT const void ** const dest, + OUT size_t * const dest_size, + IN const void * const src, + IN const size_t mem_size +); + +#if defined(ENABLE_PKCS11H_THREADING) +/*======================================================================* + * THREADING INTERFACE + *======================================================================*/ + +static +void +_pkcs11h_sleep ( + IN const unsigned milli +); +static +CK_RV +_pkcs11h_mutexInit ( + OUT pkcs11h_mutex_t * const mutex +); +static +CK_RV +_pkcs11h_mutexLock ( + IN OUT pkcs11h_mutex_t *const mutex +); +static +CK_RV +_pkcs11h_mutexRelease ( + IN OUT pkcs11h_mutex_t *const mutex +); +static +CK_RV +_pkcs11h_mutexFree ( + IN OUT pkcs11h_mutex_t *const mutex +); +#if !defined(WIN32) +static +void +__pkcs1h_mutexLockAll (); +static +void +__pkcs1h_mutexReleaseAll (); +#endif +static +CK_RV +_pkcs11h_condSignal ( + IN OUT pkcs11h_cond_t *const cond +); +static +CK_RV +_pkcs11h_condInit ( + OUT pkcs11h_cond_t * const cond +); +static +CK_RV +_pkcs11h_condWait ( + IN OUT pkcs11h_cond_t *const cond, + IN const unsigned milli +); +static +CK_RV +_pkcs11h_condFree ( + IN OUT pkcs11h_cond_t *const cond +); +static +CK_RV +_pkcs11h_threadStart ( + OUT pkcs11h_thread_t * const thread, + IN pkcs11h_thread_start_t const start, + IN void * data +); +static +CK_RV +_pkcs11h_threadJoin ( + IN pkcs11h_thread_t * const thread +); +#endif /* ENABLE_PKCS11H_THREADING */ + +/*======================================================================* + * COMMON INTERNAL INTERFACE + *======================================================================*/ + static void _pkcs11h_fixupFixedString ( - IN const char * const szSource, OUT char * const szTarget, /* MUST BE >= nLength+1 */ + IN const char * const szSource, IN const size_t nLength /* FIXED STRING LENGTH */ ); static void -_hexToBinary ( - IN const char * const szSource, - OUT unsigned char * const target, - IN OUT size_t * const target_size +_pkcs11h_log ( + IN const unsigned flags, + IN const char * const szFormat, + IN ... +) +#ifdef __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + ; + +static +CK_RV +_pkcs11h_getSlotList ( + IN const pkcs11h_provider_t provider, + IN const CK_BBOOL tokenPresent, + OUT CK_SLOT_ID_PTR * const pSlotList, + OUT CK_ULONG_PTR pulCount ); static -bool -_isBetterCertificate ( - IN const unsigned char * const pCurrent, - IN const size_t nCurrentSize, - IN const unsigned char * const pNew, - IN const size_t nNewSize +CK_RV +_pkcs11h_getObjectAttributes ( + IN const pkcs11h_session_t session, + IN const CK_OBJECT_HANDLE object, + IN OUT const CK_ATTRIBUTE_PTR attrs, + IN const unsigned count ); static CK_RV -_pkcs11h_getSlotById ( - IN const char * const szSlot, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot +_pkcs11h_freeObjectAttributes ( + IN OUT const CK_ATTRIBUTE_PTR attrs, + IN const unsigned count ); static CK_RV -_pkcs11h_getSlotByName ( - IN const char * const szName, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot +_pkcs11h_findObjects ( + IN const pkcs11h_session_t session, + IN const CK_ATTRIBUTE * const filter, + IN const CK_ULONG filter_attrs, + OUT CK_OBJECT_HANDLE **const p_objects, + OUT CK_ULONG *p_objects_found ); static CK_RV -_pkcs11h_getSlotByLabel ( - IN const char * const szLabel, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot +_pkcs11h_getTokenId ( + IN const CK_TOKEN_INFO_PTR info, + OUT pkcs11h_token_id_t * const p_token_id ); static CK_RV -_pkcs11h_getSlot ( - IN const char * const szSlotType, - IN const char * const szSlot, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot +_pkcs11h_newTokenId ( + OUT pkcs11h_token_id_t * const token_id ); static CK_RV -_pkcs11h_getSession ( - IN const char * const szSlotType, - IN const char * const szSlot, - IN const bool fProtectedAuthentication, - IN const int nPINCachePeriod, - OUT pkcs11h_session_t * const session +_pkcs11h_getSessionByTokenId ( + IN const pkcs11h_token_id_t token_id, + OUT pkcs11h_session_t * const p_session ); static CK_RV @@ -138,16 +445,17 @@ static CK_RV _pkcs11h_resetSession ( IN const pkcs11h_session_t session, - OUT CK_SLOT_ID * const slot + IN const unsigned maskPrompt, + OUT CK_SLOT_ID * const p_slot ); static CK_RV _pkcs11h_getObjectById ( - IN const pkcs11h_session_t pkcs11h_certificate, + IN const pkcs11h_session_t certificate, IN const CK_OBJECT_CLASS class, - IN const unsigned char * const id, + IN const CK_BYTE_PTR id, IN const size_t id_size, - OUT CK_OBJECT_HANDLE * const handle + OUT CK_OBJECT_HANDLE * const p_handle ); static CK_RV @@ -158,337 +466,5477 @@ static CK_RV _pkcs11h_login ( IN const pkcs11h_session_t session, - IN const bool fPublicOnly + IN const PKCS11H_BOOL fPublicOnly, + IN const PKCS11H_BOOL fReadOnly, + IN const unsigned maskPrompt ); static CK_RV _pkcs11h_logout ( IN const pkcs11h_session_t session ); + static -CK_RV -_pkcs11h_setCertificateSession_Certificate ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - IN const char * const szIdType, - IN const char * const szId +void +_pkcs11h_hooks_default_log ( + IN const void * pData, + IN const unsigned flags, + IN const char * const szFormat, + IN va_list args ); + static -CK_RV -_pkcs11h_resetCertificateSession ( - IN const pkcs11h_certificate_t pkcs11h_certificate +PKCS11H_BOOL +_pkcs11h_hooks_default_token_prompt ( + IN const void * pData, + IN const pkcs11h_token_id_t token ); + static -CK_RV -_pkcs11h_getCertificateKeyAttributes ( - IN const pkcs11h_certificate_t pkcs11h_certificate +PKCS11H_BOOL +_pkcs11h_hooks_default_pin_prompt ( + IN const void * pData, + IN const pkcs11h_token_id_t token, + OUT char * const szPIN, + IN const size_t nMaxPIN ); -/*========================================== - * openssl interface - */ +#if !defined(WIN32) +#if defined(ENABLE_PKCS11H_THREADING) +static +void +__pkcs11h_atfork_prepare (); +static +void +__pkcs11h_atfork_parent (); +static +void +__pkcs11h_atfork_child (); +#endif +static +CK_RV +_pkcs11h_forkFixup (); +#endif + +#if defined(ENABLE_PKCS11H_CERTIFICATE) +/*======================================================================* + * CERTIFICATE INTERFACE + *======================================================================*/ static -int -_pkcs11h_openssl_finish ( - IN OUT RSA *rsa +void +_pkcs11h_isBetterCertificate_getExpiration ( + IN const unsigned char * const pCertificate, + IN const size_t nCertificateSize, + OUT char * const szNotBefore, + IN const int nNotBeforeSize ); -#if OPENSSL_VERSION_NUMBER < 0x00907000L static -int -_pkcs11h_openssl_dec ( - IN int flen, - IN unsigned char *from, - OUT unsigned char *to, - IN OUT RSA *rsa, - IN int padding +PKCS11H_BOOL +_pkcs11h_isBetterCertificate ( + IN const unsigned char * const pCurrent, + IN const size_t nCurrentSize, + IN const unsigned char * const pNew, + IN const size_t nNewSize ); static -int -_pkcs11h_openssl_sign ( - IN int type, - IN unsigned char *m, - IN unsigned int m_len, - OUT unsigned char *sigret, - OUT unsigned int *siglen, - IN OUT RSA *rsa +CK_RV +_pkcs11h_newCertificateId ( + OUT pkcs11h_certificate_id_t * const certificate_id ); -#else static -int -_pkcs11h_openssl_dec ( - IN int flen, - IN const unsigned char *from, - OUT unsigned char *to, - IN OUT RSA *rsa, - IN int padding +CK_RV +_pkcs11h_loadCertificate ( + IN const pkcs11h_certificate_t certificate ); static -int -_pkcs11h_openssl_sign ( - IN int type, - IN const unsigned char *m, - IN unsigned int m_len, - OUT unsigned char *sigret, - OUT unsigned int *siglen, - IN OUT const RSA *rsa +CK_RV +_pkcs11h_updateCertificateIdDescription ( + IN OUT pkcs11h_certificate_id_t certificate_id ); -#endif static -pkcs11h_openssl_session_t -_pkcs11h_openssl_get_pkcs11h_openssl_session ( - IN OUT const RSA *rsa -); +CK_RV +_pkcs11h_ensureCertificateBlob ( + IN const pkcs11h_certificate_t certificate +); static -pkcs11h_certificate_t -_pkcs11h_openssl_get_pkcs11h_certificate ( - IN OUT const RSA *rsa -); - -/*========================================== - * Static data - */ - -pkcs11h_data_t pkcs11h_data = NULL; +CK_RV +_pkcs11h_getCertificateKeyAttributes ( + IN const pkcs11h_certificate_t certificate +); +static +CK_RV +_pkcs11h_validateCertificateSession ( + IN const pkcs11h_certificate_t certificate +); +static +CK_RV +_pkcs11h_resetCertificateSession ( + IN const pkcs11h_certificate_t certificate, + IN const PKCS11H_BOOL fPublicOnly, + IN const unsigned maskPrompt +); +static +CK_RV +_pkcs11h_certificate_private_op ( + IN const pkcs11h_certificate_t certificate, + IN const enum _pkcs11h_private_op_e op, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size +); +#endif /* ENABLE_PKCS11H_CERTIFICATE */ -/*========================================== - * Internal utility functions - */ +#if defined(ENABLE_PKCS11H_LOCATE) +/*======================================================================* + * LOCATE INTERFACE + *======================================================================*/ static -void -_pkcs11h_fixupFixedString ( - IN const char * const szSource, - OUT char * const szTarget, /* MUST BE >= nLength+1 */ - IN const size_t nLength /* FIXED STRING LENGTH */ -) { - char *p; +CK_RV +_pkcs11h_locate_getTokenIdBySlotId ( + IN const char * const szSlot, + OUT pkcs11h_token_id_t * const p_token_id +); +static +CK_RV +_pkcs11h_locate_getTokenIdBySlotName ( + IN const char * const szName, + OUT pkcs11h_token_id_t * const p_token_id +); +static +CK_RV +_pkcs11h_locate_getTokenIdByLabel ( + IN const char * const szLabel, + OUT pkcs11h_token_id_t * const p_token_id +); + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +static +void +_pkcs11h_locate_hexToBinary ( + OUT unsigned char * const target, + IN const char * const szSource, + IN OUT size_t * const p_target_size +); +static +CK_RV +_pkcs11h_locate_getCertificateIdByLabel ( + IN const pkcs11h_session_t session, + IN OUT const pkcs11h_certificate_id_t certificate_id, + IN const char * const szLabel +); +static +CK_RV +_pkcs11h_locate_getCertificateIdBySubject ( + IN const pkcs11h_session_t session, + IN OUT const pkcs11h_certificate_id_t certificate_id, + IN const char * const szSubject +); + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ +#endif /* ENABLE_PKCS11H_LOCATE */ + +#if defined(ENABLE_PKCS11H_ENUM) +/*======================================================================* + * ENUM INTERFACE + *======================================================================*/ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +static +CK_RV +_pkcs11h_enum_getSessionCertificates ( + IN const pkcs11h_session_t session +); +static +CK_RV +_pkcs11h_enum_splitCertificateIdList ( + IN const pkcs11h_certificate_id_list_t cert_id_all, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list +); + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#endif /* ENABLE_PKCS11H_ENUM */ + +#if defined(ENABLE_PKCS11H_SLOTEVENT) +/*======================================================================* + * SLOTEVENT INTERFACE + *======================================================================*/ + +static +unsigned long +_pkcs11h_slotevent_checksum ( + IN const unsigned char * const p, + IN const size_t s +); +static +void * +_pkcs11h_slotevent_provider ( + IN void *p +); +static +void * +_pkcs11h_slotevent_manager ( + IN void *p +); +static +CK_RV +_pkcs11h_slotevent_init (); +static +CK_RV +_pkcs11h_slotevent_notify (); +static +CK_RV +_pkcs11h_slotevent_terminate (); + +#endif /* ENABLE_PKCS11H_SLOTEVENT */ + +#if defined(ENABLE_PKCS11H_OPENSSL) +/*======================================================================* + * OPENSSL INTERFACE + *======================================================================*/ + +static +int +_pkcs11h_openssl_finish ( + IN OUT RSA *rsa +); +#if OPENSSL_VERSION_NUMBER < 0x00907000L +static +int +_pkcs11h_openssl_dec ( + IN int flen, + IN unsigned char *from, + OUT unsigned char *to, + IN OUT RSA *rsa, + IN int padding +); +static +int +_pkcs11h_openssl_sign ( + IN int type, + IN unsigned char *m, + IN unsigned int m_len, + OUT unsigned char *sigret, + OUT unsigned int *siglen, + IN OUT RSA *rsa +); +#else +static +int +_pkcs11h_openssl_dec ( + IN int flen, + IN const unsigned char *from, + OUT unsigned char *to, + IN OUT RSA *rsa, + IN int padding +); +static +int +_pkcs11h_openssl_sign ( + IN int type, + IN const unsigned char *m, + IN unsigned int m_len, + OUT unsigned char *sigret, + OUT unsigned int *siglen, + IN OUT const RSA *rsa +); +#endif +static +pkcs11h_openssl_session_t +_pkcs11h_openssl_get_openssl_session ( + IN OUT const RSA *rsa +); +static +pkcs11h_certificate_t +_pkcs11h_openssl_get_pkcs11h_certificate ( + IN OUT const RSA *rsa +); +#endif /* ENABLE_PKCS11H_OPENSSL */ + +/*========================================== + * Static data + */ + +#if defined(ENABLE_PKCS11H_THREADING) +#if !defined(WIN32) +static struct { + pkcs11h_mutex_t mutex; + __pkcs11h_mutex_entry_t head; +} __s_pkcs11h_mutex_list = { + PTHREAD_MUTEX_INITIALIZER, + NULL +}; +#endif +#endif + +pkcs11h_data_t s_pkcs11h_data = NULL; +unsigned int s_pkcs11h_loglevel = PKCS11H_LOG_INFO; + +/*======================================================================* + * PUBLIC INTERFACE + *======================================================================*/ + +char * +pkcs11h_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"; + } +} + +CK_RV +pkcs11h_initialize () { + +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_RV rv = CKR_OK; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_initialize entry" + ); + + pkcs11h_terminate (); + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ((void*)&s_pkcs11h_data, sizeof (struct pkcs11h_data_s)); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (rv == CKR_OK) { + rv = _pkcs11h_mutexInit (&s_pkcs11h_data->mutexGlobal); + } + if (rv == CKR_OK) { + rv = _pkcs11h_mutexInit (&s_pkcs11h_data->mutexSession); + } + if (rv == CKR_OK) { + rv = _pkcs11h_mutexInit (&s_pkcs11h_data->mutexCache); + } +#if !defined(WIN32) + if ( + rv == CKR_OK && + pthread_atfork ( + __pkcs11h_atfork_prepare, + __pkcs11h_atfork_parent, + __pkcs11h_atfork_child + ) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + s_pkcs11h_data->nMaxLoginRetries = PKCS11H_DEFAULT_MAX_LOGIN_RETRY; + s_pkcs11h_data->fProtectedAuthentication = TRUE; + s_pkcs11h_data->nPINCachePeriod = PKCS11H_DEFAULT_PIN_CACHE_PERIOD; + s_pkcs11h_data->fInitialized = TRUE; + } + + if (rv == CKR_OK) { + pkcs11h_setLogHook (_pkcs11h_hooks_default_log, NULL); + pkcs11h_setTokenPromptHook (_pkcs11h_hooks_default_token_prompt, NULL); + pkcs11h_setPINPromptHook (_pkcs11h_hooks_default_pin_prompt, NULL); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_initialize return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +pkcs11h_terminate () { + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_terminate entry" + ); + + if (s_pkcs11h_data != NULL) { + pkcs11h_provider_t current_provider = NULL; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Removing providers" + ); + + for ( + current_provider = s_pkcs11h_data->providers; + current_provider != NULL; + current_provider = current_provider->next + ) { + pkcs11h_removeProvider (current_provider->szReferenceName); + } + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexCache); + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexSession); + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal); +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Releasing sessions" + ); + + while (s_pkcs11h_data->sessions != NULL) { + pkcs11h_session_t current = s_pkcs11h_data->sessions; + s_pkcs11h_data->sessions = s_pkcs11h_data->sessions->next; + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexLock (¤t->mutexSession); +#endif + + current->fValid = FALSE; + + if (current->nReferenceCount != 0) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Warning: Found session with references" + ); + } + + if (current->token_id != NULL) { + pkcs11h_freeTokenId (current->token_id); + current->token_id = NULL; + } + +#if defined(ENABLE_PKCS11H_ENUM) +#if defined(ENABLE_PKCS11H_CERTIFICATE) + pkcs11h_freeCertificateIdList (current->cached_certs); +#endif +#endif + + current->provider = NULL; + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexFree (¤t->mutexSession); +#endif + + _pkcs11h_free ((void *)¤t); + } + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Terminating slotevent" + ); + + _pkcs11h_slotevent_terminate (); +#endif + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Marking as uninitialized" + ); + + s_pkcs11h_data->fInitialized = FALSE; + + while (s_pkcs11h_data->providers != NULL) { + pkcs11h_provider_t current = s_pkcs11h_data->providers; + s_pkcs11h_data->providers = s_pkcs11h_data->providers->next; + + _pkcs11h_free ((void *)¤t); + } + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexFree (&s_pkcs11h_data->mutexCache); + _pkcs11h_mutexFree (&s_pkcs11h_data->mutexGlobal); + _pkcs11h_mutexFree (&s_pkcs11h_data->mutexSession); +#endif + + _pkcs11h_free ((void *)&s_pkcs11h_data); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_terminate return" + ); + + return CKR_OK; +} + +void +pkcs11h_setLogLevel ( + IN const unsigned flags +) { + s_pkcs11h_loglevel = flags; +} + +unsigned +pkcs11h_getLogLevel () { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + + return s_pkcs11h_loglevel; +} + +CK_RV +pkcs11h_setLogHook ( + IN const pkcs11h_hook_log_t hook, + IN void * const pData +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (hook!=NULL); + + s_pkcs11h_data->hooks.log = hook; + s_pkcs11h_data->hooks.log_data = pData; + + return CKR_OK; +} + +CK_RV +pkcs11h_setSlotEventHook ( + IN const pkcs11h_hook_slotevent_t hook, + IN void * const pData +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (hook!=NULL); + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + s_pkcs11h_data->hooks.slotevent = hook; + s_pkcs11h_data->hooks.slotevent_data = pData; + + return _pkcs11h_slotevent_init (); +#else + return CKR_FUNCTION_NOT_SUPPORTED; +#endif +} + +CK_RV +pkcs11h_setPINPromptHook ( + IN const pkcs11h_hook_pin_prompt_t hook, + IN void * const pData +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (hook!=NULL); + + s_pkcs11h_data->hooks.pin_prompt = hook; + s_pkcs11h_data->hooks.pin_prompt_data = pData; + + return CKR_OK; +} + +CK_RV +pkcs11h_setTokenPromptHook ( + IN const pkcs11h_hook_token_prompt_t hook, + IN void * const pData +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (hook!=NULL); + + s_pkcs11h_data->hooks.token_prompt = hook; + s_pkcs11h_data->hooks.token_prompt_data = pData; + + return CKR_OK; +} + +CK_RV +pkcs11h_setPINCachePeriod ( + IN const int nPINCachePeriod +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + + s_pkcs11h_data->nPINCachePeriod = nPINCachePeriod; + + return CKR_OK; +} + +CK_RV +pkcs11h_setMaxLoginRetries ( + IN const int nMaxLoginRetries +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + + s_pkcs11h_data->nMaxLoginRetries = nMaxLoginRetries; + + return CKR_OK; +} + +CK_RV +pkcs11h_setProtectedAuthentication ( + IN const PKCS11H_BOOL fProtectedAuthentication +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + + s_pkcs11h_data->fProtectedAuthentication = fProtectedAuthentication; + + return CKR_OK; +} + +CK_RV +pkcs11h_addProvider ( + IN const char * const szReferenceName, + IN const char * const szProvider, + IN const PKCS11H_BOOL fProtectedAuthentication, + IN const unsigned maskSignMode, + IN const int nSlotEventMethod, + IN const int nSlotEventPollInterval, + IN const PKCS11H_BOOL fCertIsPrivate +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif +#if defined(WIN32) + int mypid = 0; +#else + pid_t mypid = getpid (); +#endif + pkcs11h_provider_t provider = NULL; + CK_C_GetFunctionList gfl = NULL; + CK_INFO info; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (szProvider!=NULL); + /*PKCS11H_ASSERT (szSignMode!=NULL); NOT NEEDED*/ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_addProvider entry pid=%d, szReferenceName=%s, szProvider='%s', fProtectedAuthentication=%d, maskSignMode=%08x, fCertIsPrivate=%d", + mypid, + szReferenceName, + szProvider, + fProtectedAuthentication ? 1 : 0, + maskSignMode, + fCertIsPrivate ? 1 : 0 + ); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Adding provider '%s'-'%s'", + szReferenceName, + szProvider + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ((void *)&provider, sizeof (struct pkcs11h_provider_s))) == CKR_OK + ) { + strncpy ( + provider->szReferenceName, + szReferenceName, + sizeof (provider->szReferenceName)-1 + ); + provider->szReferenceName[sizeof (provider->szReferenceName)-1] = '\x0'; + strncpy ( + provider->manufacturerID, + ( + strlen (szProvider) < sizeof (provider->manufacturerID) ? + szProvider : + szProvider+strlen (szProvider)-sizeof (provider->manufacturerID)+1 + ), + sizeof (provider->manufacturerID)-1 + ); + provider->manufacturerID[sizeof (provider->manufacturerID)-1] = '\x0'; + provider->fProtectedAuthentication = fProtectedAuthentication; + provider->maskSignMode = maskSignMode; + provider->nSlotEventMethod = nSlotEventMethod; + provider->nSlotEventPollInterval = nSlotEventPollInterval; + provider->fCertIsPrivate = fCertIsPrivate; + } + + if (rv == CKR_OK) { +#if defined(WIN32) + provider->hLibrary = LoadLibraryA (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 + /* + * Make compiler happy! + */ + void *p = dlsym ( + provider->hLibrary, + "C_GetFunctionList" + ); + memmove ( + &gfl, + &p, + sizeof (void *) + ); +#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 && + (rv = provider->f->C_GetInfo (&info)) == CKR_OK + ) { + _pkcs11h_fixupFixedString ( + provider->manufacturerID, + (char *)info.manufacturerID, + sizeof (info.manufacturerID) + ); + } + + if (rv == CKR_OK) { + provider->fEnabled = TRUE; + } + + if (provider != NULL) { + if (s_pkcs11h_data->providers == NULL) { + s_pkcs11h_data->providers = provider; + } + else { + pkcs11h_provider_t last = NULL; + + for ( + last = s_pkcs11h_data->providers; + last->next != NULL; + last = last->next + ); + last->next = provider; + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; + } +#endif + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + _pkcs11h_slotevent_notify (); +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Provider '%s' added rv=%ld-'%s'", + szReferenceName, + rv, + pkcs11h_getMessage (rv) + ); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +pkcs11h_removeProvider ( + IN const char * const szReferenceName +) { +#if defined(ENABLE_PKCS11H_THREADING) + pkcs11h_session_t current_session = NULL; +#endif + pkcs11h_provider_t provider = NULL; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (szReferenceName!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_removeProvider entry szReferenceName='%s'", + szReferenceName + ); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Removing provider '%s'", + szReferenceName + ); + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexCache); + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexSession); + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal); + + for ( + current_session = s_pkcs11h_data->sessions; + current_session != NULL; + current_session = current_session->next + ) { + _pkcs11h_mutexLock (¤t_session->mutexSession); + } +#endif + + provider = s_pkcs11h_data->providers; + while ( + rv == CKR_OK && + provider != NULL && + strcmp (szReferenceName, provider->szReferenceName) + ) { + provider = provider->next; + } + + if (rv == CKR_OK && provider == NULL) { + rv = CKR_OBJECT_HANDLE_INVALID; + } + + if (rv == CKR_OK) { + provider->fEnabled = FALSE; + provider->szReferenceName[0] = '\0'; + + if (provider->fShouldFinalize) { + provider->f->C_Finalize (NULL); + provider->fShouldFinalize = FALSE; + } + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + _pkcs11h_slotevent_notify (); + + /* + * Wait until manager join this thread + * this happens saldom so I can poll + */ + while (provider->threadSlotEvent != PKCS11H_THREAD_NULL) { + _pkcs11h_sleep (500); + } +#endif + + if (provider->f != NULL) { + provider->f = NULL; + } + + if (provider->hLibrary != NULL) { +#if defined(WIN32) + FreeLibrary (provider->hLibrary); +#else + dlclose (provider->hLibrary); +#endif + provider->hLibrary = NULL; + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + for ( + current_session = s_pkcs11h_data->sessions; + current_session != NULL; + current_session = current_session->next + ) { + _pkcs11h_mutexRelease (¤t_session->mutexSession); + } + + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexCache); + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexSession); + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_removeProvider return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +pkcs11h_forkFixup () { +#if defined(WIN32) + return CKR_OK; +#else +#if defined(ENABLE_PKCS11H_THREADING) + return CKR_OK; +#else + return _pkcs11h_forkFixup (); +#endif +#endif +} + +CK_RV +pkcs11h_plugAndPlay () { +#if defined(WIN32) + int mypid = 0; +#else + pid_t mypid = getpid (); +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_forkFixup entry pid=%d", + mypid + ); + + if (s_pkcs11h_data != NULL && s_pkcs11h_data->fInitialized) { + pkcs11h_provider_t current; +#if defined(ENABLE_PKCS11H_SLOTEVENT) + PKCS11H_BOOL fSlotEventActive = FALSE; +#endif + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal); +#endif + for ( + current = s_pkcs11h_data->providers; + current != NULL; + current = current->next + ) { + if (current->fEnabled) { + current->f->C_Finalize (NULL); + } + } + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + if (s_pkcs11h_data->fSlotEventInitialized) { + fSlotEventActive = TRUE; + _pkcs11h_slotevent_terminate (); + } +#endif + + for ( + current = s_pkcs11h_data->providers; + current != NULL; + current = current->next + ) { + if (current->fEnabled) { + current->f->C_Initialize (NULL); + } + } + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + if (fSlotEventActive) { + _pkcs11h_slotevent_init (); + } +#endif + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); +#endif + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_forkFixup return" + ); + + return CKR_OK; +} + +CK_RV +pkcs11h_freeTokenId ( + IN pkcs11h_token_id_t token_id +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeTokenId entry certificate_id=%p", + (void *)token_id + ); + + _pkcs11h_free ((void *)&token_id); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeTokenId return" + ); + + return CKR_OK; +} + +CK_RV +pkcs11h_duplicateTokenId ( + OUT pkcs11h_token_id_t * const to, + IN const pkcs11h_token_id_t from +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (to!=NULL); + PKCS11H_ASSERT (from!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_duplicateTokenId entry to=%p form=%p", + (void *)to, + (void *)from + ); + + *to = NULL; + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)to, + NULL, + from, + sizeof (struct pkcs11h_token_id_s) + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_duplicateTokenId return rv=%ld-'%s', *to=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*to + ); + + return rv; +} + +PKCS11H_BOOL +pkcs11h_sameTokenId ( + IN const pkcs11h_token_id_t a, + IN const pkcs11h_token_id_t b +) { + PKCS11H_ASSERT (a!=NULL); + PKCS11H_ASSERT (b!=NULL); + + return ( + !strcmp (a->manufacturerID, b->manufacturerID) && + !strcmp (a->model, b->model) && + !strcmp (a->serialNumber, b->serialNumber) + ); +} + +/*======================================================================* + * MEMORY INTERFACE + *======================================================================*/ + +static +CK_RV +_pkcs11h_malloc ( + OUT const void ** const p, + IN const size_t s +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (p!=NULL); + PKCS11H_ASSERT (s!=0); + + *p = NULL; + + if (s > 0) { + if ( + (*p = (void *)malloc (s)) == NULL + ) { + rv = CKR_HOST_MEMORY; + } + else { + memset ((void *)*p, 0, s); + } + } + + return rv; +} + +static +CK_RV +_pkcs11h_free ( + IN const void ** const p +) { + PKCS11H_ASSERT (p!=NULL); + + free ((void *)*p); + *p = NULL; + + return CKR_OK; +} + +static +CK_RV +_pkcs11h_dupmem ( + OUT const void ** const dest, + OUT size_t * const p_dest_size, + IN const void * const src, + IN const size_t mem_size +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (dest!=NULL); + /*PKCS11H_ASSERT (dest_size!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (!(mem_size!=0&&src==NULL)); + + *dest = NULL; + if (p_dest_size != NULL) { + *p_dest_size = 0; + } + + if (src != NULL) { + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc (dest, mem_size)) == CKR_OK + ) { + if (p_dest_size != NULL) { + *p_dest_size = mem_size; + } + memmove ((void*)*dest, src, mem_size); + } + } + + return rv; +} + +#if defined(ENABLE_PKCS11H_THREADING) +/*======================================================================* + * THREADING INTERFACE + *======================================================================*/ + +static +void +_pkcs11h_sleep ( + IN const unsigned milli +) { +#if defined(WIN32) + Sleep (milli); +#else + usleep (milli*1000); +#endif +} + +static +CK_RV +_pkcs11h_mutexInit ( + OUT pkcs11h_mutex_t * const mutex +) { + CK_RV rv = CKR_OK; +#if defined(WIN32) + if ( + rv == CKR_OK && + (*mutex = CreateMutex (NULL, FALSE, NULL)) == NULL + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + { + __pkcs11h_mutex_entry_t entry = NULL; + PKCS11H_BOOL fMutexLocked = FALSE; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex)) == CKR_OK + ) { + fMutexLocked = TRUE; + } + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ( + (void *)&entry, + sizeof (struct __pkcs11h_mutex_entry_s) + ); + } + + if ( + rv == CKR_OK && + pthread_mutex_init (mutex, NULL) + ) { + rv = CKR_FUNCTION_FAILED; + } + + if (rv == CKR_OK) { + entry->p_mutex = mutex; + entry->next = __s_pkcs11h_mutex_list.head; + __s_pkcs11h_mutex_list.head = entry; + entry = NULL; + } + + if (entry != NULL) { + _pkcs11h_free ((void *)&entry); + } + + if (fMutexLocked) { + _pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex); + fMutexLocked = FALSE; + } + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_mutexLock ( + IN OUT pkcs11h_mutex_t *const mutex +) { + CK_RV rv = CKR_OK; +#if defined(WIN32) + if ( + rv == CKR_OK && + WaitForSingleObject (*mutex, INFINITE) == WAIT_FAILED + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + if ( + rv == CKR_OK && + pthread_mutex_lock (mutex) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_mutexRelease ( + IN OUT pkcs11h_mutex_t *const mutex +) { + CK_RV rv = CKR_OK; +#if defined(WIN32) + if ( + rv == CKR_OK && + !ReleaseMutex (*mutex) + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + if ( + rv == CKR_OK && + pthread_mutex_unlock (mutex) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_mutexFree ( + IN OUT pkcs11h_mutex_t *const mutex +) { +#if defined(WIN32) + if (*mutex != NULL) { + CloseHandle (*mutex); + *mutex = NULL; + } +#else + { + __pkcs11h_mutex_entry_t last = NULL; + __pkcs11h_mutex_entry_t entry = NULL; + PKCS11H_BOOL fMutexLocked = FALSE; + + if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) { + fMutexLocked = TRUE; + } + + entry = __s_pkcs11h_mutex_list.head; + while ( + entry != NULL && + entry->p_mutex != mutex + ) { + last = entry; + entry = entry->next; + } + + if (entry != NULL) { + if (last == NULL) { + __s_pkcs11h_mutex_list.head = entry->next; + } + else { + last->next = entry->next; + } + _pkcs11h_free ((void *)&entry); + } + + pthread_mutex_destroy (mutex); + + if (fMutexLocked) { + _pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex); + fMutexLocked = FALSE; + } + } +#endif + return CKR_OK; +} + +#if !defined(WIN32) +/* + * This function is required in order + * to lock all mutexes before fork is called, + * and to avoid dedlocks. + * The loop is required because there is no + * way to lock all mutex in one system call... + */ +static +void +__pkcs1h_mutexLockAll () { + __pkcs11h_mutex_entry_t entry = NULL; + PKCS11H_BOOL fMutexLocked = FALSE; + PKCS11H_BOOL fAllLocked = FALSE; + + if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) { + fMutexLocked = TRUE; + } + + for ( + entry = __s_pkcs11h_mutex_list.head; + entry != NULL; + entry = entry->next + ) { + entry->fLocked = FALSE; + } + + while (!fAllLocked) { + PKCS11H_BOOL fOK = TRUE; + + for ( + entry = __s_pkcs11h_mutex_list.head; + entry != NULL && fOK; + entry = entry->next + ) { + if (!pthread_mutex_trylock (entry->p_mutex)) { + entry->fLocked = TRUE; + } + else { + fOK = FALSE; + } + } + + if (!fOK) { + for ( + entry = __s_pkcs11h_mutex_list.head; + entry != NULL; + entry = entry->next + ) { + if (entry->fLocked == TRUE) { + pthread_mutex_unlock (entry->p_mutex); + entry->fLocked = FALSE; + } + } + + _pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex); + _pkcs11h_sleep (1000); + _pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex); + } + else { + fAllLocked = TRUE; + } + } + + if (fMutexLocked) { + _pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex); + fMutexLocked = FALSE; + } +} + +static +void +__pkcs1h_mutexReleaseAll () { + __pkcs11h_mutex_entry_t entry = NULL; + PKCS11H_BOOL fMutexLocked = FALSE; + + if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) { + fMutexLocked = TRUE; + } + + for ( + entry = __s_pkcs11h_mutex_list.head; + entry != NULL; + entry = entry->next + ) { + pthread_mutex_unlock (entry->p_mutex); + entry->fLocked = FALSE; + } + + if (fMutexLocked) { + _pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex); + fMutexLocked = FALSE; + } +} +#endif + +CK_RV +_pkcs11h_condSignal ( + IN OUT pkcs11h_cond_t *const cond +) { + CK_RV rv = CKR_OK; +#if defined(WIN32) + if ( + rv == CKR_OK && + !SetEvent (*cond) + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + if ( + rv == CKR_OK && + ( + pthread_mutex_lock (&cond->mut) || + pthread_cond_signal (&cond->cond) || + pthread_mutex_unlock (&cond->mut) + ) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + + return rv; +} + +static +CK_RV +_pkcs11h_condInit ( + OUT pkcs11h_cond_t * const cond +) { + CK_RV rv = CKR_OK; +#if defined(WIN32) + if ( + rv == CKR_OK && + (*cond = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + if ( + rv == CKR_OK && + ( + pthread_mutex_init (&cond->mut, NULL) || + pthread_cond_init (&cond->cond, NULL) || + pthread_mutex_lock (&cond->mut) + ) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_condWait ( + IN OUT pkcs11h_cond_t *const cond, + IN const unsigned milli +) { + CK_RV rv = CKR_OK; + +#if defined(WIN32) + DWORD dwMilli; + + if (milli == PKCS11H_COND_INFINITE) { + dwMilli = INFINITE; + } + else { + dwMilli = milli; + } + + if ( + rv == CKR_OK && + WaitForSingleObject (*cond, dwMilli) == WAIT_FAILED + ) { + rv = CKR_FUNCTION_FAILED; + } +#else + if (milli == PKCS11H_COND_INFINITE) { + if ( + rv == CKR_OK && + pthread_cond_wait (&cond->cond, &cond->mut) + ) { + rv = CKR_FUNCTION_FAILED; + } + } + else { + struct timeval now; + struct timespec timeout; + + if ( + rv == CKR_OK && + gettimeofday (&now, NULL) + ) { + rv = CKR_FUNCTION_FAILED; + } + + if (rv == CKR_OK) { + timeout.tv_sec = now.tv_sec + milli/1000; + timeout.tv_nsec = now.tv_usec*1000 + milli%1000; + } + + if ( + rv == CKR_OK && + pthread_cond_timedwait (&cond->cond, &cond->mut, &timeout) + ) { + rv = CKR_FUNCTION_FAILED; + } + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_condFree ( + IN OUT pkcs11h_cond_t *const cond +) { +#if defined(WIN32) + CloseHandle (*cond); + *cond = NULL; +#else + pthread_mutex_unlock (&cond->mut); +#endif + return CKR_OK; +} + +#if defined(WIN32) +static +unsigned +__stdcall +__pkcs11h_thread_start (void *p) { + __pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p; + unsigned ret; + + ret = (unsigned)_data->start (_data->data); + + _pkcs11h_free ((void *)&_data); + + return ret; +} +#else +static +void * +__pkcs11h_thread_start (void *p) { + __pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p; + void *ret; + int i; + + /* + * Ignore any signal in + * this thread + */ + for (i=1;i<16;i++) { + signal (i, SIG_IGN); + } + + ret = _data->start (_data->data); + + _pkcs11h_free ((void *)&_data); + + return ret; +} +#endif + +static +CK_RV +_pkcs11h_threadStart ( + OUT pkcs11h_thread_t * const thread, + IN pkcs11h_thread_start_t const start, + IN void * data +) { + __pkcs11h_thread_data_t *_data = NULL; + CK_RV rv = CKR_OK; + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ( + (void *)&_data, + sizeof (__pkcs11h_thread_data_t) + ); + } + + if (rv == CKR_OK) { + _data->start = start; + _data->data = data; + } + +#if defined(WIN32) + { + unsigned tmp; + + if ( + rv == CKR_OK && + (*thread = (HANDLE)_beginthreadex ( + NULL, + 0, + __pkcs11h_thread_start, + _data, + 0, + &tmp + )) == NULL + ) { + rv = CKR_FUNCTION_FAILED; + } + } +#else + if ( + rv == CKR_OK && + pthread_create (thread, NULL, __pkcs11h_thread_start, _data) + ) { + rv = CKR_FUNCTION_FAILED; + } +#endif + return rv; +} + +static +CK_RV +_pkcs11h_threadJoin ( + IN pkcs11h_thread_t * const thread +) { +#if defined(WIN32) + WaitForSingleObject (*thread, INFINITE); + CloseHandle (*thread); + *thread = NULL; +#else + pthread_join (*thread, NULL); + *thread = 0l; +#endif + return CKR_OK; +} + +#endif /* ENABLE_PKCS11H_THREADING */ + +/*======================================================================* + * COMMON INTERNAL INTERFACE + *======================================================================*/ + +static +void +_pkcs11h_fixupFixedString ( + OUT char * const szTarget, /* MUST BE >= nLength+1 */ + IN const char * const szSource, + IN const size_t nLength /* FIXED STRING LENGTH */ +) { + char *p; + + PKCS11H_ASSERT (szSource!=NULL); + PKCS11H_ASSERT (szTarget!=NULL); + + p = szTarget+nLength; + memmove (szTarget, szSource, nLength); + *p = '\0'; + p--; + while (p >= szTarget && *p == ' ') { + *p = '\0'; + p--; + } +} + +static +void +_pkcs11h_log ( + IN const unsigned flags, + IN const char * const szFormat, + IN ... +) { + va_list args; + + PKCS11H_ASSERT (szFormat!=NULL); + + va_start (args, szFormat); + + if ( + s_pkcs11h_data != NULL && + s_pkcs11h_data->fInitialized + ) { + if (PKCS11H_MSG_LEVEL_TEST (flags)) { + if (s_pkcs11h_data->hooks.log == NULL) { + _pkcs11h_hooks_default_log ( + NULL, + flags, + szFormat, + args + ); + } + else { + s_pkcs11h_data->hooks.log ( + s_pkcs11h_data->hooks.log_data, + flags, + szFormat, + args + ); + } + } + } + + va_end (args); +} + +static +CK_RV +_pkcs11h_getSlotList ( + IN const pkcs11h_provider_t provider, + IN const CK_BBOOL tokenPresent, + OUT CK_SLOT_ID_PTR * const pSlotList, + OUT CK_ULONG_PTR pulCount +) { + CK_SLOT_ID_PTR _slots = NULL; + CK_ULONG _slotnum = 0; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (provider!=NULL); + PKCS11H_ASSERT (pSlotList!=NULL); + PKCS11H_ASSERT (pulCount!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getSlotList entry provider=%p, tokenPresent=%d, pSlotList=%p, pulCount=%p", + (void *)provider, + tokenPresent, + (void *)pSlotList, + (void *)pulCount + ); + + *pSlotList = NULL; + *pulCount = 0; + + if (rv == CKR_OK) { + rv = provider->f->C_GetSlotList ( + tokenPresent, + NULL_PTR, + &_slotnum + ); + } + + if (rv == CKR_OK && _slotnum > 0) { + rv = _pkcs11h_malloc ((void *)&_slots, _slotnum * sizeof (CK_SLOT_ID)); + } + + if (rv == CKR_OK && _slotnum > 0) { + rv = provider->f->C_GetSlotList ( + tokenPresent, + _slots, + &_slotnum + ); + } + + if (rv == CKR_OK) { + *pSlotList = _slots; + _slots = NULL; + *pulCount = _slotnum; + } + + if (_slots != NULL) { + _pkcs11h_free ((void *)&_slots); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getSlotList return rv=%ld-'%s' *pulCount=%ld", + rv, + pkcs11h_getMessage (rv), + *pulCount + ); + + return rv; +} + +static +CK_RV +_pkcs11h_getObjectAttributes ( + IN const pkcs11h_session_t session, + IN const CK_OBJECT_HANDLE object, + IN OUT const CK_ATTRIBUTE_PTR attrs, + IN const unsigned count +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (attrs!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getObjectAttributes entry session=%p, object=%ld, attrs=%p, count=%d", + (void *)session, + object, + (void *)attrs, + count + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if ( + rv == CKR_OK && + (rv = session->provider->f->C_GetAttributeValue ( + session->hSession, + object, + attrs, + count + )) == CKR_OK + ) { + unsigned i; + for (i=0;rv == CKR_OK && iprovider->f->C_GetAttributeValue ( + session->hSession, + object, + attrs, + count + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getObjectAttributes return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_freeObjectAttributes ( + IN OUT const CK_ATTRIBUTE_PTR attrs, + IN const unsigned count +) { + unsigned i; + + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (attrs!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_freeObjectAttributes entry attrs=%p, count=%d", + (void *)attrs, + count + ); + + for (i=0;imutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if ( + rv == CKR_OK && + (rv = session->provider->f->C_FindObjectsInit ( + session->hSession, + (CK_ATTRIBUTE *)filter, + filter_attrs + )) == CKR_OK + ) { + fShouldFindObjectFinal = TRUE; + } + + while ( + rv == CKR_OK && + (rv = session->provider->f->C_FindObjects ( + session->hSession, + objects_buffer, + sizeof (objects_buffer) / sizeof (CK_OBJECT_HANDLE), + &objects_found + )) == CKR_OK && + objects_found > 0 + ) { + CK_OBJECT_HANDLE *temp = NULL; + + /* + * Begin workaround + * + * Workaround iKey bug + * It returns the same objects over and over + */ + if (oLast == objects_buffer[0]) { + PKCS11H_LOG ( + PKCS11H_LOG_WARN, + "PKCS#11: Bad PKCS#11 C_FindObjects implementation detected, workaround applied" + ); + break; + } + oLast = objects_buffer[0]; + /* End workaround */ + + if ( + (rv = _pkcs11h_malloc ( + (void *)&temp, + (objects_size+objects_found) * sizeof (CK_OBJECT_HANDLE) + )) == CKR_OK + ) { + if (objects != NULL) { + memmove ( + temp, + objects, + objects_size * sizeof (CK_OBJECT_HANDLE) + ); + } + memmove ( + temp + objects_size, + objects_buffer, + objects_found * sizeof (CK_OBJECT_HANDLE) + ); + } + + if (rv == CKR_OK) { + _pkcs11h_free ((void *)&objects); + objects = temp; + objects_size += objects_found; + temp = NULL; + } + + if (temp != NULL) { + _pkcs11h_free ((void *)&temp); + temp = NULL; + } + } + + if (fShouldFindObjectFinal) { + session->provider->f->C_FindObjectsFinal ( + session->hSession + ); + fShouldFindObjectFinal = FALSE; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + *p_objects = objects; + *p_objects_found = objects_size; + objects = NULL; + objects_size = 0; + } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + objects = NULL; + objects_size = 0; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_findObjects return rv=%ld-'%s', *p_objects_found=%ld", + rv, + pkcs11h_getMessage (rv), + *p_objects_found + ); + + return rv; +} + +static +CK_RV +_pkcs11h_getTokenId ( + IN const CK_TOKEN_INFO_PTR info, + OUT pkcs11h_token_id_t * const p_token_id +) { + pkcs11h_token_id_t token_id; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (info!=NULL); + PKCS11H_ASSERT (p_token_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getTokenId entry p_token_id=%p", + (void *)p_token_id + ); + + *p_token_id = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_newTokenId (&token_id)) == CKR_OK + ) { + _pkcs11h_fixupFixedString ( + token_id->label, + (char *)info->label, + sizeof (info->label) + ); + _pkcs11h_fixupFixedString ( + token_id->manufacturerID, + (char *)info->manufacturerID, + sizeof (info->manufacturerID) + ); + _pkcs11h_fixupFixedString ( + token_id->model, + (char *)info->model, + sizeof (info->model) + ); + _pkcs11h_fixupFixedString ( + token_id->serialNumber, + (char *)info->serialNumber, + sizeof (info->serialNumber) + ); + } + + if (rv == CKR_OK) { + *p_token_id = token_id; + token_id = NULL; + } + + if (token_id != NULL) { + _pkcs11h_free ((void *)&token_id); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getTokenId return rv=%ld-'%s', *p_token_id=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_token_id + ); + + return rv; +} + +static +CK_RV +_pkcs11h_newTokenId ( + OUT pkcs11h_token_id_t * const p_token_id +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (p_token_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_newTokenId entry p_token_id=%p", + (void *)p_token_id + ); + + *p_token_id = NULL; + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ((void *)p_token_id, sizeof (struct pkcs11h_token_id_s)); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_newTokenId return rv=%ld-'%s', *p_token_id=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_token_id + ); + + return rv; +} + +static +CK_RV +_pkcs11h_getSessionByTokenId ( + IN const pkcs11h_token_id_t token_id, + OUT pkcs11h_session_t * const p_session +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + pkcs11h_session_t session = NULL; + PKCS11H_BOOL fNewSession = FALSE; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (token_id!=NULL); + PKCS11H_ASSERT (p_session!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getSessionByTokenId entry token_id=%p, p_session=%p", + (void *)token_id, + (void *)p_session + ); + + *p_session = NULL; + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + pkcs11h_session_t current_session; + + for ( + current_session = s_pkcs11h_data->sessions; + current_session != NULL && session == NULL; + current_session = current_session->next + ) { + if ( + pkcs11h_sameTokenId ( + current_session->token_id, + token_id + ) + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Using cached session" + ); + session = current_session; + session->nReferenceCount++; + } + } + } + + if ( + rv == CKR_OK && + session == NULL + ) { + fNewSession = TRUE; + } + + if (fNewSession) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Creating a new session" + ); + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ((void *)&session, sizeof (struct pkcs11h_session_s))) == CKR_OK + ) { + session->nReferenceCount = 1; + session->hSession = PKCS11H_INVALID_SESSION_HANDLE; + + session->nPINCachePeriod = s_pkcs11h_data->nPINCachePeriod; + + } + + if (rv == CKR_OK) { + rv = pkcs11h_duplicateTokenId ( + &session->token_id, + token_id + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (rv == CKR_OK) { + rv = _pkcs11h_mutexInit (&session->mutexSession); + } +#endif + + if (rv == CKR_OK) { + session->fValid = TRUE; + session->next = s_pkcs11h_data->sessions; + s_pkcs11h_data->sessions = session; + } + else { +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexFree (&session->mutexSession); +#endif + _pkcs11h_free ((void *)&session); + } + } + + if (rv == CKR_OK) { + *p_session = session; + session = NULL; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexSession); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getSessionByTokenId return rv=%ld-'%s', *p_session=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_session + ); + + return rv; +} + +static +CK_RV +_pkcs11h_releaseSession ( + IN const pkcs11h_session_t session +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (session!=NULL); + PKCS11H_ASSERT (session->nReferenceCount>=0); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_releaseSession session=%p", + (void *)session + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + /* + * Never logout for now + */ + if (rv == CKR_OK) { + if (session->nReferenceCount > 0) { + session->nReferenceCount--; + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_releaseSession return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_resetSession ( + IN const pkcs11h_session_t session, + IN const unsigned maskPrompt, + OUT CK_SLOT_ID * const p_slot +) { + /* + * This function MUST NOT touch session + */ + PKCS11H_BOOL fFound = FALSE; + + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (session!=NULL); + PKCS11H_ASSERT (p_slot!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_resetSession entry session=%p, maskPrompt=%08x, p_slot=%p", + (void *)session, + maskPrompt, + (void *)p_slot + ); + + *p_slot = PKCS11H_INVALID_SLOT_ID; + + while ( + rv == CKR_OK && + !fFound + ) { + pkcs11h_provider_t current_provider = NULL; +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + for ( + current_provider = s_pkcs11h_data->providers; + ( + rv == CKR_OK && + current_provider != NULL && + !fFound + ); + current_provider = current_provider->next + ) { + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slotnum; + CK_SLOT_ID slot_index; + + /* + * Skip disabled providers + * Skip all other providers, + * if one was set in the past + */ + if (session->provider != NULL) { + if (!session->provider->fEnabled) { + continue; + } + if (session->provider != current_provider) { + continue; + } + } + + if (rv == CKR_OK) { + rv = _pkcs11h_getSlotList ( + current_provider, + CK_TRUE, + &slots, + &slotnum + ); + } + + for ( + slot_index=0; + ( + slot_index < slotnum && + rv == CKR_OK && + !fFound + ); + slot_index++ + ) { + pkcs11h_token_id_t token_id = NULL; + CK_TOKEN_INFO info; + + if (rv == CKR_OK) { + rv = current_provider->f->C_GetTokenInfo ( + slots[slot_index], + &info + ); + } + + if ( + rv == CKR_OK && + (rv = _pkcs11h_getTokenId ( + &info, + &token_id + )) == CKR_OK && + pkcs11h_sameTokenId ( + session->token_id, + token_id + ) + ) { + fFound = TRUE; + *p_slot = slots[slot_index]; + if (session->provider == NULL) { + session->provider = current_provider; + _pkcs11h_fixupFixedString ( + token_id->label, + (char *)info.label, + sizeof (info.label) + ); + session->fProtectedAuthenticationSupported = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0; + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'", + current_provider->manufacturerID, + slots[slot_index], + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + if (token_id != NULL) { + pkcs11h_freeTokenId (token_id); + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'", + current_provider->manufacturerID, + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + slots = NULL; + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if ( + rv == CKR_OK && + !fFound + ) { + if ((maskPrompt & PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT) != 0) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling token_prompt hook for '%s'", + session->token_id->label + ); + + if ( + !s_pkcs11h_data->hooks.token_prompt ( + s_pkcs11h_data->hooks.token_prompt_data, + session->token_id + ) + ) { + rv = CKR_CANCEL; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: token_prompt returned %ld", + rv + ); + } + else { + rv = CKR_TOKEN_NOT_PRESENT; + } + } + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_resetSession return rv=%ld-'%s', *p_slot=%ld", + rv, + pkcs11h_getMessage (rv), + *p_slot + ); + + return rv; +} + +static +CK_RV +_pkcs11h_getObjectById ( + IN const pkcs11h_session_t session, + IN const CK_OBJECT_CLASS class, + IN const CK_BYTE_PTR id, + IN const size_t id_size, + OUT CK_OBJECT_HANDLE * const p_handle +) { + CK_ATTRIBUTE filter[] = { + {CKA_CLASS, (void *)&class, sizeof (class)}, + {CKA_ID, (void *)id, id_size} + }; + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + CK_RV rv = CKR_OK; + + /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (id!=NULL); + PKCS11H_ASSERT (p_handle!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getObjectById entry session=%p, class=%ld, id=%p, id_size=%u, p_handle=%p", + (void *)session, + class, + id, + id_size, + (void *)p_handle + ); + + *p_handle = PKCS11H_INVALID_OBJECT_HANDLE; + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_findObjects ( + session, + filter, + sizeof (filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found + ); + } + + if ( + rv == CKR_OK && + objects_found == 0 + ) { + rv = CKR_FUNCTION_REJECTED; + } + + if (rv == CKR_OK) { + *p_handle = objects[0]; + } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getObjectById return rv=%ld-'%s', *p_handle=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_handle + ); + + return rv; +} + +static +CK_RV +_pkcs11h_validateSession ( + IN const pkcs11h_session_t session +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_RV rv = CKR_OK; + + /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_validateSession entry session=%p", + (void *)session + ); + + if ( + rv == CKR_OK && + session == NULL + ) { + rv = CKR_SESSION_HANDLE_INVALID; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if ( + rv == CKR_OK && + ( + session->provider == NULL || + !session->provider->fEnabled || + session->hSession == PKCS11H_INVALID_SESSION_HANDLE + ) + ) { + rv = CKR_SESSION_HANDLE_INVALID; + } + + if ( + rv == CKR_OK && + session->timePINExpire != (time_t)0 && + session->timePINExpire < PKCS11H_TIME (NULL) + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Forcing logout due to pin timeout" + ); + _pkcs11h_logout (session); + rv = CKR_SESSION_HANDLE_INVALID; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_validateSession return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_login ( + IN const pkcs11h_session_t session, + IN const PKCS11H_BOOL fPublicOnly, + IN const PKCS11H_BOOL fReadOnly, + IN const unsigned maskPrompt +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (session!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_login entry session=%p, fPublicOnly=%d, fReadOnly=%d, maskPrompt=%08x", + (void *)session, + fPublicOnly ? 1 : 0, + fReadOnly ? 1 : 0, + maskPrompt + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_logout (session); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_resetSession (session, maskPrompt, &slot); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = session->provider->f->C_OpenSession ( + slot, + ( + CKF_SERIAL_SESSION | + (fReadOnly ? 0 : CKF_RW_SESSION) + ), + NULL_PTR, + NULL_PTR, + &session->hSession + ); + } + + if ( + rv == CKR_OK && + ( + !fPublicOnly || + session->provider->fCertIsPrivate + ) + ) { + PKCS11H_BOOL fSuccessLogin = FALSE; + int nRetryCount = 0; + + if ((maskPrompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT) == 0) { + rv = CKR_USER_NOT_LOGGED_IN; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling pin_prompt hook denied because of prompt mask" + ); + } + + while ( + rv == CKR_OK && + !fSuccessLogin && + nRetryCount++ < s_pkcs11h_data->nMaxLoginRetries + ) { + CK_UTF8CHAR_PTR utfPIN = NULL; + CK_ULONG lPINLength = 0; + char szPIN[1024]; + + if ( + rv == CKR_OK && + !( + s_pkcs11h_data->fProtectedAuthentication && + session->provider->fProtectedAuthentication && + session->fProtectedAuthenticationSupported + ) + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling pin_prompt hook for '%s'", + session->token_id->label + ); + + if ( + !s_pkcs11h_data->hooks.pin_prompt ( + s_pkcs11h_data->hooks.pin_prompt_data, + session->token_id, + szPIN, + sizeof (szPIN) + ) + ) { + rv = CKR_CANCEL; + } + else { + utfPIN = (CK_UTF8CHAR_PTR)szPIN; + lPINLength = strlen (szPIN); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: pin_prompt hook return rv=%ld", + rv + ); + + } + + if (session->nPINCachePeriod == PKCS11H_PIN_CACHE_INFINITE) { + session->timePINExpire = 0; + } + else { + session->timePINExpire = ( + PKCS11H_TIME (NULL) + + (time_t)session->nPINCachePeriod + ); + } + + if ( + rv == CKR_OK && + (rv = session->provider->f->C_Login ( + session->hSession, + CKU_USER, + utfPIN, + lPINLength + )) != CKR_OK + ) { + if (rv == CKR_USER_ALREADY_LOGGED_IN) { + rv = CKR_OK; + } + } + + /* + * Clean PIN buffer + */ + memset (szPIN, 0, sizeof (szPIN)); + + if (rv == CKR_OK) { + fSuccessLogin = TRUE; + } + else if ( + rv == CKR_PIN_INCORRECT || + rv == CKR_PIN_INVALID + ) { + /* + * Ignore these errors + * so retry can be performed + */ + rv = CKR_OK; + } + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_login return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_logout ( + IN const pkcs11h_session_t session +) { + /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_logout entry session=%p", + (void *)session + ); + + if ( + session != NULL && + session->hSession != PKCS11H_INVALID_SESSION_HANDLE + ) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_RV rv = CKR_OK; + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + if (session->provider != NULL) { + session->provider->f->C_Logout (session->hSession); + session->provider->f->C_CloseSession (session->hSession); + } + session->hSession = PKCS11H_INVALID_SESSION_HANDLE; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_logout return" + ); + + return CKR_OK; +} + +static +void +_pkcs11h_hooks_default_log ( + IN const void * pData, + IN const unsigned flags, + IN const char * const szFormat, + IN va_list args +) { + (void)pData; + (void)flags; + (void)szFormat; + (void)args; +} + +static +PKCS11H_BOOL +_pkcs11h_hooks_default_token_prompt ( + IN const void * pData, + IN const pkcs11h_token_id_t token +) { + PKCS11H_ASSERT (token!=NULL); + + (void)pData; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_hooks_default_token_prompt pData=%p, szLabel='%s'", + pData, + token->label + ); + + return FALSE; +} + +static +PKCS11H_BOOL +_pkcs11h_hooks_default_pin_prompt ( + IN const void * pData, + IN const pkcs11h_token_id_t token, + OUT char * const szPIN, + IN const size_t nMaxPIN +) { + PKCS11H_ASSERT (token!=NULL); + + (void)pData; + (void)szPIN; + (void)nMaxPIN; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_hooks_default_pin_prompt pData=%p, szLabel='%s'", + pData, + token->label + ); + + return FALSE; +} + +#if !defined(WIN32) +#if defined(ENABLE_PKCS11H_THREADING) + +static +void +__pkcs11h_atfork_prepare () { + __pkcs1h_mutexLockAll (); +} +static +void +__pkcs11h_atfork_parent () { + __pkcs1h_mutexReleaseAll (); +} +static +void +__pkcs11h_atfork_child () { + __pkcs1h_mutexReleaseAll (); + _pkcs11h_forkFixup (); +} + +#endif /* ENABLE_PKCS11H_THREADING */ + +static +CK_RV +_pkcs11h_forkFixup () { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + pid_t mypid = getpid (); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_forkFixup entry pid=%d", + mypid + ); + + if (s_pkcs11h_data != NULL && s_pkcs11h_data->fInitialized) { + pkcs11h_provider_t current; + +#if defined(ENABLE_PKCS11H_THREADING) + if (_pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal) == CKR_OK) { + fMutexLocked = TRUE; + } +#endif + + for ( + current = s_pkcs11h_data->providers; + current != NULL; + current = current->next + ) { + if (current->fEnabled) { + current->f->C_Initialize (NULL); + } + +#if defined(ENABLE_PKCS11H_SLOTEVENT) + /* + * After fork we have no threads... + * So just initialized. + */ + if (s_pkcs11h_data->fSlotEventInitialized) { + s_pkcs11h_data->fSlotEventInitialized = FALSE; + _pkcs11h_slotevent_init (); + } +#endif + } + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_forkFixup return" + ); + + return CKR_OK; +} + +#endif /* !WIN32 */ + +#if defined(ENABLE_PKCS11H_TOKEN) +/*======================================================================* + * TOKEN INTERFACE + *======================================================================*/ + +CK_RV +pkcs11h_token_ensureAccess ( + IN const pkcs11h_token_id_t token_id, + IN const unsigned maskPrompt +) { + pkcs11h_session_t session = NULL; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_token_ensureAccess entry token_id=%p, maskPrompt=%08x", + (void *)token_id, + maskPrompt + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + ); + } + + if (rv == CKR_OK) { + CK_SLOT_ID slot; + + rv = _pkcs11h_resetSession ( + session, + maskPrompt, + &slot + ); + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_token_ensureAccess return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +#endif /* ENABLE_PKCS11H_TOKEN */ + +#if defined(ENABLE_PKCS11H_DATA) +/*======================================================================* + * DATA INTERFACE + *======================================================================*/ + +static +CK_RV +_pkcs11h_data_getObject ( + IN const pkcs11h_session_t session, + IN const char * const szApplication, + IN const char * const szLabel, + OUT CK_OBJECT_HANDLE * const p_handle +) { + CK_OBJECT_CLASS class = CKO_DATA; + CK_ATTRIBUTE filter[] = { + {CKA_CLASS, (void *)&class, sizeof (class)}, + {CKA_APPLICATION, (void *)szApplication, szApplication == NULL ? 0 : strlen (szApplication)}, + {CKA_LABEL, (void *)szLabel, szLabel == NULL ? 0 : strlen (szLabel)} + }; + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + CK_RV rv = CKR_OK; + + /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (szApplication!=NULL); + PKCS11H_ASSERT (szLabel!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_data_getObject entry session=%p, szApplication='%s', szLabel='%s', p_handle=%p", + (void *)session, + szApplication, + szLabel, + (void *)p_handle + ); + + *p_handle = PKCS11H_INVALID_OBJECT_HANDLE; + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_findObjects ( + session, + filter, + sizeof (filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found + ); + } + + if ( + rv == CKR_OK && + objects_found == 0 + ) { + rv = CKR_FUNCTION_REJECTED; + } + + if (rv == CKR_OK) { + *p_handle = objects[0]; + } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_data_getObject return rv=%ld-'%s', *p_handle=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_handle + ); + + return rv; +} + +CK_RV +pkcs11h_data_get ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel, + OUT char * const blob, + IN OUT size_t * const p_blob_size +) { + CK_ATTRIBUTE attrs[] = { + {CKA_VALUE, NULL, 0} + }; + CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE; + CK_RV rv = CKR_OK; + + pkcs11h_session_t session = NULL; + size_t blob_size_max; + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + PKCS11H_BOOL fMutexLocked = FALSE; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + PKCS11H_ASSERT (szApplication!=NULL); + PKCS11H_ASSERT (szLabel!=NULL); + /*PKCS11H_ASSERT (blob!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (p_blob_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_get entry token_id=%p, szApplication='%s', szLabel='%s', blob=%p, p_blob_size=%p", + (void *)token_id, + szApplication, + szLabel, + blob, + (void *)p_blob_size + ); + + blob_size_max = *p_blob_size; + *p_blob_size = 0; + + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + ); + } + + while (rv == CKR_OK && !fOpSuccess) { + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = _pkcs11h_data_getObject ( + session, + szApplication, + szLabel, + &handle + ); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_getObjectAttributes ( + session, + handle, + attrs, + sizeof (attrs)/sizeof (CK_ATTRIBUTE) + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Read data object failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + fLoginRetry = TRUE; + rv = _pkcs11h_login ( + session, + fPublic, + TRUE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } + } + + if (rv == CKR_OK) { + *p_blob_size = attrs[0].ulValueLen; + } + + if (rv == CKR_OK) { + if (blob != NULL) { + if (*p_blob_size > blob_size_max) { + rv = CKR_BUFFER_TOO_SMALL; + } + else { + memmove (blob, attrs[0].pValue, *p_blob_size); + } + } + } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs)/sizeof (CK_ATTRIBUTE) + ); + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_get return rv=%ld-'%s', *p_blob_size=%d", + rv, + pkcs11h_getMessage (rv), + *p_blob_size + ); + + return rv; +} + +CK_RV +pkcs11h_data_put ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel, + OUT char * const blob, + IN const size_t blob_size +) { + CK_OBJECT_CLASS class = CKO_DATA; + CK_BBOOL ck_true = CK_TRUE; + CK_BBOOL ck_false = CK_FALSE; + + CK_ATTRIBUTE attrs[] = { + {CKA_CLASS, &class, sizeof (class)}, + {CKA_TOKEN, &ck_true, sizeof (ck_true)}, + {CKA_PRIVATE, fPublic ? &ck_false : &ck_true, sizeof (CK_BBOOL)}, + {CKA_APPLICATION, (void *)szApplication, strlen (szApplication)}, + {CKA_LABEL, (void *)szLabel, strlen (szLabel)}, + {CKA_VALUE, blob, blob_size} + }; + + CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE; + CK_RV rv = CKR_OK; + + pkcs11h_session_t session = NULL; + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + PKCS11H_BOOL fMutexLocked = FALSE; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + PKCS11H_ASSERT (szApplication!=NULL); + PKCS11H_ASSERT (szLabel!=NULL); + PKCS11H_ASSERT (blob!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_put entry token_id=%p, szApplication='%s', szLabel='%s', blob=%p, blob_size=%d", + (void *)token_id, + szApplication, + szLabel, + blob, + blob_size + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + ); + } + + while (rv == CKR_OK && !fOpSuccess) { + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = session->provider->f->C_CreateObject ( + session->hSession, + attrs, + sizeof (attrs)/sizeof (CK_ATTRIBUTE), + &handle + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Write data object failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + fLoginRetry = TRUE; + rv = _pkcs11h_login ( + session, + fPublic, + FALSE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_put return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +pkcs11h_data_del ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel +) { + CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE; + CK_RV rv = CKR_OK; + + pkcs11h_session_t session = NULL; + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + PKCS11H_BOOL fMutexLocked = FALSE; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + PKCS11H_ASSERT (szApplication!=NULL); + PKCS11H_ASSERT (szLabel!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_del entry token_id=%p, szApplication='%s', szLabel='%s'", + (void *)token_id, + szApplication, + szLabel + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + ); + } + + while (rv == CKR_OK && !fOpSuccess) { + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_data_getObject ( + session, + szApplication, + szLabel, + &handle + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = session->provider->f->C_DestroyObject ( + session->hSession, + handle + ); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Remove data object failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + fLoginRetry = TRUE; + rv = _pkcs11h_login ( + session, + fPublic, + FALSE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_del return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +#endif /* ENABLE_PKCS11H_DATA */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) +/*======================================================================* + * CERTIFICATE INTERFACE + *======================================================================*/ + +static +void +_pkcs11h_isBetterCertificate_getExpiration ( + IN const unsigned char * const pCertificate, + IN const size_t nCertificateSize, + OUT char * const szNotBefore, + IN const int nNotBeforeSize +) { + /* + * 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 *x509 = NULL; + + PKCS11H_ASSERT (pCertificate!=NULL); + PKCS11H_ASSERT (szNotBefore!=NULL); + PKCS11H_ASSERT (nNotBeforeSize>0); + + szNotBefore[0] = '\0'; + + x509 = X509_new (); + + if (x509 != NULL) { + pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)pCertificate; + + if ( + d2i_X509 (&x509, &d2i, nCertificateSize) + ) { + ASN1_TIME *notBefore = X509_get_notBefore (x509); + ASN1_TIME *notAfter = X509_get_notAfter (x509); + + if ( + notBefore != NULL && + X509_cmp_current_time (notBefore) <= 0 && + X509_cmp_current_time (notAfter) >= 0 && + notBefore->length < nNotBeforeSize - 1 + ) { + memmove (szNotBefore, notBefore->data, notBefore->length); + szNotBefore[notBefore->length] = '\0'; + } + } + } + + if (x509 != NULL) { + X509_free (x509); + x509 = NULL; + } +} + +static +PKCS11H_BOOL +_pkcs11h_isBetterCertificate ( + IN const unsigned char * const pCurrent, + IN const size_t nCurrentSize, + IN const unsigned char * const pNew, + IN const size_t 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. + */ + + PKCS11H_BOOL fBetter = FALSE; + + /*PKCS11H_ASSERT (pCurrent!=NULL); NOT NEEDED */ + PKCS11H_ASSERT (pNew!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_isBetterCertificate entry pCurrent=%p, nCurrentSize=%u, pNew=%p, nNewSize=%u", + pCurrent, + nCurrentSize, + pNew, + nNewSize + ); + + /* + * First certificae + * always select + */ + if (nCurrentSize == 0 || pCurrent == NULL) { + fBetter = TRUE; + } + else { + char szNotBeforeCurrent[1024], szNotBeforeNew[1024]; + + _pkcs11h_isBetterCertificate_getExpiration ( + pCurrent, + nCurrentSize, + szNotBeforeCurrent, + sizeof (szNotBeforeCurrent) + ); + _pkcs11h_isBetterCertificate_getExpiration ( + pNew, + nNewSize, + szNotBeforeNew, + sizeof (szNotBeforeNew) + ); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_isBetterCertificate szNotBeforeCurrent='%s', szNotBeforeNew='%s'", + szNotBeforeCurrent, + szNotBeforeNew + ); + + fBetter = strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_isBetterCertificate return fBetter=%d", + fBetter ? 1 : 0 + ); + + return fBetter; +} + +static +CK_RV +_pkcs11h_newCertificateId ( + OUT pkcs11h_certificate_id_t * const p_certificate_id +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (p_certificate_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_newCertificateId entry p_certificate_id=%p", + (void *)p_certificate_id + ); + + *p_certificate_id = NULL; + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ((void *)p_certificate_id, sizeof (struct pkcs11h_certificate_id_s)); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_newCertificateId return rv=%ld-'%s', *p_certificate_id=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_certificate_id + ); + + return rv; +} + +static +CK_RV +_pkcs11h_loadCertificate ( + IN const pkcs11h_certificate_t certificate +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE; + CK_ATTRIBUTE cert_filter[] = { + {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}, + {CKA_ID, NULL, 0} + }; + + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + CK_RV rv = CKR_OK; + + CK_ULONG i; + + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (certificate->id!=NULL); + + /* Must be after assert */ + cert_filter[1].pValue = certificate->id->attrCKA_ID; + cert_filter[1].ulValueLen = certificate->id->attrCKA_ID_size; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_loadCertificate entry certificate=%p", + (void *)certificate + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (certificate->session); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = _pkcs11h_findObjects ( + certificate->session, + cert_filter, + sizeof (cert_filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found + ); + } + + for (i=0;rv == CKR_OK && i < objects_found;i++) { + CK_ATTRIBUTE attrs[] = { + {CKA_VALUE, NULL, 0} + }; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_getObjectAttributes ( + certificate->session, + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + )) == CKR_OK + ) { + if ( + _pkcs11h_isBetterCertificate ( + certificate->id->certificate_blob, + certificate->id->certificate_blob_size, + attrs[0].pValue, + attrs[0].ulValueLen + ) + ) { + if (certificate->id->certificate_blob != NULL) { + _pkcs11h_free ((void *)&certificate->id->certificate_blob); + } + + rv = _pkcs11h_dupmem ( + (void*)&certificate->id->certificate_blob, + &certificate->id->certificate_blob_size, + attrs[0].pValue, + attrs[0].ulValueLen + ); + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'", + certificate->session->provider->manufacturerID, + objects[i], + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + } + + if ( + rv == CKR_OK && + certificate->id->certificate_blob == NULL + ) { + rv = CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&certificate->mutexCertificate); + fMutexLocked = FALSE; + } +#endif + + /* + * No need to free allocated objects + * on error, since the certificate_id + * should be free by caller. + */ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_loadCertificate return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_updateCertificateIdDescription ( + IN OUT pkcs11h_certificate_id_t certificate_id +) { + static const char * szSeparator = " on "; + static const char * szUnknown = "UNKNOWN"; + X509 *x509 = NULL; + pkcs11_openssl_d2i_t d2i1; + + PKCS11H_ASSERT (certificate_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_updateCertificateIdDescription entry certificate_id=%p", + (void *)certificate_id + ); + + x509 = X509_new (); + + d2i1 = (pkcs11_openssl_d2i_t)certificate_id->certificate_blob; + if (d2i_X509 (&x509, &d2i1, certificate_id->certificate_blob_size)) { + X509_NAME_oneline ( + X509_get_subject_name (x509), + certificate_id->displayName, + sizeof (certificate_id->displayName) + ); + } + else { + strncpy ( + certificate_id->displayName, + szUnknown, + sizeof (certificate_id->displayName)-1 + ); + } + + if (x509 != NULL) { + X509_free (x509); + x509 = NULL; + } + + /* + * Try to avoid using snprintf, + * may be unavailable + */ + strncat ( + certificate_id->displayName, + szSeparator, + sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName) + ); + strncat ( + certificate_id->displayName, + certificate_id->token_id->label, + sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName) + ); + certificate_id->displayName[sizeof (certificate_id->displayName) - 1] = '\0'; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_updateCertificateIdDescription return displayName=%s", + certificate_id->displayName + ); + + return CKR_OK; +} + +static +CK_RV +_pkcs11h_ensureCertificateBlob ( + IN const pkcs11h_certificate_t certificate +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (certificate!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_ensureCertificateBlob entry certificate=%p", + (void *)certificate + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (certificate->id->certificate_blob == NULL) { + fOpSuccess = FALSE; + fLoginRetry = FALSE; + while (rv == CKR_OK && !fOpSuccess) { + if (rv == CKR_OK) { + rv = _pkcs11h_loadCertificate (certificate); + } + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + fLoginRetry = TRUE; + rv = _pkcs11h_resetCertificateSession ( + certificate, + TRUE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } + } + } + + if ( + rv == CKR_OK && + certificate->id->certificate_blob == NULL + ) { + rv = CKR_FUNCTION_REJECTED; + } + + if (rv == CKR_OK) { + _pkcs11h_updateCertificateIdDescription (certificate->id); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&certificate->mutexCertificate); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_ensureCertificateBlob return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_getCertificateKeyAttributes ( + IN const pkcs11h_certificate_t certificate +) { + CK_RV rv = CKR_OK; + + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + + PKCS11H_ASSERT (certificate!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getCertificateKeyAttributes entry certificate=%p", + (void *)certificate + ); + + certificate->maskSignMode = 0; + + while (rv == CKR_OK && !fOpSuccess) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + CK_ATTRIBUTE key_attrs[] = { + {CKA_SIGN, NULL, 0}, + {CKA_SIGN_RECOVER, NULL, 0} + }; + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + /* + * Don't try invalid object + */ + if ( + rv == CKR_OK && + certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE + ) { + rv = CKR_OBJECT_HANDLE_INVALID; + } + + if (rv == CKR_OK) { + if (certificate->session->provider->maskSignMode != 0) { + certificate->maskSignMode = certificate->session->provider->maskSignMode; + fOpSuccess = TRUE; + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Key attributes enforced by provider (%08x)", + certificate->maskSignMode + ); + } + } + + if (rv == CKR_OK && !fOpSuccess) { + rv = _pkcs11h_getObjectAttributes ( + certificate->session, + certificate->hKey, + key_attrs, + sizeof (key_attrs) / sizeof (CK_ATTRIBUTE) + ); + } + + if (rv == CKR_OK && !fOpSuccess) { + CK_BBOOL *key_attrs_sign = (CK_BBOOL *)key_attrs[0].pValue; + CK_BBOOL *key_attrs_sign_recover = (CK_BBOOL *)key_attrs[1].pValue; + + if (key_attrs_sign != NULL && *key_attrs_sign != CK_FALSE) { + certificate->maskSignMode |= PKCS11H_SIGNMODE_MASK_SIGN; + } + if (key_attrs_sign_recover != NULL && *key_attrs_sign_recover != CK_FALSE) { + certificate->maskSignMode |= PKCS11H_SIGNMODE_MASK_RECOVER; + } + if (certificate->maskSignMode == 0) { + rv = CKR_KEY_TYPE_INCONSISTENT; + } + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Key attributes loaded (%08x)", + certificate->maskSignMode + ); + } + + _pkcs11h_freeObjectAttributes ( + key_attrs, + sizeof (key_attrs) / sizeof (CK_ATTRIBUTE) + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&certificate->mutexCertificate); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Get private key attributes failed: %ld:'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + rv = _pkcs11h_resetCertificateSession ( + certificate, + FALSE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + + fLoginRetry = TRUE; + } + } + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_getCertificateKeyAttributes return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_validateCertificateSession ( + IN const pkcs11h_certificate_t certificate +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (certificate!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_validateCertificateSession entry certificate=%p", + (void *)certificate + ); + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (certificate->session); + } + + if (rv == CKR_OK) { + if (certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE) { + rv = CKR_OBJECT_HANDLE_INVALID; + } + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_validateCertificateSession return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +_pkcs11h_resetCertificateSession ( + IN const pkcs11h_certificate_t certificate, + IN const PKCS11H_BOOL fPublicOnly, + IN const unsigned maskPrompt +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + PKCS11H_BOOL fKeyValid = FALSE; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (certificate!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_resetCertificateSession entry certificate=%p, fPublicOnly=%d, maskPrompt=%08x", + (void *)certificate, + fPublicOnly ? 1 : 0, + maskPrompt + ); + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if ( + !fKeyValid && + rv == CKR_OK && + certificate->session == NULL && + (rv = _pkcs11h_getSessionByTokenId (certificate->id->token_id, &certificate->session)) == CKR_OK + ) { + if (certificate->nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) { + if (certificate->session->nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) { + if (certificate->session->nPINCachePeriod > certificate->nPINCachePeriod) { + certificate->session->timePINExpire = ( + certificate->session->timePINExpire - + (time_t)certificate->session->nPINCachePeriod + + (time_t)certificate->nPINCachePeriod + ); + certificate->session->nPINCachePeriod = certificate->nPINCachePeriod; + } + } + else { + certificate->session->timePINExpire = ( + PKCS11H_TIME (NULL) + + (time_t)certificate->nPINCachePeriod + ); + certificate->session->nPINCachePeriod = certificate->nPINCachePeriod; + } + } + } + + /* + * First, if session seems to be valid + * and key handle is invalid (hard-set), + * try to fetch key handle, + * maybe the token is already logged in + */ + if (rv == CKR_OK) { + if ( + certificate->session->hSession != PKCS11H_INVALID_SESSION_HANDLE && + certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE && + !fPublicOnly + ) { + if ( + (rv = _pkcs11h_getObjectById ( + certificate->session, + CKO_PRIVATE_KEY, + certificate->id->attrCKA_ID, + certificate->id->attrCKA_ID_size, + &certificate->hKey + )) == CKR_OK + ) { + fKeyValid = TRUE; + } + else { + /* + * Ignore error + */ + rv = CKR_OK; + certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE; + } + } + } + + if ( + !fKeyValid && + rv == CKR_OK && + (rv = _pkcs11h_login ( + certificate->session, + fPublicOnly, + TRUE, + maskPrompt + )) == CKR_OK + ) { + rv = _pkcs11h_updateCertificateIdDescription (certificate->id); + } + + if ( + !fKeyValid && + rv == CKR_OK && + !fPublicOnly && + (rv = _pkcs11h_getObjectById ( + certificate->session, + CKO_PRIVATE_KEY, + certificate->id->attrCKA_ID, + certificate->id->attrCKA_ID_size, + &certificate->hKey + )) == CKR_OK + ) { + fKeyValid = TRUE; + } + + if ( + rv == CKR_OK && + !fPublicOnly && + !fKeyValid + ) { + rv = CKR_FUNCTION_REJECTED; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&certificate->mutexCertificate); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_resetCertificateSession return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +static +CK_RV +_pkcs11h_certificate_private_op ( + IN const pkcs11h_certificate_t certificate, + IN const enum _pkcs11h_private_op_e op, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size +) { + CK_MECHANISM mech = { + mech_type, NULL, 0 + }; + + CK_RV rv = CKR_OK; + PKCS11H_BOOL fLoginRetry = FALSE; + PKCS11H_BOOL fOpSuccess = FALSE; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (source!=NULL); + /*PKCS11H_ASSERT (target); NOT NEEDED*/ + PKCS11H_ASSERT (p_target_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_private_op entry certificate=%p, op=%d, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p", + (void *)certificate, + op, + mech_type, + source, + source_size, + target, + (void *)p_target_size + ); + + if (target == NULL) { + *p_target_size = 0; + } + + while (rv == CKR_OK && !fOpSuccess) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + + if (rv == CKR_OK && !certificate->fOperationActive) { + rv = _pkcs11h_validateCertificateSession (certificate); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&certificate->session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK && !certificate->fOperationActive) { + switch (op) { + case _pkcs11h_private_op_sign: + rv = certificate->session->provider->f->C_SignInit ( + certificate->session->hSession, + &mech, + certificate->hKey + ); + break; + case _pkcs11h_private_op_sign_recover: + rv = certificate->session->provider->f->C_SignRecoverInit ( + certificate->session->hSession, + &mech, + certificate->hKey + ); + break; + case _pkcs11h_private_op_decrypt: + rv = certificate->session->provider->f->C_DecryptInit ( + certificate->session->hSession, + &mech, + certificate->hKey + ); + break; + default: + rv = CKR_ARGUMENTS_BAD; + break; + } + } + + if (rv == CKR_OK) { + CK_ULONG size = *p_target_size; + + switch (op) { + case _pkcs11h_private_op_sign: + rv = certificate->session->provider->f->C_Sign ( + certificate->session->hSession, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); + break; + case _pkcs11h_private_op_sign_recover: + rv = certificate->session->provider->f->C_SignRecover ( + certificate->session->hSession, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); + break; + case _pkcs11h_private_op_decrypt: + rv = certificate->session->provider->f->C_Decrypt ( + certificate->session->hSession, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); + break; + default: + rv = CKR_ARGUMENTS_BAD; + break; + } + + *p_target_size = size; + } + + if ( + target == NULL && + ( + rv == CKR_BUFFER_TOO_SMALL || + rv == CKR_OK + ) + ) { + certificate->fOperationActive = TRUE; + rv = CKR_OK; + } + else { + certificate->fOperationActive = FALSE; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&certificate->session->mutexSession); + fMutexLocked = FALSE; + } +#endif + + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Private key operation failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + fLoginRetry = TRUE; + rv = _pkcs11h_resetCertificateSession ( + certificate, + FALSE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_private_op return rv=%ld-'%s', *p_target_size=%d", + rv, + pkcs11h_getMessage (rv), + *p_target_size + ); + + return rv; +} + +CK_RV +pkcs11h_freeCertificateId ( + IN pkcs11h_certificate_id_t certificate_id +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificateId entry certificate_id=%p", + (void *)certificate_id + ); + + if (certificate_id->attrCKA_ID != NULL) { + _pkcs11h_free ((void *)&certificate_id->attrCKA_ID); + } + if (certificate_id->certificate_blob != NULL) { + _pkcs11h_free ((void *)&certificate_id->certificate_blob); + } + if (certificate_id->token_id != NULL) { + pkcs11h_freeTokenId (certificate_id->token_id); + certificate_id->token_id = NULL; + } + _pkcs11h_free ((void *)&certificate_id); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificateId return" + ); + + return CKR_OK; +} + +CK_RV +pkcs11h_duplicateCertificateId ( + OUT pkcs11h_certificate_id_t * const to, + IN const pkcs11h_certificate_id_t from +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (to!=NULL); + PKCS11H_ASSERT (from!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_duplicateCertificateId entry to=%p form=%p", + (void *)to, + (void *)from + ); + + *to = NULL; + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)to, + NULL, + from, + sizeof (struct pkcs11h_certificate_id_s) + ); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)&(*to)->token_id, + NULL, + from->token_id, + sizeof (struct pkcs11h_token_id_s) + ); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)&(*to)->attrCKA_ID, + &(*to)->attrCKA_ID_size, + from->attrCKA_ID, + from->attrCKA_ID_size + ); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)&(*to)->certificate_blob, + &(*to)->certificate_blob_size, + from->certificate_blob, + from->certificate_blob_size + ); + } - PKCS11ASSERT (szSource!=NULL); - PKCS11ASSERT (szTarget!=NULL); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_duplicateCertificateId return rv=%ld-'%s', *to=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*to + ); - p = szTarget+nLength; - memmove (szTarget, szSource, nLength); - *p = '\0'; - p--; - while (p >= szTarget && *p == ' ') { - *p = '\0'; - p--; + return rv; +} + +CK_RV +pkcs11h_freeCertificate ( + IN pkcs11h_certificate_t certificate +) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificate entry certificate=%p", + (void *)certificate + ); + + if (certificate != NULL) { + if (certificate->session != NULL) { + _pkcs11h_releaseSession (certificate->session); + } + pkcs11h_freeCertificateId (certificate->id); + certificate->id = NULL; + +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexFree (&certificate->mutexCertificate); +#endif + + _pkcs11h_free ((void *)&certificate); } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificate return" + ); + + return CKR_OK; } -static -void -_hexToBinary ( - IN const char * const szSource, +CK_RV +pkcs11h_certificate_sign ( + IN const pkcs11h_certificate_t certificate, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT size_t * const target_size + IN OUT size_t * const p_target_size ) { - size_t target_max_size; - const char *p; - char buf[3] = {'\0', '\0', '\0'}; - int i = 0; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (source!=NULL); + /*PKCS11H_ASSERT (target); NOT NEEDED*/ + PKCS11H_ASSERT (p_target_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_sign entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p", + (void *)certificate, + mech_type, + source, + source_size, + target, + (void *)p_target_size + ); - PKCS11ASSERT (szSource!=NULL); - PKCS11ASSERT (target!=NULL); - PKCS11ASSERT (target_size!=NULL); + if (target == NULL) { + *p_target_size = 0; + } - target_max_size = *target_size; - p = szSource; - *target_size = 0; + if (rv == CKR_OK) { + rv = _pkcs11h_certificate_private_op ( + certificate, + _pkcs11h_private_op_sign, + mech_type, + source, + source_size, + target, + p_target_size + ); + } - while (*p != '\0' && *target_size < target_max_size) { - if (isxdigit (*p)) { - buf[i%2] = *p; + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_sign return rv=%ld-'%s', *p_target_size=%d", + rv, + pkcs11h_getMessage (rv), + *p_target_size + ); + + return rv; +} - if ((i%2) == 1) { - unsigned v; - if (sscanf (buf, "%x", &v) != 1) { - v = 0; - } - target[*target_size] = v & 0xff; - (*target_size)++; - } +CK_RV +pkcs11h_certificate_signRecover ( + IN const pkcs11h_certificate_t certificate, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (source!=NULL); + /*PKCS11H_ASSERT (target); NOT NEEDED*/ + PKCS11H_ASSERT (p_target_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_signRecover entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p", + (void *)certificate, + mech_type, + source, + source_size, + target, + (void *)p_target_size + ); + + if (target == NULL) { + *p_target_size = 0; + } + + if (rv == CKR_OK) { + rv = _pkcs11h_certificate_private_op ( + certificate, + _pkcs11h_private_op_sign_recover, + mech_type, + source, + source_size, + target, + p_target_size + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_signRecover return rv=%ld-'%s', *p_target_size=%d", + rv, + pkcs11h_getMessage (rv), + *p_target_size + ); + + return rv; +} + +CK_RV +pkcs11h_certificate_signAny ( + IN const pkcs11h_certificate_t certificate, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size +) { + CK_RV rv = CKR_OK; + PKCS11H_BOOL fSigned = FALSE; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (source!=NULL); + /*PKCS11H_ASSERT (target); NOT NEEDED*/ + PKCS11H_ASSERT (p_target_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_signAny entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p", + (void *)certificate, + mech_type, + source, + source_size, + target, + (void *)p_target_size + ); + + if ( + rv == CKR_OK && + certificate->maskSignMode == 0 + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Getting key attributes" + ); + rv = _pkcs11h_getCertificateKeyAttributes (certificate); + } + + if ( + rv == CKR_OK && + !fSigned && + (certificate->maskSignMode & PKCS11H_SIGNMODE_MASK_SIGN) != 0 + ) { + rv = pkcs11h_certificate_sign ( + certificate, + mech_type, + source, + source_size, + target, + p_target_size + ); + + if (rv == CKR_OK) { + fSigned = TRUE; + } + else if ( + rv == CKR_FUNCTION_NOT_SUPPORTED || + rv == CKR_KEY_FUNCTION_NOT_PERMITTED + ) { + certificate->maskSignMode &= ~PKCS11H_SIGNMODE_MASK_SIGN; + rv = CKR_OK; + } + } + + if ( + rv == CKR_OK && + !fSigned && + (certificate->maskSignMode & PKCS11H_SIGNMODE_MASK_RECOVER) != 0 + ) { + rv = pkcs11h_certificate_signRecover ( + certificate, + mech_type, + source, + source_size, + target, + p_target_size + ); + + if (rv == CKR_OK) { + fSigned = TRUE; + } + else if ( + rv == CKR_FUNCTION_NOT_SUPPORTED || + rv == CKR_KEY_FUNCTION_NOT_PERMITTED + ) { + certificate->maskSignMode &= ~PKCS11H_SIGNMODE_MASK_RECOVER; + rv = CKR_OK; + } + } + + if (!fSigned) { + rv = CKR_FUNCTION_FAILED; + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_signAny return rv=%ld-'%s', *p_target_size=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_target_size + ); + + return rv; +} + +CK_RV +pkcs11h_certificate_decrypt ( + IN const pkcs11h_certificate_t certificate, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (source!=NULL); + /*PKCS11H_ASSERT (target); NOT NEEDED*/ + PKCS11H_ASSERT (p_target_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_decrypt entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p", + (void *)certificate, + mech_type, + source, + source_size, + target, + (void *)p_target_size + ); + + if (target == NULL) { + *p_target_size = 0; + } + + if (rv == CKR_OK) { + rv = _pkcs11h_certificate_private_op ( + certificate, + _pkcs11h_private_op_decrypt, + mech_type, + source, + source_size, + target, + p_target_size + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_decrypt return rv=%ld-'%s', *p_target_size=%d", + rv, + pkcs11h_getMessage (rv), + *p_target_size + ); + + return rv; +} + +CK_RV +pkcs11h_certificate_create ( + IN const pkcs11h_certificate_id_t certificate_id, + IN const int nPINCachePeriod, + OUT pkcs11h_certificate_t * const p_certificate +) { + pkcs11h_certificate_t certificate = NULL; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (p_certificate!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_create entry certificate_id=%p, nPINCachePeriod=%d, p_certificate=%p", + (void *)certificate_id, + nPINCachePeriod, + (void *)p_certificate + ); + + *p_certificate = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ((void*)&certificate, sizeof (struct pkcs11h_certificate_s))) == CKR_OK + ) { + certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE; + certificate->nPINCachePeriod = nPINCachePeriod; + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (rv == CKR_OK) { + rv = _pkcs11h_mutexInit (&certificate->mutexCertificate); + } +#endif + + if (rv == CKR_OK) { + rv = pkcs11h_duplicateCertificateId (&certificate->id, certificate_id); + } + + if (rv == CKR_OK) { + *p_certificate = certificate; + certificate = NULL; + } + + if (certificate != NULL) { +#if defined(ENABLE_PKCS11H_THREADING) + _pkcs11h_mutexFree (&certificate->mutexCertificate); +#endif + _pkcs11h_free ((void *)&certificate); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_create return rv=%ld-'%s' *p_certificate=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_certificate + ); + + return rv; +} + +CK_RV +pkcs11h_certificate_getCertificateId ( + IN const pkcs11h_certificate_t certificate, + OUT pkcs11h_certificate_id_t * const p_certificate_id +) { + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + PKCS11H_ASSERT (p_certificate_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_getCertificateId entry certificate=%p, certificate_id=%p", + (void *)certificate, + (void *)p_certificate_id + ); + + if (rv == CKR_OK) { + rv = pkcs11h_duplicateCertificateId ( + p_certificate_id, + certificate->id + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_getCertificateId return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; +} + +CK_RV +pkcs11h_certificate_getCertificateBlob ( + IN const pkcs11h_certificate_t certificate, + OUT unsigned char * const certificate_blob, + IN OUT size_t * const p_certificate_blob_size +) { + size_t certifiate_blob_size_max = 0; + + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); + /*PKCS11H_ASSERT (certificate_blob!=NULL); NOT NEEDED */ + PKCS11H_ASSERT (p_certificate_blob_size!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_getCertificateBlob entry certificate=%p, certificate_blob=%p, p_certificate_blob_size=%p", + (void *)certificate, + certificate_blob, + (void *)p_certificate_blob_size + ); + + certifiate_blob_size_max = *p_certificate_blob_size; + *p_certificate_blob_size = 0; + + if (rv == CKR_OK) { + rv = _pkcs11h_ensureCertificateBlob (certificate); + } + + if (rv == CKR_OK) { + *p_certificate_blob_size = certificate->id->certificate_blob_size; + } - i++; + if (certificate_blob != NULL) { + if ( + rv == CKR_OK && + certifiate_blob_size_max > certificate->id->certificate_blob_size + ) { + rv = CKR_BUFFER_TOO_SMALL; + } + + if (rv == CKR_OK) { + memmove ( + certificate_blob, + certificate->id->certificate_blob, + *p_certificate_blob_size + ); } - p++; } -} -static -void -_isBetterCertificate_getExpiration ( - IN const unsigned char * const pCertificate, - IN const size_t nCertificateSize, - OUT char * const szNotBefore, - IN const int nNotBeforeSize -) { - /* - * 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. - */ + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_getCertificateBlob return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); - X509 *x509 = NULL; + return rv; +} - PKCS11ASSERT (pCertificate!=NULL); - PKCS11ASSERT (szNotBefore!=NULL); - PKCS11ASSERT (nNotBeforeSize>0); +CK_RV +pkcs11h_certificate_ensureCertificateAccess ( + IN const pkcs11h_certificate_t certificate, + IN const unsigned maskPrompt +) { + PKCS11H_BOOL fValidCert = FALSE; + CK_RV rv = CKR_OK; - szNotBefore[0] = '\0'; + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); - x509 = X509_new (); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_ensureCertificateAccess entry certificate=%p, maskPrompt=%08x", + (void *)certificate, + maskPrompt + ); - if (x509 != NULL) { - pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)pCertificate; + if (!fValidCert && rv == CKR_OK) { + CK_OBJECT_HANDLE h = PKCS11H_INVALID_OBJECT_HANDLE; if ( - d2i_X509 (&x509, &d2i, nCertificateSize) + (rv = _pkcs11h_getObjectById ( + certificate->session, + CKO_CERTIFICATE, + certificate->id->attrCKA_ID, + certificate->id->attrCKA_ID_size, + &h + )) == CKR_OK ) { - ASN1_TIME *notBefore = X509_get_notBefore (x509); - ASN1_TIME *notAfter = X509_get_notAfter (x509); + fValidCert = TRUE; + } - if ( - notBefore != NULL && - X509_cmp_current_time (notBefore) <= 0 && - X509_cmp_current_time (notAfter) >= 0 && - notBefore->length < nNotBeforeSize - 1 - ) { - memmove (szNotBefore, notBefore->data, notBefore->length); - szNotBefore[notBefore->length] = '\0'; - } + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot access existing object rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; } } - if (x509 != NULL) { - X509_free (x509); - x509 = NULL; + if (!fValidCert && rv == CKR_OK) { + if ( + (rv = _pkcs11h_resetCertificateSession ( + certificate, + TRUE, + maskPrompt + )) == CKR_OK + ) { + fValidCert = TRUE; + } } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_ensureCertificateAccess return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + return rv; } -static -bool -_isBetterCertificate ( - IN const unsigned char * const pCurrent, - IN const size_t nCurrentSize, - IN const unsigned char * const pNew, - IN const size_t nNewSize +CK_RV +pkcs11h_certificate_ensureKeyAccess ( + IN const pkcs11h_certificate_t certificate, + IN const unsigned maskPrompt ) { - /* - * 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. - */ + CK_RV rv = CKR_OK; + PKCS11H_BOOL fValidKey = FALSE; - bool fBetter = false; + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (certificate!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _isBetterCertificate entry pCurrent=%p, nCurrentSize=%u, pNew=%p, nNewSize=%u", - pCurrent, - nCurrentSize, - pNew, - nNewSize + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_ensureKeyAccess entry certificate=%p, maskPrompt=%08x", + (void *)certificate, + maskPrompt ); - /* - * First certificae - * always select - */ - if (nCurrentSize == 0) { - fBetter = true; - } - else { - char szNotBeforeCurrent[1024], szNotBeforeNew[1024]; + if (!fValidKey && rv == CKR_OK) { + if ( + (rv = _pkcs11h_getObjectById ( + certificate->session, + CKO_PRIVATE_KEY, + certificate->id->attrCKA_ID, + certificate->id->attrCKA_ID_size, + &certificate->hKey + )) == CKR_OK + ) { + fValidKey = TRUE; + } - _isBetterCertificate_getExpiration ( - pCurrent, - nCurrentSize, - szNotBeforeCurrent, - sizeof (szNotBeforeCurrent) - ); - _isBetterCertificate_getExpiration ( - pNew, - nNewSize, - szNotBeforeNew, - sizeof (szNotBeforeNew) - ); + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot access existing object rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _isBetterCertificate szNotBeforeCurrent=%s, szNotBeforeNew=%s", - szNotBeforeCurrent, - szNotBeforeNew - ); + /* + * Ignore error + */ + rv = CKR_OK; + certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE; + } + } - fBetter = strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0; + if (!fValidKey && rv == CKR_OK) { + if ( + (rv = _pkcs11h_resetCertificateSession ( + certificate, + FALSE, + maskPrompt + )) == CKR_OK + ) { + fValidKey = TRUE; + } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _isBetterCertificate return fBetter=%d", - fBetter ? 1 : 0 + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_certificate_ensureKeyAccess return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) ); - return fBetter; + return rv; } -/*======================================== - * Low level PKCS#11 functions - */ +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#if defined(ENABLE_PKCS11H_LOCATE) +/*======================================================================* + * LOCATE INTERFACE + *======================================================================*/ + +#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE) static CK_RV -_pkcs11h_getSlotById ( +_pkcs11h_locate_getTokenIdBySlotId ( IN const char * const szSlot, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot + OUT pkcs11h_token_id_t * const p_token_id ) { - int provider_number; - int slot_number; + pkcs11h_provider_t current_provider = NULL; + char szReferenceName[sizeof (((pkcs11h_provider_t)NULL)->szReferenceName)]; + + CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID; + CK_TOKEN_INFO info; CK_RV rv = CKR_OK; - PKCS11ASSERT (szSlot!=NULL); - PKCS11ASSERT (provider!=NULL); - PKCS11ASSERT (slot!=NULL); + PKCS11H_ASSERT (szSlot!=NULL); + PKCS11H_ASSERT (p_token_id!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotById entry szSlot=%s, provider=%p, slot=%p", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdBySlotId entry szSlot='%s', p_token_id=%p", szSlot, - (void *)provider, - (void *)slot + (void *)p_token_id ); + *p_token_id = NULL; + if (rv == CKR_OK) { if (strchr (szSlot, ':') == NULL) { - provider_number = 0; - slot_number = atoi (szSlot); + szReferenceName[0] = '\0'; + selected_slot = atol (szSlot); } else { - if (sscanf (szSlot, "%d:%d", &provider_number, &slot_number) != 2) { - rv = CKR_FUNCTION_FAILED; - } + char *p; + + strncpy (szReferenceName, szSlot, sizeof (szReferenceName)); + szReferenceName[sizeof (szReferenceName)-1] = '\0'; + + p = strchr (szReferenceName, ':'); + + *p = '\0'; + p++; + selected_slot = atol (p); } } if (rv == CKR_OK) { - pkcs11h_provider_t current_provider; - int i; - - for ( - i=0, current_provider=pkcs11h_data->providers; - ( - i < provider_number && - current_provider != NULL && - rv == CKR_OK - ); - i++, current_provider = current_provider->next - ); + current_provider=s_pkcs11h_data->providers; + while ( + current_provider != NULL && + szReferenceName[0] != '\0' && /* So first provider will be selected */ + strcmp (current_provider->szReferenceName, szReferenceName) + ) { + current_provider = current_provider->next; + } if ( current_provider == NULL || @@ -499,17 +5947,24 @@ _pkcs11h_getSlotById ( ) { rv = CKR_SLOT_ID_INVALID; } - else { - *provider = current_provider; - *slot = slot_number; - } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotById return rv=%ld-'%s'", + if ( + rv == CKR_OK && + (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK + ) { + rv = _pkcs11h_getTokenId ( + &info, + p_token_id + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdBySlotId return rv=%ld-'%s', *p_token_id=%p", rv, - pkcs11h_getMessage (rv) + pkcs11h_getMessage (rv), + (void *)*p_token_id ); return rv; @@ -517,597 +5972,626 @@ _pkcs11h_getSlotById ( static CK_RV -_pkcs11h_getSlotByName ( +_pkcs11h_locate_getTokenIdBySlotName ( IN const char * const szName, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot + OUT pkcs11h_token_id_t * const p_token_id ) { + pkcs11h_provider_t current_provider = NULL; + + CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID; + CK_TOKEN_INFO info; CK_RV rv = CKR_OK; - pkcs11h_provider_t current_provider; - bool fFound = false; + PKCS11H_BOOL fFound = FALSE; - PKCS11ASSERT (szName!=NULL); - PKCS11ASSERT (provider!=NULL); - PKCS11ASSERT (slot!=NULL); + PKCS11H_ASSERT (szName!=NULL); + PKCS11H_ASSERT (p_token_id!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotByName entry szName=%s, provider=%p, slot=%p", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdBySlotName entry szName='%s', p_token_id=%p", szName, - (void *)provider, - (void *)slot + (void *)p_token_id ); - for ( - current_provider = pkcs11h_data->providers; - ( - current_provider != NULL && - !fFound - ); - current_provider = current_provider->next + *p_token_id = NULL; + + current_provider = s_pkcs11h_data->providers; + while ( + current_provider != NULL && + rv == CKR_OK && + !fFound ) { - CK_SLOT_ID slots[1024]; + CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; + CK_SLOT_ID slot_index; if (!current_provider->fEnabled) { continue; } - slotnum = sizeof (slots) / sizeof (CK_SLOT_ID); - if ( - (rv = current_provider->f->C_GetSlotList ( - TRUE, - slots, + if (rv == CKR_OK) { + rv = _pkcs11h_getSlotList ( + current_provider, + CK_TRUE, + &slots, &slotnum - )) == CKR_OK + ); + } + + for ( + slot_index=0; + ( + slot_index < slotnum && + rv == CKR_OK && + !fFound + ); + slot_index++ ) { - CK_SLOT_ID s; + CK_SLOT_INFO info; - for (s=0;!fFound && sf->C_GetSlotInfo ( + slots[slot_index], + &info + )) == CKR_OK + ) { + char szCurrentName[sizeof (info.slotDescription)+1]; - if ( - (rv = current_provider->f->C_GetSlotInfo ( - slots[s], - &info - )) == CKR_OK - ) { - char szCurrentName[sizeof (info.slotDescription)+1]; - - _pkcs11h_fixupFixedString ( - (char *)info.slotDescription, - szCurrentName, - sizeof (info.slotDescription) - ); + _pkcs11h_fixupFixedString ( + szCurrentName, + (char *)info.slotDescription, + sizeof (info.slotDescription) + ); - if (!strcmp (szCurrentName, szName)) { - fFound = true; - *provider = current_provider; - *slot = slots[s]; - } + if (!strcmp (szCurrentName, szName)) { + fFound = TRUE; + selected_slot = slots[slot_index]; } } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot information for provider '%s' slot %ld rv=%ld-'%s'", + current_provider->manufacturerID, + slots[slot_index], + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'", + current_provider->manufacturerID, + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + slots = NULL; + } + + if (!fFound) { + current_provider = current_provider->next; } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotByName return fFound=%d-'%s'", - fFound ? 1 : 0, - pkcs11h_getMessage (rv) + if (rv == CKR_OK && !fFound) { + rv = CKR_SLOT_ID_INVALID; + } + + if ( + rv == CKR_OK && + (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK + ) { + rv = _pkcs11h_getTokenId ( + &info, + p_token_id + ); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdBySlotName return rv=%ld-'%s' *p_token_id=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_token_id ); - return fFound ? CKR_OK : CKR_SLOT_ID_INVALID; + return rv; } static CK_RV -_pkcs11h_getSlotByLabel ( +_pkcs11h_locate_getTokenIdByLabel ( IN const char * const szLabel, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot + OUT pkcs11h_token_id_t * const p_token_id ) { - CK_RV rv; + pkcs11h_provider_t current_provider = NULL; - pkcs11h_provider_t current_provider; - bool fFound = false; + CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID; + CK_TOKEN_INFO info; + CK_RV rv = CKR_OK; - PKCS11ASSERT (szLabel!=NULL); - PKCS11ASSERT (provider!=NULL); - PKCS11ASSERT (slot!=NULL); + PKCS11H_BOOL fFound = FALSE; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotByLabel entry szLabel=%s, provider=%p, slot=%p", + PKCS11H_ASSERT (szLabel!=NULL); + PKCS11H_ASSERT (p_token_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdByLabel entry szLabel='%s', p_token_id=%p", szLabel, - (void *)provider, - (void *)slot + (void *)p_token_id ); - for ( - current_provider = pkcs11h_data->providers; - ( - current_provider != NULL && - !fFound - ); - current_provider = current_provider->next + *p_token_id = NULL; + + current_provider = s_pkcs11h_data->providers; + while ( + current_provider != NULL && + rv == CKR_OK && + !fFound ) { - CK_SLOT_ID slots[1024]; + CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; + CK_SLOT_ID slot_index; if (!current_provider->fEnabled) { continue; } - slotnum = sizeof (slots) / sizeof (CK_SLOT_ID); - if ( - (rv = current_provider->f->C_GetSlotList ( - TRUE, - slots, + if (rv == CKR_OK) { + rv = _pkcs11h_getSlotList ( + current_provider, + CK_TRUE, + &slots, &slotnum - )) == CKR_OK + ); + } + + for ( + slot_index=0; + ( + slot_index < slotnum && + rv == CKR_OK && + !fFound + ); + slot_index++ ) { - CK_SLOT_ID s; + CK_TOKEN_INFO info; - for (s=0;!fFound && sf->C_GetTokenInfo ( + slots[slot_index], + &info + ); + } - if ( - (rv = current_provider->f->C_GetTokenInfo ( - slots[s], - &info - )) == CKR_OK - ) { - char szCurrentLabel[sizeof (info.label)+1]; - - _pkcs11h_fixupFixedString ( - (char *)info.label, - szCurrentLabel, - sizeof (info.label) - ); + if (rv == CKR_OK) { + char szCurrentLabel[sizeof (info.label)+1]; + + _pkcs11h_fixupFixedString ( + szCurrentLabel, + (char *)info.label, + sizeof (info.label) + ); - if (!strcmp (szCurrentLabel, szLabel)) { - fFound = true; - *provider = current_provider; - *slot = slots[s]; - } + if (!strcmp (szCurrentLabel, szLabel)) { + fFound = TRUE; + selected_slot = slots[slot_index]; } } - } - } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlotByLabel return fFound=%d", - fFound ? 1 : 0 - ); + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'", + current_provider->manufacturerID, + slots[slot_index], + rv, + pkcs11h_getMessage (rv) + ); - return fFound ? CKR_OK : CKR_SLOT_ID_INVALID; -} + /* + * Ignore error + */ + rv = CKR_OK; + } + } -static -CK_RV -_pkcs11h_getSlot ( - IN const char * const szSlotType, - IN const char * const szSlot, - OUT pkcs11h_provider_t * const provider, - OUT CK_SLOT_ID * const slot -) { - CK_RV rv = CKR_OK; + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'", + current_provider->manufacturerID, + rv, + pkcs11h_getMessage (rv) + ); - PKCS11ASSERT (szSlotType!=NULL); - PKCS11ASSERT (szSlot!=NULL); - PKCS11ASSERT (provider!=NULL); - PKCS11ASSERT (slot!=NULL); + /* + * Ignore error + */ + rv = CKR_OK; + } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlot entry szSlotType=%s, szSlot=%s, provider=%p, slot=%p", - szSlotType, - szSlot, - (void *)provider, - (void *)slot - ); + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + slots = NULL; + } - if (!strcmp (szSlotType, "id")) { - rv = _pkcs11h_getSlotById ( - szSlot, - provider, - slot - ); + if (!fFound) { + current_provider = current_provider->next; + } } - else if (!strcmp (szSlotType, "name")) { - rv = _pkcs11h_getSlotByName ( - szSlot, - provider, - slot - ); + + if (rv == CKR_OK && !fFound) { + rv = CKR_SLOT_ID_INVALID; } - else if (!strcmp (szSlotType, "label")) { - rv = _pkcs11h_getSlotByLabel ( - szSlot, - provider, - slot + + if ( + rv == CKR_OK && + (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK + ) { + rv = _pkcs11h_getTokenId ( + &info, + p_token_id ); } - else { - rv = CKR_ARGUMENTS_BAD; - } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSlot return rv=%ld-'%s'", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getTokenIdByLabel return rv=%ld-'%s', *p_token_id=%p", rv, - pkcs11h_getMessage (rv) + pkcs11h_getMessage (rv), + (void *)*p_token_id ); return rv; } -static CK_RV -_pkcs11h_getSession ( +pkcs11h_locate_token ( IN const char * const szSlotType, IN const char * const szSlot, - IN const bool fProtectedAuthentication, - IN const int nPINCachePeriod, - OUT pkcs11h_session_t * const session + OUT pkcs11h_token_id_t * const p_token_id ) { - CK_TOKEN_INFO info; - CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID; - CK_RV rv = CKR_OK; +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif - pkcs11h_provider_t provider = NULL; + pkcs11h_token_id_t dummy_token_id = NULL; + pkcs11h_token_id_t token_id = NULL; + PKCS11H_BOOL fFound = FALSE; + + CK_RV rv = CKR_OK; - PKCS11ASSERT (szSlotType!=NULL); - PKCS11ASSERT (szSlot!=NULL); - PKCS11ASSERT (session!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (szSlotType!=NULL); + PKCS11H_ASSERT (szSlot!=NULL); + PKCS11H_ASSERT (p_token_id!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSession entry szSlotType=%s, szSlot=%s, fProtectedAuthentication=%d, nPINCachePeriod=%d, session=%p", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_locate_token entry szSlotType='%s', szSlot='%s', p_token_id=%p", szSlotType, szSlot, - fProtectedAuthentication ? 1 : 0, - nPINCachePeriod, - (void *)session + (void *)p_token_id ); - if (rv == CKR_OK) { - do { - rv = _pkcs11h_getSlot ( - szSlotType, - szSlot, - &provider, - &slot - ); - - if (rv == CKR_SLOT_ID_INVALID) { - char szLabel[1024]; - strcpy (szLabel, "SLOT("); - strncat (szLabel, szSlotType, sizeof (szLabel)-1-strlen (szLabel)); - strncat (szLabel, "=", sizeof (szLabel)-1-strlen (szLabel)); - strncat (szLabel, szSlot, sizeof (szLabel)-1-strlen (szLabel)); - strncat (szLabel, ")", sizeof (szLabel)-1-strlen (szLabel)); - szLabel[sizeof (szLabel)-1] = 0; - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Calling card_prompt hook for %s", - szLabel - ); - if ( - !pkcs11h_data->hooks->card_prompt ( - pkcs11h_data->hooks->card_prompt_data, - szLabel - ) - ) { - rv = CKR_CANCEL; - } - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: card_prompt returned rv=%ld", - rv - ); - } - } while (rv == CKR_SLOT_ID_INVALID); + *p_token_id = NULL; + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK + ) { + fMutexLocked = TRUE; } +#endif - if (rv == CKR_OK) { - rv = provider->f->C_GetTokenInfo ( - slot, - &info - ); + if ( + rv == CKR_OK && + (rv = _pkcs11h_newTokenId (&dummy_token_id)) == CKR_OK + ) { + /* + * Temperary slot id + */ + strcpy (dummy_token_id->label, "SLOT("); + strncat (dummy_token_id->label, szSlotType, sizeof (dummy_token_id->label)-1-strlen (dummy_token_id->label)); + strncat (dummy_token_id->label, "=", sizeof (dummy_token_id->label)-1-strlen (dummy_token_id->label)); + strncat (dummy_token_id->label, szSlot, sizeof (dummy_token_id->label)-1-strlen (dummy_token_id->label)); + strncat (dummy_token_id->label, ")", sizeof (dummy_token_id->label)-1-strlen (dummy_token_id->label)); + dummy_token_id->label[sizeof (dummy_token_id->label)-1] = 0; } - if (rv == CKR_OK) { - pkcs11h_session_t current_session; + while (rv == CKR_OK && !fFound) { + if (!strcmp (szSlotType, "id")) { + rv = _pkcs11h_locate_getTokenIdBySlotId ( + szSlot, + &token_id + ); + } + else if (!strcmp (szSlotType, "name")) { + rv = _pkcs11h_locate_getTokenIdBySlotName ( + szSlot, + &token_id + ); + } + else if (!strcmp (szSlotType, "label")) { + rv = _pkcs11h_locate_getTokenIdByLabel ( + szSlot, + &token_id + ); + } + else { + rv = CKR_ARGUMENTS_BAD; + } - for ( - current_session = pkcs11h_data->sessions, *session=NULL; - current_session != NULL && *session == NULL; - current_session = current_session->next - ) { - if ( - current_session->provider == provider && - !memcmp ( - current_session->serialNumber, - info.serialNumber, - sizeof (current_session->serialNumber) - ) - ) { - *session = current_session; - } + if (rv == CKR_OK) { + fFound = TRUE; } - } - if (rv == CKR_OK) { - if (*session == NULL) { - + if (!fFound && rv != CKR_ARGUMENTS_BAD) { + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: pkcs11h_locate_token failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling token_prompt hook for '%s'", + dummy_token_id->label + ); + if ( - rv == CKR_OK && - (*session = (pkcs11h_session_t)malloc ( - sizeof (struct pkcs11h_session_s) - )) == NULL + !s_pkcs11h_data->hooks.token_prompt ( + s_pkcs11h_data->hooks.token_prompt_data, + dummy_token_id + ) ) { - rv = CKR_HOST_MEMORY; + rv = CKR_CANCEL; } - if (rv == CKR_OK) { - memset (*session, 0, sizeof (struct pkcs11h_session_s)); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: token_prompt returned %ld", + rv + ); + } + } - (*session)->fValid = true; - (*session)->nReferenceCount = 1; - (*session)->fProtectedAuthentication = fProtectedAuthentication; - (*session)->hSession = PKCS11H_INVALID_SESSION_HANDLE; - - (*session)->provider = provider; + if (rv == CKR_OK && !fFound) { + rv = CKR_SLOT_ID_INVALID; + } - if (nPINCachePeriod == PKCS11H_PIN_CACHE_INFINITE) { - (*session)->nPINCachePeriod = pkcs11h_data->nPINCachePeriod; - } - else { - (*session)->nPINCachePeriod = nPINCachePeriod; - } + if (rv == CKR_OK) { + *p_token_id = token_id; + token_id = NULL; + } - provider = NULL; - - _pkcs11h_fixupFixedString ( - (char *)info.label, - (*session)->szLabel, - sizeof (info.label) - ); - - memmove ( - (*session)->serialNumber, - info.serialNumber, - sizeof (info.serialNumber) - ); + if (dummy_token_id != NULL) { + pkcs11h_freeTokenId (dummy_token_id); + dummy_token_id = NULL; + } - (*session)->next = pkcs11h_data->sessions; - pkcs11h_data->sessions = *session; - } - } - else { - (*session)->nReferenceCount++; - if (nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) { - if ((*session)->nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) { - if ((*session)->nPINCachePeriod > nPINCachePeriod) { - (*session)->timePINExpire = ( - (*session)->timePINExpire - - (time_t)(*session)->nPINCachePeriod + - (time_t)nPINCachePeriod - ); - (*session)->nPINCachePeriod = nPINCachePeriod; - } - } - else { - (*session)->timePINExpire = ( - PKCS11_TIME (NULL) + - (time_t)nPINCachePeriod - ); - (*session)->nPINCachePeriod = nPINCachePeriod; - } - rv = _pkcs11h_validateSession (*session); - } - } +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; } +#endif - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getSession return rv=%ld-'%s'", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_locate_token return rv=%ld-'%s', *p_token_id=%p", rv, - pkcs11h_getMessage (rv) + pkcs11h_getMessage (rv), + (void *)*p_token_id ); return rv; } -static -CK_RV -_pkcs11h_releaseSession ( - IN const pkcs11h_session_t session -) { - PKCS11ASSERT (session!=NULL); - PKCS11ASSERT (session->nReferenceCount>=0); - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_releaseSession session=%p", - (void *)session - ); - - /* - * Never logout for now - */ - - if (session->nReferenceCount > 0) { - session->nReferenceCount--; - } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_releaseSession return" - ); +#endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */ - return CKR_OK; -} +#if defined(ENABLE_PKCS11H_CERTIFICATE) static -CK_RV -_pkcs11h_resetSession ( - IN const pkcs11h_session_t session, - OUT CK_SLOT_ID * const slot +void +_pkcs11h_locate_hexToBinary ( + OUT unsigned char * const target, + IN const char * const szSource, + IN OUT size_t * const p_target_size ) { - CK_SLOT_ID slots[1024]; - CK_ULONG slotnum; - CK_RV rv; - bool fFound = false; - bool fCancel = false; - - PKCS11ASSERT (session!=NULL); - PKCS11ASSERT (slot!=NULL); + size_t target_max_size; + const char *p; + char buf[3] = {'\0', '\0', '\0'}; + int i = 0; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_resetSession entry session=%p, slot=%p", - (void *)session, - (void *)slot - ); + PKCS11H_ASSERT (szSource!=NULL); + PKCS11H_ASSERT (target!=NULL); + PKCS11H_ASSERT (p_target_size!=NULL); - do { - slotnum = sizeof (slots) / sizeof (CK_SLOT_ID); - if ( - (rv = session->provider->f->C_GetSlotList ( - TRUE, - slots, - &slotnum - )) == CKR_OK - ) { - CK_SLOT_ID s; + target_max_size = *p_target_size; + p = szSource; + *p_target_size = 0; - for (s=0;!fFound && sprovider->f->C_GetTokenInfo ( - slots[s], - &info - )) == CKR_OK - ) { - if ( - !memcmp ( - session->serialNumber, - info.serialNumber, - sizeof (session->serialNumber) - ) - ) { - *slot = slots[s]; - fFound = true; - } + if ((i%2) == 1) { + unsigned v; + if (sscanf (buf, "%x", &v) != 1) { + v = 0; } + target[*p_target_size] = v & 0xff; + (*p_target_size)++; } - } - - if (!fFound) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Calling card_prompt hook for %s", - session->szLabel - ); - - fCancel = !pkcs11h_data->hooks->card_prompt ( - pkcs11h_data->hooks->card_prompt_data, - session->szLabel - ); - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: card_prompt returned %d", - fCancel ? 1 : 0 - ); + i++; } - } while (!fFound && !fCancel); - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_resetSession return fFound=%d", - fFound ? 1 : 0 - ); - - return fFound ? CKR_OK : CKR_SLOT_ID_INVALID; + p++; + } } static CK_RV -_pkcs11h_getObjectById ( +_pkcs11h_locate_getCertificateIdByLabel ( IN const pkcs11h_session_t session, - IN const CK_OBJECT_CLASS class, - IN const unsigned char * const id, - IN const size_t id_size, - OUT CK_OBJECT_HANDLE * const handle + IN OUT const pkcs11h_certificate_id_t certificate_id, + IN const char * const szLabel ) { - CK_ULONG count; + CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE; + CK_ATTRIBUTE cert_filter[] = { + {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}, + {CKA_LABEL, (CK_BYTE_PTR)szLabel, strlen (szLabel)} + }; + + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; CK_RV rv = CKR_OK; - CK_ATTRIBUTE filter[] = { - {CKA_CLASS, (void *)&class, sizeof (class)}, - {CKA_ID, (void *)id, id_size} - }; - - PKCS11ASSERT (session!=NULL); - PKCS11ASSERT (id!=NULL); - PKCS11ASSERT (handle!=NULL); + CK_ULONG i; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getObjectById entry session=%p, class=%ld, id=%p, id_size=%u, handle=%p", - (void *)session, - class, - id, - id_size, - (void *)handle + PKCS11H_ASSERT (session!=NULL); + PKCS11H_ASSERT (certificate_id!=NULL); + PKCS11H_ASSERT (szLabel!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getCertificateIdByLabel entry session=%p, certificate_id=%p, szLabel='%s'", + (void *)session, + (void *)certificate_id, + szLabel ); - /* - * Don't try invalid session - */ - if ( - rv == CKR_OK && - session->hSession == PKCS11H_INVALID_SESSION_HANDLE - ) { - rv = CKR_SESSION_HANDLE_INVALID; + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); } if (rv == CKR_OK) { - rv = session->provider->f->C_FindObjectsInit ( - session->hSession, - filter, - sizeof (filter) / sizeof (CK_ATTRIBUTE) + rv = _pkcs11h_findObjects ( + session, + cert_filter, + sizeof (cert_filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found ); } - if (rv == CKR_OK) { - rv = session->provider->f->C_FindObjects ( - session->hSession, - handle, - 1, - &count + for (i=0;rv == CKR_OK && i < objects_found;i++) { + CK_ATTRIBUTE attrs[] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0} + }; + + if (rv == CKR_OK) { + rv = _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + } + + if ( + rv == CKR_OK && + _pkcs11h_isBetterCertificate ( + certificate_id->certificate_blob, + certificate_id->certificate_blob_size, + attrs[1].pValue, + attrs[1].ulValueLen + ) + ) { + if (certificate_id->attrCKA_ID != NULL) { + _pkcs11h_free ((void *)&certificate_id->attrCKA_ID); + } + if (certificate_id->certificate_blob != NULL) { + _pkcs11h_free ((void *)&certificate_id->certificate_blob); + } + rv = _pkcs11h_dupmem ( + (void *)&certificate_id->attrCKA_ID, + &certificate_id->attrCKA_ID_size, + attrs[0].pValue, + attrs[0].ulValueLen + ); + rv = _pkcs11h_dupmem ( + (void *)&certificate_id->certificate_blob, + &certificate_id->certificate_blob_size, + attrs[1].pValue, + attrs[1].ulValueLen + ); + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'", + session->provider->manufacturerID, + objects[i], + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) ); } - + if ( rv == CKR_OK && - count == 0 + certificate_id->certificate_blob == NULL ) { - rv = CKR_FUNCTION_REJECTED; + rv = CKR_ATTRIBUTE_VALUE_INVALID; } - session->provider->f->C_FindObjectsFinal (session->hSession); + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + + /* + * No need to free allocated objects + * on error, since the certificate_id + * should be free by caller. + */ - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getObjectById return rv=%ld-'%s'", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getCertificateIdByLabel return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); @@ -1117,152 +6601,159 @@ _pkcs11h_getObjectById ( static CK_RV -_pkcs11h_validateSession ( - IN const pkcs11h_session_t session -) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_validateSession entry session=%p", - (void *)session - ); - - if ( - session->timePINExpire != (time_t)0 && - session->timePINExpire < PKCS11_TIME (NULL) - ) { - _pkcs11h_logout (session); - } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_validateSession return" - ); - - return CKR_OK; -} - -static -CK_RV -_pkcs11h_login ( +_pkcs11h_locate_getCertificateIdBySubject ( IN const pkcs11h_session_t session, - IN const bool fPublicOnly + IN OUT const pkcs11h_certificate_id_t certificate_id, + IN const char * const szSubject ) { - CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID; + CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE; + CK_ATTRIBUTE cert_filter[] = { + {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)} + }; + + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; CK_RV rv = CKR_OK; - PKCS11ASSERT (session!=NULL); + CK_ULONG i; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_login entry session=%p, fPublicOnly=%d", + PKCS11H_ASSERT (session!=NULL); + PKCS11H_ASSERT (certificate_id!=NULL); + PKCS11H_ASSERT (szSubject!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getCertificateIdBySubject entry session=%p, certificate_id=%p, szSubject=%s", (void *)session, - fPublicOnly ? 1 : 0 + (void *)certificate_id, + szSubject ); if (rv == CKR_OK) { - rv = _pkcs11h_logout (session); - } - - if (rv == CKR_OK) { - rv = _pkcs11h_resetSession (session, &slot); + rv = _pkcs11h_validateSession (session); } if (rv == CKR_OK) { - rv = session->provider->f->C_OpenSession ( - slot, - CKF_SERIAL_SESSION, - NULL_PTR, - NULL_PTR, - &session->hSession + rv = _pkcs11h_findObjects ( + session, + cert_filter, + sizeof (cert_filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found ); } - if (rv == CKR_OK) { - if (!fPublicOnly) { - int nRetryCount = 0; - do { - CK_UTF8CHAR_PTR utfPIN = NULL; - CK_ULONG lPINLength = 0; - char szPIN[1024]; + for (i=0;rv == CKR_OK && i < objects_found;i++) { + CK_ATTRIBUTE attrs[] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0} + }; + char szCurrentSubject[1024]; + szCurrentSubject[0] = '\0'; - /* - * Assume OK for next iteration - */ - rv = CKR_OK; + if (rv == CKR_OK) { + rv = _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + } - if ( - rv == CKR_OK && - !session->fProtectedAuthentication - ) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Calling pin_prompt hook for %s", - session->szLabel - ); - - if ( - !pkcs11h_data->hooks->pin_prompt ( - pkcs11h_data->hooks->pin_prompt_data, - session->szLabel, - szPIN, - sizeof (szPIN) - ) - ) { - rv = CKR_FUNCTION_FAILED; - } - else { - utfPIN = (CK_UTF8CHAR_PTR)szPIN; - lPINLength = strlen (szPIN); - } + if (rv == CKR_OK) { + X509 *x509 = NULL; + pkcs11_openssl_d2i_t d2i1; - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: pin_prompt hook return rv=%ld", - rv - ); - - } + x509 = X509_new (); - if (session->nPINCachePeriod == PKCS11H_PIN_CACHE_INFINITE) { - session->timePINExpire = 0; - } - else { - session->timePINExpire = ( - PKCS11_TIME (NULL) + - (time_t)session->nPINCachePeriod - ); - } - if ( - rv == CKR_OK && - (rv = session->provider->f->C_Login ( - session->hSession, - CKU_USER, - utfPIN, - lPINLength - )) != CKR_OK - ) { - if (rv == CKR_USER_ALREADY_LOGGED_IN) { - rv = CKR_OK; - } - } + d2i1 = (pkcs11_openssl_d2i_t)attrs[1].pValue; + if (d2i_X509 (&x509, &d2i1, attrs[1].ulValueLen)) { + X509_NAME_oneline ( + X509_get_subject_name (x509), + szCurrentSubject, + sizeof (szCurrentSubject) + ); + szCurrentSubject[sizeof (szCurrentSubject) - 1] = '\0'; + } - /* - * Clean PIN buffer - */ - memset (szPIN, 0, sizeof (szPIN)); - } while ( - ++nRetryCount < 3 && - ( - rv == CKR_PIN_INCORRECT || - rv == CKR_PIN_INVALID - ) + if (x509 != NULL) { + X509_free (x509); + x509 = NULL; + } + } + + if ( + rv == CKR_OK && + !strcmp (szSubject, szCurrentSubject) && + _pkcs11h_isBetterCertificate ( + certificate_id->certificate_blob, + certificate_id->certificate_blob_size, + attrs[1].pValue, + attrs[1].ulValueLen + ) + ) { + if (certificate_id->attrCKA_ID != NULL) { + _pkcs11h_free ((void *)&certificate_id->attrCKA_ID); + } + if (certificate_id->certificate_blob != NULL) { + _pkcs11h_free ((void *)&certificate_id->certificate_blob); + } + rv = _pkcs11h_dupmem ( + (void *)&certificate_id->attrCKA_ID, + &certificate_id->attrCKA_ID_size, + attrs[0].pValue, + attrs[0].ulValueLen + ); + rv = _pkcs11h_dupmem ( + (void *)&certificate_id->certificate_blob, + &certificate_id->certificate_blob_size, + attrs[1].pValue, + attrs[1].ulValueLen ); } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'", + session->provider->manufacturerID, + objects[i], + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + } + + if ( + rv == CKR_OK && + certificate_id->certificate_blob == NULL + ) { + rv = CKR_ATTRIBUTE_VALUE_INVALID; } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_login return rv=%ld-'%s'", + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + + /* + * No need to free allocated objects + * on error, since the certificate_id + * should be free by caller. + */ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_locate_getCertificateIdBySubject return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); @@ -1270,754 +6761,1045 @@ _pkcs11h_login ( return rv; } -static CK_RV -_pkcs11h_logout ( - IN const pkcs11h_session_t session +pkcs11h_locate_certificate ( + IN const char * const szSlotType, + IN const char * const szSlot, + IN const char * const szIdType, + IN const char * const szId, + OUT pkcs11h_certificate_id_t * const p_certificate_id ) { - PKCS11ASSERT (session!=NULL); + pkcs11h_certificate_id_t certificate_id = NULL; + pkcs11h_session_t session = NULL; + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; + + CK_RV rv = CKR_OK; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_logout entry session=%p", - (void *)session + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (szSlotType!=NULL); + PKCS11H_ASSERT (szSlot!=NULL); + PKCS11H_ASSERT (szIdType!=NULL); + PKCS11H_ASSERT (szId!=NULL); + PKCS11H_ASSERT (p_certificate_id!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_locateCertificate entry szSlotType='%s', szSlot='%s', szIdType='%s', szId='%s', p_certificate_id=%p", + szSlotType, + szSlot, + szIdType, + szId, + (void *)p_certificate_id ); - if (session->hSession != PKCS11H_INVALID_SESSION_HANDLE) { - session->provider->f->C_Logout (session->hSession); - session->provider->f->C_CloseSession (session->hSession); - session->hSession = PKCS11H_INVALID_SESSION_HANDLE; - } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_logout return" - ); + *p_certificate_id = NULL; - return CKR_OK; -} + if (rv == CKR_OK) { + rv = _pkcs11h_newCertificateId (&certificate_id); + } -static -CK_RV -_pkcs11h_setCertificateSession_Certificate ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - IN const char * const szIdType, - IN const char * const szId -) { - CK_RV rv = CKR_OK; + if (rv == CKR_OK) { + rv = pkcs11h_locate_token ( + szSlotType, + szSlot, + &certificate_id->token_id + ); + } - unsigned char selected_id[PKCS11H_MAX_ATTRIBUTE_SIZE]; - int selected_id_size = 0; - unsigned char selected_certificate[PKCS11H_MAX_ATTRIBUTE_SIZE]; - int selected_certificate_size = 0; + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + certificate_id->token_id, + &session + ); + } - CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE; - unsigned char cert_filter_by[PKCS11H_MAX_ATTRIBUTE_SIZE]; - CK_ATTRIBUTE cert_filter[] = { - {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}, - {0, cert_filter_by, 0} - }; - int cert_filter_num = 1; + while (rv == CKR_OK && !fOpSuccess) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif - PKCS11ASSERT (pkcs11h_certificate!=NULL); - PKCS11ASSERT (szIdType!=NULL); - PKCS11ASSERT (szId!=NULL); +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_setCertificateSession_Certificate entry pkcs11h_certificate=%p, szIdType=%s, szId=%s", - (void *)pkcs11h_certificate, - szIdType, - szId - ); + if (!strcmp (szIdType, "id")) { + certificate_id->attrCKA_ID_size = strlen (szId)/2; - if (rv == CKR_OK) { - 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 - ); - cert_filter_num++; + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ( + (void*)&certificate_id->attrCKA_ID, + certificate_id->attrCKA_ID_size + )) == CKR_OK + ) { + _pkcs11h_locate_hexToBinary ( + certificate_id->attrCKA_ID, + szId, + &certificate_id->attrCKA_ID_size + ); + } } - else if (!strcmp (szIdType, "id")) { - size_t s = sizeof (cert_filter_by); - - cert_filter[1].type = CKA_ID; - _hexToBinary ( - szId, - cert_filter_by, - &s + else if (!strcmp (szIdType, "label")) { + rv = _pkcs11h_locate_getCertificateIdByLabel ( + session, + certificate_id, + szId ); - cert_filter[1].ulValueLen = s; - cert_filter_num++; } else if (!strcmp (szIdType, "subject")) { - memmove (&cert_filter[1], &cert_filter[0], sizeof (CK_ATTRIBUTE)); + rv = _pkcs11h_locate_getCertificateIdBySubject ( + session, + certificate_id, + szId + ); } else { rv = CKR_ARGUMENTS_BAD; } - } - - if (rv == CKR_OK) { - rv = pkcs11h_certificate->session->provider->f->C_FindObjectsInit ( - pkcs11h_certificate->session->hSession, - cert_filter, - cert_filter_num - ); - } - - if (rv == CKR_OK) { - CK_OBJECT_HANDLE objects[10]; - CK_ULONG objects_found; - CK_OBJECT_HANDLE oLast = PKCS11H_INVALID_OBJECT_HANDLE; - while ( - (rv = pkcs11h_certificate->session->provider->f->C_FindObjects ( - pkcs11h_certificate->session->hSession, - objects, - sizeof (objects) / sizeof (CK_OBJECT_HANDLE), - &objects_found - )) == CKR_OK && - objects_found > 0 - ) { - CK_ULONG i; +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; + } +#endif - /* - * Begin workaround - * - * Workaround iKey bug - * It returns the same objects over and over - */ - if (oLast == objects[0]) { - PKCS11LOG ( - PKCS11_LOG_WARN, - "PKCS#11: Bad PKCS#11 C_FindObjects implementation detected, workaround applied" - ); - break; - } - oLast = objects[0]; - /* End workaround */ - - for (i=0;isession->provider->f->C_GetAttributeValue ( - pkcs11h_certificate->session->hSession, - objects[i], - attrs, - sizeof (attrs) / sizeof (CK_ATTRIBUTE) - ) == CKR_OK - ) { - bool fSelected = false; - - if (!strcmp (szIdType, "subject")) { - X509 *x509 = NULL; - char szSubject[1024]; - pkcs11_openssl_d2i_t d2i1; - - x509 = X509_new (); - - d2i1 = (pkcs11_openssl_d2i_t)attrs_value; - if (d2i_X509 (&x509, &d2i1, 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 - ); - } - } + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Get certificate failed: %ld:'%s'", + rv, + pkcs11h_getMessage (rv) + ); + + rv = _pkcs11h_login ( + session, + TRUE, + TRUE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + + fLoginRetry = TRUE; } } - - pkcs11h_certificate->session->provider->f->C_FindObjectsFinal ( - pkcs11h_certificate->session->hSession - ); - rv = CKR_OK; } - if ( - rv == CKR_OK && - selected_certificate_size == 0 - ) { - rv = CKR_ATTRIBUTE_VALUE_INVALID; + if (rv == CKR_OK) { + *p_certificate_id = certificate_id; + certificate_id = NULL; } - if ( - rv == CKR_OK && - (pkcs11h_certificate->certificate_id = (unsigned char *)malloc (selected_id_size)) == NULL - ) { - rv = CKR_HOST_MEMORY; + if (certificate_id != NULL) { + pkcs11h_freeCertificateId (certificate_id); + certificate_id = NULL; } - if ( /* should be last on none failure */ - rv == CKR_OK && - (pkcs11h_certificate->certificate = (unsigned char *)malloc (selected_certificate_size)) == NULL - ) { - rv = CKR_HOST_MEMORY; + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; } - if (rv == CKR_OK) { - pkcs11h_certificate->certificate_size = selected_certificate_size; - memmove ( - pkcs11h_certificate->certificate, - selected_certificate, - selected_certificate_size - ); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_locateCertificate return rv=%ld-'%s' *p_certificate_id=%p", + rv, + pkcs11h_getMessage (rv), + (void *)*p_certificate_id + ); + + return rv; +} - pkcs11h_certificate->certificate_id_size = selected_id_size; - memmove ( - pkcs11h_certificate->certificate_id, - selected_id, - selected_id_size - ); +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#endif /* ENABLE_PKCS11H_LOCATE */ + +#if defined(ENABLE_PKCS11H_ENUM) +/*======================================================================* + * ENUM INTERFACE + *======================================================================*/ + +#if defined(ENABLE_PKCS11H_TOKEN) + +CK_RV +pkcs11h_freeTokenIdList ( + IN const pkcs11h_token_id_list_t token_id_list +) { + pkcs11h_token_id_list_t _id = token_id_list; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + /*PKCS11H_ASSERT (token_id_list!=NULL); NOT NEEDED*/ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeTokenIdList entry token_id_list=%p", + (void *)token_id_list + ); + + while (_id != NULL) { + pkcs11h_token_id_list_t x = _id; + _id = _id->next; + if (x->token_id != NULL) { + pkcs11h_freeTokenId (x->token_id); + } + x->next = NULL; + _pkcs11h_free ((void *)&x); } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_setCertificateSession_Certificate return rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeTokenIdList return" ); - return rv; + return CKR_OK; } -static CK_RV -_pkcs11h_getCertificateKeyAttributes ( - IN const pkcs11h_certificate_t pkcs11h_certificate +pkcs11h_enum_getTokenIds ( + IN const int method, + OUT pkcs11h_token_id_list_t * const p_token_id_list ) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + + pkcs11h_token_id_list_t token_id_list = NULL; + pkcs11h_provider_t current_provider; CK_RV rv = CKR_OK; - 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)} - }; + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (p_token_id_list!=NULL); - bool fOpSuccess = false; - bool fLoginRetry = false; + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getTokenIds entry p_token_id_list=%p", + (void *)p_token_id_list + ); - PKCS11ASSERT (pkcs11h_certificate!=NULL); + *p_token_id_list = NULL; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getCertificateKeyAttributes entry pkcs11h_certificate=%p", - (void *)pkcs11h_certificate - ); +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif - while (rv == CKR_OK && !fOpSuccess) { + for ( + current_provider = s_pkcs11h_data->providers; + ( + current_provider != NULL && + rv == CKR_OK + ); + current_provider = current_provider->next + ) { + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slotnum; + CK_SLOT_ID slot_index; + + if (!current_provider->fEnabled) { + continue; + } if (rv == CKR_OK) { - rv = _pkcs11h_getObjectById ( - pkcs11h_certificate->session, - CKO_PRIVATE_KEY, - pkcs11h_certificate->certificate_id, - pkcs11h_certificate->certificate_id_size, - &pkcs11h_certificate->hKey + rv = _pkcs11h_getSlotList ( + current_provider, + CK_TRUE, + &slots, + &slotnum ); } - if (pkcs11h_certificate->signmode == pkcs11h_signmode_none) { - if (!strcmp (pkcs11h_certificate->session->provider->szSignMode, "recover")) { - pkcs11h_certificate->signmode = pkcs11h_signmode_recover; + for ( + slot_index=0; + ( + slot_index < slotnum && + rv == CKR_OK + ); + slot_index++ + ) { + pkcs11h_token_id_list_t entry = NULL; + CK_TOKEN_INFO info; + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ((void *)&entry, sizeof (struct pkcs11h_token_id_list_s)); } - else if (!strcmp (pkcs11h_certificate->session->provider->szSignMode, "sign")) { - pkcs11h_certificate->signmode = pkcs11h_signmode_sign; + + if (rv == CKR_OK) { + rv = current_provider->f->C_GetTokenInfo ( + slots[slot_index], + &info + ); } - else { + + if (rv == CKR_OK) { + rv = _pkcs11h_getTokenId ( + &info, + &entry->token_id + ); + } + + if (rv == CKR_OK) { + entry->next = token_id_list; + token_id_list = entry; + entry = NULL; + } + + if (entry != NULL) { + pkcs11h_freeTokenIdList (entry); + entry = NULL; + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'", + current_provider->manufacturerID, + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + slots = NULL; + } + } + + if (rv == CKR_OK && method == PKCS11H_ENUM_METHOD_CACHE) { + pkcs11h_session_t session = NULL; + + for ( + session = s_pkcs11h_data->sessions; + session != NULL && rv == CKR_OK; + session = session->next + ) { + pkcs11h_token_id_list_t entry = NULL; + PKCS11H_BOOL fFound = FALSE; + + for ( + entry = token_id_list; + entry != NULL && !fFound; + entry = entry->next + ) { + if ( + pkcs11h_sameTokenId ( + session->token_id, + entry->token_id + ) + ) { + fFound = TRUE; + } + } + + if (!fFound) { + entry = NULL; + if (rv == CKR_OK) { - rv = pkcs11h_certificate->session->provider->f->C_GetAttributeValue ( - pkcs11h_certificate->session->hSession, - pkcs11h_certificate->hKey, - key_attrs, - sizeof (key_attrs) / sizeof (CK_ATTRIBUTE) + rv = _pkcs11h_malloc ( + (void *)&entry, + sizeof (struct pkcs11h_token_id_list_s) ); } - - if (rv == CKR_OK) { - if (key_attrs_sign != CK_FALSE) { - pkcs11h_certificate->signmode = pkcs11h_signmode_sign; - } - else if (key_attrs_sign_recover != CK_FALSE) { - pkcs11h_certificate->signmode = pkcs11h_signmode_recover; - } - else { - rv = CKR_KEY_TYPE_INCONSISTENT; - } - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Signature mode selected: %d", - pkcs11h_certificate->signmode + if (rv == CKR_OK) { + rv = pkcs11h_duplicateTokenId ( + &entry->token_id, + session->token_id ); } + + if (rv == CKR_OK) { + entry->next = token_id_list; + token_id_list = entry; + entry = NULL; + } + + if (entry != NULL) { + if (entry->token_id != NULL) { + pkcs11h_freeTokenId (entry->token_id); + } + _pkcs11h_free ((void *)&entry); + } } } + } + if (rv == CKR_OK) { + *p_token_id_list = token_id_list; + token_id_list = NULL; + } - if (rv == CKR_OK) { - fOpSuccess = true; - } - else { - if (!fLoginRetry) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Get key attributes failed: %ld:'%s'", - rv, - pkcs11h_getMessage (rv) - ); + if (token_id_list != NULL) { + pkcs11h_freeTokenIdList (token_id_list); + token_id_list = NULL; + } - rv = _pkcs11h_login ( - pkcs11h_certificate->session, - false - ); - fLoginRetry = true; - } - } +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + rv = _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); + fMutexLocked = FALSE; } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_getCertificateKeyAttributes return rv=%ld-'%s'", +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getTokenIds return rv=%ld-'%s', *p_token_id_list=%p", rv, - pkcs11h_getMessage (rv) + pkcs11h_getMessage (rv), + (void *)p_token_id_list ); - + return rv; } +#endif + +#if defined(ENABLE_PKCS11H_DATA) + CK_RV -_pkcs11h_resetCertificateSession ( - IN const pkcs11h_certificate_t pkcs11h_certificate +pkcs11h_freeDataIdList ( + IN const pkcs11h_data_id_list_t data_id_list ) { - CK_RV rv = CKR_OK; - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_resetCertificateSession entry pkcs11h_certificate=%p", - (void *)pkcs11h_certificate + pkcs11h_data_id_list_t _id = data_id_list; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + /*PKCS11H_ASSERT (data_id_list!=NULL); NOT NEEDED*/ + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeDataIdList entry token_id_list=%p", + (void *)data_id_list ); - if (rv == CKR_OK) { - rv = _pkcs11h_login ( - pkcs11h_certificate->session, - false - ); - } + while (_id != NULL) { + pkcs11h_data_id_list_t x = _id; + _id = _id->next; - if (rv == CKR_OK) { - /* - * Will be performed only once - */ - rv = _pkcs11h_getCertificateKeyAttributes (pkcs11h_certificate); + if (x->application != NULL) { + _pkcs11h_free ((void *)&x->application); + } + if (x->label != NULL) { + _pkcs11h_free ((void *)&x->label); + } + _pkcs11h_free ((void *)&x); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_freeCertificateSession return" + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeDataIdList return" ); return CKR_OK; } -/*======================================= - * Simplified PKCS#11 functions - */ - -static -bool -_pkcs11h_hooks_card_prompt_default ( - IN const void * pData, - IN const char * const szLabel +CK_RV +pkcs11h_enumDataObjects ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + OUT pkcs11h_data_id_list_t * const p_data_id_list ) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_hooks_card_prompt_default pData=%p, szLabel=%s", - pData, - szLabel - ); + pkcs11h_session_t session = NULL; + pkcs11h_data_id_list_t data_id_list = NULL; + CK_RV rv = CKR_OK; - return false; -} + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; -static -bool -_pkcs11h_hooks_pin_prompt_default ( - IN const void * pData, - IN const char * const szLabel, - OUT char * const szPIN, - IN const size_t nMaxPIN -) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: _pkcs11h_hooks_pin_prompt_default pData=%p, szLabel=%s", - pData, - szLabel + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (p_data_id_list!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enumDataObjects entry p_data_id_list=%p", + (void *)p_data_id_list ); - - return false; -} -CK_RV -pkcs11h_initialize () { + *p_data_id_list = NULL; - CK_RV rv = CKR_OK; + if (rv == CKR_OK) { + rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + ); + } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_initialize entry" - ); + while (rv == CKR_OK && !fOpSuccess) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif - pkcs11h_terminate (); + CK_OBJECT_CLASS class = CKO_DATA; + CK_ATTRIBUTE filter[] = { + {CKA_CLASS, (void *)&class, sizeof (class)} + }; + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + + CK_ULONG i; + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif + + if (rv == CKR_OK) { + rv = _pkcs11h_findObjects ( + session, + filter, + sizeof (filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found + ); + } + + for (i = 0;rv == CKR_OK && i < objects_found;i++) { + pkcs11h_data_id_list_t entry = NULL; + + CK_ATTRIBUTE attrs[] = { + {CKA_APPLICATION, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + + if (rv == CKR_OK) { + rv = _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + } + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ( + (void *)&entry, + sizeof (struct pkcs11h_data_id_list_s) + ); + } + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ( + (void *)&entry->application, + attrs[0].ulValueLen+1 + )) == CKR_OK + ) { + memmove (entry->application, attrs[0].pValue, attrs[0].ulValueLen); + entry->application[attrs[0].ulValueLen] = '\0'; + } + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ( + (void *)&entry->label, + attrs[1].ulValueLen+1 + )) == CKR_OK + ) { + memmove (entry->label, attrs[1].pValue, attrs[1].ulValueLen); + entry->label[attrs[1].ulValueLen] = '\0'; + } + + if (rv == CKR_OK) { + entry->next = data_id_list; + data_id_list = entry; + entry = NULL; + } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + + if (entry != NULL) { + if (entry->application != NULL) { + _pkcs11h_free ((void *)&entry->application); + } + if (entry->label != NULL) { + _pkcs11h_free ((void *)&entry->label); + } + _pkcs11h_free ((void *)&entry); + } + } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&session->mutexSession); + fMutexLocked = FALSE; + } +#endif - if ( - rv == CKR_OK && - (pkcs11h_data = (pkcs11h_data_t)malloc (sizeof (struct pkcs11h_data_s))) == NULL - ) { - rv = CKR_HOST_MEMORY; + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Enumerate data objects failed rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); + fLoginRetry = TRUE; + rv = _pkcs11h_login ( + session, + fPublic, + TRUE, + ( + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | + PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT + ) + ); + } + } } if (rv == CKR_OK) { - memset (pkcs11h_data, 0, sizeof (struct pkcs11h_data_s)); + *p_data_id_list = data_id_list; + data_id_list = NULL; } - - if ( - rv == CKR_OK && - (pkcs11h_data->hooks = (pkcs11h_hooks_t)malloc (sizeof (struct pkcs11h_hooks_s))) == NULL - ) { - rv = CKR_HOST_MEMORY; + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; } - if (rv == CKR_OK) { - memset (pkcs11h_data->hooks, 0, sizeof (struct pkcs11h_hooks_s)); - - pkcs11h_data->fInitialized = true; - pkcs11h_data->nPINCachePeriod = PKCS11H_PIN_CACHE_INFINITE; - - pkcs11h_setCardPromptHook (_pkcs11h_hooks_card_prompt_default, NULL); - pkcs11h_setPINPromptHook (_pkcs11h_hooks_pin_prompt_default, NULL); + if (data_id_list != NULL) { + pkcs11h_freeDataIdList (data_id_list); + data_id_list = NULL; } - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_initialize return rv=%ld-'%s'", + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_data_id_list_t return rv=%ld-'%s', *p_data_id_list=%p", rv, - pkcs11h_getMessage (rv) + pkcs11h_getMessage (rv), + (void *)*p_data_id_list ); - + return rv; } +#endif /* ENABLE_PKCS11H_DATA */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +static CK_RV -pkcs11h_terminate () { +_pkcs11h_enum_getSessionCertificates ( + IN const pkcs11h_session_t session +) { + PKCS11H_BOOL fOpSuccess = FALSE; + PKCS11H_BOOL fLoginRetry = FALSE; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_terminate entry" + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (session!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_enum_getSessionCertificates entry session=%p", + (void *)session ); + + /* THREADS: NO NEED TO LOCK, GLOBAL CACHE IS LOCKED */ - if (pkcs11h_data != NULL) { - pkcs11h_provider_t p_last = NULL; - pkcs11h_session_t s_last = NULL; + while (rv == CKR_OK && !fOpSuccess) { + CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE; + CK_ATTRIBUTE cert_filter[] = { + {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)} + }; - for ( - ; - pkcs11h_data->sessions != NULL; - pkcs11h_data->sessions = pkcs11h_data->sessions->next - ) { - if (s_last != NULL) { - if (s_last->nReferenceCount == 0) { - free (s_last); - } - } - s_last = pkcs11h_data->sessions; - - _pkcs11h_logout (s_last); - s_last->fValid = false; - s_last->provider = NULL; + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + + CK_ULONG i; + + if (rv == CKR_OK) { + rv = _pkcs11h_validateSession (session); } - if (s_last != NULL) { - if (s_last->nReferenceCount == 0) { - free (s_last); - } + if (rv == CKR_OK) { + rv = _pkcs11h_findObjects ( + session, + cert_filter, + sizeof (cert_filter) / sizeof (CK_ATTRIBUTE), + &objects, + &objects_found + ); } + + for (i=0;rv == CKR_OK && i < objects_found;i++) { + pkcs11h_certificate_id_t certificate_id = NULL; + pkcs11h_certificate_id_list_t new_element = NULL; + + CK_ATTRIBUTE attrs[] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0} + }; - for ( - ; - pkcs11h_data->providers != NULL; - pkcs11h_data->providers = pkcs11h_data->providers->next - ) { - if (p_last != NULL) { - free (p_last); + if (rv == CKR_OK) { + rv = _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); } - p_last = pkcs11h_data->providers; - - if (p_last->szName != NULL) { - free (p_last->szName); - p_last->szName = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_newCertificateId (&certificate_id)) == CKR_OK + ) { + rv = pkcs11h_duplicateTokenId ( + &certificate_id->token_id, + session->token_id + ); } - if (p_last->szSignMode != NULL) { - free (p_last->szSignMode); - p_last->szSignMode = NULL; + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)&certificate_id->attrCKA_ID, + &certificate_id->attrCKA_ID_size, + attrs[0].pValue, + attrs[0].ulValueLen + ); } - - if (p_last->fShouldFinalize) { - p_last->f->C_Finalize (NULL); - p_last->fShouldFinalize = false; + + if (rv == CKR_OK) { + rv = _pkcs11h_dupmem ( + (void*)&certificate_id->certificate_blob, + &certificate_id->certificate_blob_size, + attrs[1].pValue, + attrs[1].ulValueLen + ); } - if (p_last->f != NULL) { - p_last->f = NULL; + if (rv == CKR_OK) { + rv = _pkcs11h_updateCertificateIdDescription (certificate_id); } - - if (p_last->hLibrary != NULL) { -#if defined(WIN32) - FreeLibrary (p_last->hLibrary); -#else - dlclose (p_last->hLibrary); -#endif - p_last->hLibrary = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ( + (void *)&new_element, + sizeof (struct pkcs11h_certificate_id_list_s) + )) == CKR_OK + ) { + new_element->next = session->cached_certs; + new_element->certificate_id = certificate_id; + certificate_id = NULL; + + session->cached_certs = new_element; + new_element = NULL; } - } - if (p_last != NULL) { - free (p_last); - } + if (certificate_id != NULL) { + pkcs11h_freeCertificateId (certificate_id); + certificate_id = NULL; + } - if (pkcs11h_data->hooks != NULL) { - free (pkcs11h_data->hooks); - pkcs11h_data->hooks = NULL; - } + if (new_element != NULL) { + _pkcs11h_free ((void *)&new_element); + new_element = NULL; + } - free (pkcs11h_data); - pkcs11h_data = NULL; - } + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_terminate return" - ); + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'", + session->provider->manufacturerID, + objects[i], + rv, + pkcs11h_getMessage (rv) + ); - return CKR_OK; -} + /* + * Ignore error + */ + rv = CKR_OK; + } + } -CK_RV -pkcs11h_setPINPromptHook ( - IN const pkcs11h_hook_pin_prompt_t hook, - IN void * const pData -) { - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } - pkcs11h_data->hooks->pin_prompt = hook; - pkcs11h_data->hooks->pin_prompt_data = pData; + if (rv == CKR_OK) { + fOpSuccess = TRUE; + } + else { + if (!fLoginRetry) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Get certificate attributes failed: %ld:'%s'", + rv, + pkcs11h_getMessage (rv) + ); - return CKR_OK; -} + rv = _pkcs11h_login ( + session, + TRUE, + TRUE, + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT + ); -CK_RV -pkcs11h_setCardPromptHook ( - IN const pkcs11h_hook_card_prompt_t hook, - IN void * const pData -) { - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); + fLoginRetry = TRUE; + } + } + } - pkcs11h_data->hooks->card_prompt = hook; - pkcs11h_data->hooks->card_prompt_data = pData; + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_enum_getSessionCertificates return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); - return CKR_OK; + return rv; } +static CK_RV -pkcs11h_setPINCachePeriod ( - IN const int nPINCachePeriod +_pkcs11h_enum_splitCertificateIdList ( + IN const pkcs11h_certificate_id_list_t cert_id_all, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list ) { - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); + typedef struct info_s { + struct info_s *next; + pkcs11h_certificate_id_t e; + X509 *x509; + PKCS11H_BOOL fIsIssuer; + } *info_t; - pkcs11h_data->nPINCachePeriod = nPINCachePeriod; + pkcs11h_certificate_id_list_t cert_id_issuers_list = NULL; + pkcs11h_certificate_id_list_t cert_id_end_list = NULL; - return CKR_OK; -} + info_t head = NULL; + info_t info = NULL; -CK_RV -pkcs11h_addProvider ( - IN const char * const szProvider, - IN const char * const szSignMode -) { - pkcs11h_provider_t provider = NULL; - CK_C_GetFunctionList gfl = NULL; -#if defined(WIN32) - int mypid = 0; -#else - pid_t mypid = getpid (); -#endif CK_RV rv = CKR_OK; - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); - PKCS11ASSERT (szProvider!=NULL); + /*PKCS11H_ASSERT (cert_id_all!=NULL); NOT NEEDED */ + /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (p_cert_id_end_list!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_addProvider entry pid=%d, szProvider=%s, szSignMode=%s", - mypid, - szProvider, - szSignMode + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_splitCertificateIdList entry cert_id_all=%p, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p", + (void *)cert_id_all, + (void *)p_cert_id_issuers_list, + (void *)p_cert_id_end_list ); - if ( - rv == CKR_OK && - (provider = (pkcs11h_provider_t)malloc (sizeof (struct pkcs11h_provider_s))) == NULL - ) { - rv = CKR_HOST_MEMORY; + if (p_cert_id_issuers_list != NULL) { + *p_cert_id_issuers_list = NULL; } + *p_cert_id_end_list = NULL; + + OpenSSL_add_all_digests (); if (rv == CKR_OK) { - memset (provider, 0, sizeof (struct pkcs11h_provider_s)); - provider->szName = strdup (szProvider); - - if (szSignMode == NULL) { - provider->szSignMode = strdup ("auto"); - } - else { - provider->szSignMode = strdup (szSignMode); - } - if (provider->szSignMode == NULL) { - rv = CKR_HOST_MEMORY; + pkcs11h_certificate_id_list_t entry = NULL; + + for ( + entry = cert_id_all; + entry != NULL && rv == CKR_OK; + entry = entry->next + ) { + info_t new_info = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ((void *)&new_info, sizeof (struct info_s))) == CKR_OK && + entry->certificate_id->certificate_blob != NULL + ) { + pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)entry->certificate_id->certificate_blob; + new_info->next = head; + new_info->e = entry->certificate_id; + new_info->x509 = X509_new (); + if ( + new_info->x509 != NULL && + !d2i_X509 ( + &new_info->x509, + &d2i, + entry->certificate_id->certificate_blob_size + ) + ) { + X509_free (new_info->x509); + new_info->x509 = NULL; + } + head = new_info; + new_info = NULL; + } } + } - + 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; + for ( + info = head; + info != NULL; + info = info->next + ) { + info_t info2 = NULL; + for ( + info2 = head; + info2 != NULL && !info->fIsIssuer; + info2 = info2->next + ) { + EVP_PKEY *pub = NULL; + + pub = X509_get_pubkey (info->x509); + + if ( + info != info2 && + info->x509 != NULL && + info2->x509 != NULL && +/* Some people get this wrong !X509_NAME_cmp ( + X509_get_subject_name (info->x509), + X509_get_issuer_name (info2->x509) + ) && */ + X509_verify (info2->x509, pub) == 1 + ) { + info->fIsIssuer = TRUE; + } + + if (pub != NULL) { + EVP_PKEY_free (pub); + pub = NULL; + } + } } } if (rv == CKR_OK) { -#if defined(WIN32) - gfl = (CK_C_GetFunctionList)GetProcAddress ( - provider->hLibrary, - "C_GetFunctionList" - ); -#else - /* - * Make compiler happy! - */ - void *p = dlsym ( - provider->hLibrary, - "C_GetFunctionList" - ); - memmove ( - &gfl, - &p, - sizeof (void *) - ); -#endif - if (gfl == NULL) { - rv = CKR_FUNCTION_FAILED; + for ( + info = head; + info != NULL && rv == CKR_OK; + info = info->next + ) { + pkcs11h_certificate_id_list_t new_entry = NULL; + + if (rv == CKR_OK) { + rv = _pkcs11h_malloc ( + (void *)&new_entry, + sizeof (struct pkcs11h_certificate_id_list_s) + ); + } + + if ( + rv == CKR_OK && + (rv = pkcs11h_duplicateCertificateId ( + &new_entry->certificate_id, + info->e + )) == CKR_OK + ) { + /* + * Should not free base list + */ + info->e = NULL; + } + + if (rv == CKR_OK) { + if (info->fIsIssuer) { + new_entry->next = cert_id_issuers_list; + cert_id_issuers_list = new_entry; + new_entry = NULL; + } + else { + new_entry->next = cert_id_end_list; + cert_id_end_list = new_entry; + new_entry = NULL; + } + } + + if (new_entry != NULL) { + if (new_entry->certificate_id != NULL) { + pkcs11h_freeCertificateId (new_entry->certificate_id); + } + _pkcs11h_free ((void *)&new_entry); + } } } if (rv == CKR_OK) { - rv = gfl (&provider->f); - } + while (head != NULL) { + info_t entry = head; + head = head->next; - if (rv == CKR_OK) { - if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) { - if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) { - rv = CKR_OK; + if (entry->x509 != NULL) { + X509_free (entry->x509); + entry->x509 = NULL; } - } - else { - provider->fShouldFinalize = true; + _pkcs11h_free ((void *)&entry); } } - if (rv == CKR_OK) { - provider->fEnabled = true; + if (rv == CKR_OK && p_cert_id_issuers_list != NULL ) { + *p_cert_id_issuers_list = cert_id_issuers_list; + cert_id_issuers_list = NULL; } - if (provider != NULL) { - if (pkcs11h_data->providers == NULL) { - pkcs11h_data->providers = provider; - } - else { - pkcs11h_provider_t last = NULL; - - for ( - last = pkcs11h_data->providers; - last->next != NULL; - last = last->next - ); - last->next = provider; - } + if (rv == CKR_OK) { + *p_cert_id_end_list = cert_id_end_list; + cert_id_end_list = NULL; } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'", + if (cert_id_issuers_list != NULL) { + pkcs11h_freeCertificateIdList (cert_id_issuers_list); + } + + if (cert_id_end_list != NULL) { + pkcs11h_freeCertificateIdList (cert_id_end_list); + } + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_splitCertificateIdList return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); @@ -2026,141 +7808,369 @@ pkcs11h_addProvider ( } CK_RV -pkcs11h_forkFixup () { -#if defined(WIN32) - int mypid = 0; -#else - pid_t mypid = getpid (); -#endif - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_forkFixup entry pid=%d", - mypid - ); +pkcs11h_freeCertificateIdList ( + IN const pkcs11h_certificate_id_list_t cert_id_list +) { + pkcs11h_certificate_id_list_t _id = cert_id_list; - if (pkcs11h_data != NULL && pkcs11h_data->fInitialized) { + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + /*PKCS11H_ASSERT (cert_id_list!=NULL); NOT NEEDED*/ - pkcs11h_provider_t current; + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificateIdList entry cert_id_list=%p", + (void *)cert_id_list + ); - for ( - current = pkcs11h_data->providers; - current != NULL; - current = current->next - ) { - if (current->fEnabled) { - current->f->C_Initialize (NULL); - } + while (_id != NULL) { + pkcs11h_certificate_id_list_t x = _id; + _id = _id->next; + if (x->certificate_id != NULL) { + pkcs11h_freeCertificateId (x->certificate_id); } + x->next = NULL; + _pkcs11h_free ((void *)&x); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_forkFixup return" + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_freeCertificateIdList return" ); return CKR_OK; } CK_RV -pkcs11h_createCertificateSession ( - IN const char * const szSlotType, - IN const char * const szSlot, - IN const char * const szIdType, - IN const char * const szId, - IN const bool fProtectedAuthentication, - IN const bool fCertPrivate, - IN const int nPINCachePeriod, - OUT pkcs11h_certificate_t * const p_pkcs11h_certificate +pkcs11h_enum_getTokenCertificateIds ( + IN const pkcs11h_token_id_t token_id, + IN const int method, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list ) { - pkcs11h_certificate_t pkcs11h_certificate = NULL; +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + pkcs11h_session_t session = NULL; CK_RV rv = CKR_OK; - bool fOpSuccess = false; - bool fLogonRetry = false; + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + PKCS11H_ASSERT (token_id!=NULL); + /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (p_cert_id_end_list!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getTokenCertificateIds entry token_id=%p, method=%d, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p", + (void *)token_id, + method, + (void *)p_cert_id_issuers_list, + (void *)p_cert_id_end_list + ); - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); - PKCS11ASSERT (szSlotType!=NULL); - PKCS11ASSERT (szSlot!=NULL); - PKCS11ASSERT (szIdType!=NULL); - PKCS11ASSERT (szId!=NULL); - PKCS11ASSERT (p_pkcs11h_certificate!=NULL); + if (p_cert_id_issuers_list != NULL) { + *p_cert_id_issuers_list = NULL; + } + *p_cert_id_end_list = NULL; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_createSession entry szSlotType=%s, szSlot=%s, szIdType=%s, szId=%s, fProtectedAuthentication=%d, fCertPrivate=%d, nPINCachePeriod=%d, p_pkcs11h_certificate=%p", - szSlotType, - szSlot, - szIdType, - szId, - fProtectedAuthentication ? 1 : 0, - fCertPrivate ? 1 : 0, - nPINCachePeriod, - (void *)p_pkcs11h_certificate - ); +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexCache)) == CKR_OK + ) { + fMutexLocked = TRUE; + } +#endif if ( rv == CKR_OK && - (pkcs11h_certificate = (pkcs11h_certificate_t)malloc (sizeof (struct pkcs11h_certificate_s))) == NULL + (rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + )) == CKR_OK ) { - rv = CKR_HOST_MEMORY; + if (method == PKCS11H_ENUM_METHOD_RELOAD) { + pkcs11h_freeCertificateIdList (session->cached_certs); + session->cached_certs = NULL; + } + + if (session->cached_certs == NULL) { + rv = _pkcs11h_enum_getSessionCertificates (session); + } } if (rv == CKR_OK) { - *p_pkcs11h_certificate = pkcs11h_certificate; - memset (pkcs11h_certificate, 0, sizeof (struct pkcs11h_certificate_s)); + rv = _pkcs11h_enum_splitCertificateIdList ( + session->cached_certs, + p_cert_id_issuers_list, + p_cert_id_end_list + ); + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); } + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexCache); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getTokenCertificateIds return rv=%ld-'%s'", + rv, + pkcs11h_getMessage (rv) + ); - if (rv == CKR_OK) { - pkcs11h_certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE; - pkcs11h_certificate->fCertPrivate = fCertPrivate; + return rv; +} + +CK_RV +pkcs11h_enum_getCertificateIds ( + IN const int method, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list +) { +#if defined(ENABLE_PKCS11H_THREADING) + PKCS11H_BOOL fMutexLocked = FALSE; +#endif + pkcs11h_certificate_id_list_t cert_id_list = NULL; + pkcs11h_provider_t current_provider; + pkcs11h_session_t current_session; + CK_RV rv = CKR_OK; + + PKCS11H_ASSERT (s_pkcs11h_data!=NULL); + PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); + /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/ + PKCS11H_ASSERT (p_cert_id_end_list!=NULL); + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getCertificateIds entry method=%d, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p", + method, + (void *)p_cert_id_issuers_list, + (void *)p_cert_id_end_list + ); + + if (p_cert_id_issuers_list != NULL) { + *p_cert_id_issuers_list = NULL; } + *p_cert_id_end_list = NULL; - if (rv == CKR_OK) { - rv = _pkcs11h_getSession ( - szSlotType, - szSlot, - fProtectedAuthentication, - nPINCachePeriod, - &pkcs11h_certificate->session - ); +#if defined(ENABLE_PKCS11H_THREADING) + if ( + rv == CKR_OK && + (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexCache)) == CKR_OK + ) { + fMutexLocked = TRUE; } +#endif + + for ( + current_session = s_pkcs11h_data->sessions; + current_session != NULL; + current_session = current_session->next + ) { + current_session->fTouch = FALSE; + if (method == PKCS11H_ENUM_METHOD_RELOAD) { + pkcs11h_freeCertificateIdList (current_session->cached_certs); + current_session->cached_certs = NULL; + } + } + + for ( + current_provider = s_pkcs11h_data->providers; + ( + current_provider != NULL && + rv == CKR_OK + ); + current_provider = current_provider->next + ) { + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slotnum; + CK_SLOT_ID slot_index; + + if (!current_provider->fEnabled) { + continue; + } - fOpSuccess = false; - fLogonRetry = false; - while (rv == CKR_OK && !fOpSuccess) { if (rv == CKR_OK) { - /* - * Don't repeat this if succeeded in - * unauthenticated session - */ - if (pkcs11h_certificate->certificate == NULL) { - rv = _pkcs11h_setCertificateSession_Certificate ( - pkcs11h_certificate, - szIdType, - szId + rv = _pkcs11h_getSlotList ( + current_provider, + CK_TRUE, + &slots, + &slotnum + ); + } + + for ( + slot_index=0; + ( + slot_index < slotnum && + rv == CKR_OK + ); + slot_index++ + ) { + pkcs11h_session_t session = NULL; + pkcs11h_token_id_t token_id = NULL; + CK_TOKEN_INFO info; + + if (rv == CKR_OK) { + rv = current_provider->f->C_GetTokenInfo ( + slots[slot_index], + &info + ); + } + + if ( + rv == CKR_OK && + (rv = _pkcs11h_getTokenId ( + &info, + &token_id + )) == CKR_OK && + (rv = _pkcs11h_getSessionByTokenId ( + token_id, + &session + )) == CKR_OK + ) { + session->fTouch = TRUE; + + if (session->cached_certs == NULL) { + rv = _pkcs11h_enum_getSessionCertificates (session); + } + } + + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'", + current_provider->manufacturerID, + slots[slot_index], + rv, + pkcs11h_getMessage (rv) ); + + /* + * Ignore error + */ + rv = CKR_OK; + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + if (token_id != NULL) { + pkcs11h_freeTokenId (token_id); + token_id = NULL; } } - if (rv == CKR_OK) { - fOpSuccess = true; + if (rv != CKR_OK) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'", + current_provider->manufacturerID, + rv, + pkcs11h_getMessage (rv) + ); + + /* + * Ignore error + */ + rv = CKR_OK; } - else { - if (!fLogonRetry) { - fLogonRetry = true; - rv = _pkcs11h_login ( - pkcs11h_certificate->session, - !pkcs11h_certificate->fCertPrivate + + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + slots = NULL; + } + } + + for ( + current_session = s_pkcs11h_data->sessions; + ( + current_session != NULL && + rv == CKR_OK + ); + current_session = current_session->next + ) { + if ( + method == PKCS11H_ENUM_METHOD_CACHE || + ( + ( + method == PKCS11H_ENUM_METHOD_RELOAD || + method == PKCS11H_ENUM_METHOD_CACHE_EXIST + ) && + current_session->fTouch + ) + ) { + pkcs11h_certificate_id_list_t entry = NULL; + + for ( + entry = current_session->cached_certs; + ( + entry != NULL && + rv == CKR_OK ); + entry = entry->next + ) { + pkcs11h_certificate_id_list_t new_entry = NULL; + + if ( + rv == CKR_OK && + (rv = _pkcs11h_malloc ( + (void *)&new_entry, + sizeof (struct pkcs11h_certificate_id_list_s) + )) == CKR_OK && + (rv = pkcs11h_duplicateCertificateId ( + &new_entry->certificate_id, + entry->certificate_id + )) == CKR_OK + ) { + new_entry->next = cert_id_list; + cert_id_list = new_entry; + new_entry = NULL; + } + + if (new_entry != NULL) { + new_entry->next = NULL; + pkcs11h_freeCertificateIdList (new_entry); + new_entry = NULL; + } } } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_createSession return rv=%ld-'%s'", + if (rv == CKR_OK) { + rv = _pkcs11h_enum_splitCertificateIdList ( + cert_id_list, + p_cert_id_issuers_list, + p_cert_id_end_list + ); + } + + if (cert_id_list != NULL) { + pkcs11h_freeCertificateIdList (cert_id_list); + cert_id_list = NULL; + } + + +#if defined(ENABLE_PKCS11H_THREADING) + if (fMutexLocked) { + _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexCache); + fMutexLocked = FALSE; + } +#endif + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_enum_getCertificateIds return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); @@ -2168,326 +8178,352 @@ pkcs11h_createCertificateSession ( return rv; } -CK_RV -pkcs11h_freeCertificateSession ( - IN const pkcs11h_certificate_t pkcs11h_certificate -) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_freeCertificateSession entry pkcs11h_certificate=%p", - (void *)pkcs11h_certificate - ); - - if (pkcs11h_certificate != NULL) { - if (pkcs11h_certificate->session != NULL) { - _pkcs11h_releaseSession (pkcs11h_certificate->session); - } - if (pkcs11h_certificate->certificate != NULL) { - free (pkcs11h_certificate->certificate); - } - if (pkcs11h_certificate->certificate_id != NULL) { - free (pkcs11h_certificate->certificate_id); - } +#endif /* ENABLE_PKCS11H_CERTIFICATE */ - free (pkcs11h_certificate); - } +#endif /* ENABLE_PKCS11H_ENUM */ - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_freeCertificateSession return" - ); +#if defined(ENABLE_PKCS11H_SLOTEVENT) +/*======================================================================* + * SLOTEVENT INTERFACE + *======================================================================*/ - return CKR_OK; +static +unsigned long +_pkcs11h_slotevent_checksum ( + IN const unsigned char * const p, + IN const size_t s +) { + unsigned long r = 0; + size_t i; + for (i=0;ifInitialized); - PKCS11ASSERT (pkcs11h_certificate!=NULL); - PKCS11ASSERT (source!=NULL); - PKCS11ASSERT (target_size!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_sign entry pkcs11h_certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p", - (void *)pkcs11h_certificate, - mech_type, - source, - source_size, - target, - (void *)target_size + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_provider provider='%s' entry", + provider->manufacturerID ); - if (rv == CKR_OK) { - rv = _pkcs11h_validateSession (pkcs11h_certificate->session); + if (rv == CKR_OK && !provider->fEnabled) { + rv = CKR_OPERATION_NOT_INITIALIZED; } - while (rv == CKR_OK && !fOpSuccess) { + if (rv == CKR_OK) { + + if (provider->nSlotEventPollInterval == 0) { + provider->nSlotEventPollInterval = PKCS11H_DEFAULT_SLOTEVENT_POLL; + } /* - * Don't try invalid object + * If we cannot finalize, we cannot cause + * WaitForSlotEvent to terminate */ + if (!provider->fShouldFinalize) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Setup slotevent provider='%s' mode hardset to poll", + provider->manufacturerID + ); + provider->nSlotEventMethod = PKCS11H_SLOTEVENT_METHOD_POLL; + } + if ( - rv == CKR_OK && - pkcs11h_certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE - ) { - rv = CKR_OBJECT_HANDLE_INVALID; + provider->nSlotEventMethod == PKCS11H_SLOTEVENT_METHOD_AUTO || + provider->nSlotEventMethod == PKCS11H_SLOTEVENT_METHOD_TRIGGER + ) { + if ( + provider->f->C_WaitForSlotEvent ( + CKF_DONT_BLOCK, + &slot, + NULL_PTR + ) == CKR_FUNCTION_NOT_SUPPORTED + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Setup slotevent provider='%s' mode is poll", + provider->manufacturerID + ); + + provider->nSlotEventMethod = PKCS11H_SLOTEVENT_METHOD_POLL; + } + else { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Setup slotevent provider='%s' mode is trigger", + provider->manufacturerID + ); + + provider->nSlotEventMethod = PKCS11H_SLOTEVENT_METHOD_TRIGGER; + } } + } - if (rv == CKR_OK) { - rv = pkcs11h_certificate->session->provider->f->C_SignInit ( - pkcs11h_certificate->session->hSession, - &mech, - pkcs11h_certificate->hKey + if (provider->nSlotEventMethod == PKCS11H_SLOTEVENT_METHOD_TRIGGER) { + while ( + !s_pkcs11h_data->fSlotEventShouldTerminate && + provider->fEnabled && + rv == CKR_OK && + (rv = provider->f->C_WaitForSlotEvent ( + 0, + &slot, + NULL_PTR + )) == CKR_OK + ) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Slotevent provider='%s' event", + provider->manufacturerID ); + + _pkcs11h_condSignal (&s_pkcs11h_data->condSlotEvent); } + } + else { + unsigned long ulLastChecksum = 0; + PKCS11H_BOOL fFirstTime = TRUE; - if (rv == CKR_OK) { - CK_ULONG size = *target_size; - rv = pkcs11h_certificate->session->provider->f->C_Sign ( - pkcs11h_certificate->session->hSession, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size + while ( + !s_pkcs11h_data->fSlotEventShouldTerminate && + provider->fEnabled && + rv == CKR_OK + ) { + unsigned long ulCurrentChecksum = 0; + + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slotnum; + + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Slotevent provider='%s' poll", + provider->manufacturerID ); - *target_size = (int)size; - } + if ( + rv == CKR_OK && + (rv = _pkcs11h_getSlotList ( + provider, + TRUE, + &slots, + &slotnum + )) == CKR_OK + ) { + CK_ULONG i; + + for (i=0;if->C_GetTokenInfo (slots[i], &info) == CKR_OK) { + ulCurrentChecksum += ( + _pkcs11h_slotevent_checksum ( + info.label, + sizeof (info.label) + ) + + _pkcs11h_slotevent_checksum ( + info.manufacturerID, + sizeof (info.manufacturerID) + ) + + _pkcs11h_slotevent_checksum ( + info.model, + sizeof (info.model) + ) + + _pkcs11h_slotevent_checksum ( + info.serialNumber, + sizeof (info.serialNumber) + ) + ); + } + } + } + + if (rv == CKR_OK) { + if (fFirstTime) { + fFirstTime = FALSE; + } + else { + if (ulLastChecksum != ulCurrentChecksum) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Slotevent provider='%s' event", + provider->manufacturerID + ); + _pkcs11h_condSignal (&s_pkcs11h_data->condSlotEvent); + } + } + ulLastChecksum = ulCurrentChecksum; + } - if (rv == CKR_OK) { - fOpSuccess = true; - } - else { - if (!fLogonRetry) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Private key operation failed rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) - ); - fLogonRetry = true; - rv = _pkcs11h_resetCertificateSession (pkcs11h_certificate); + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + } + + if (!s_pkcs11h_data->fSlotEventShouldTerminate) { + _pkcs11h_sleep (provider->nSlotEventPollInterval); } } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_sign return rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_provider provider='%s' return", + provider->manufacturerID ); - - return rv; + + return NULL; } -CK_RV -pkcs11h_signRecover ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - IN const CK_MECHANISM_TYPE mech_type, - IN const unsigned char * const source, - IN const size_t source_size, - OUT unsigned char * const target, - IN OUT size_t * const target_size +static +void * +_pkcs11h_slotevent_manager ( + IN void *p ) { - CK_MECHANISM mech = { - mech_type, NULL, 0 - }; - CK_RV rv = CKR_OK; - bool fLogonRetry = false; - bool fOpSuccess = false; + PKCS11H_BOOL fFirst = TRUE; - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); - PKCS11ASSERT (pkcs11h_certificate!=NULL); - PKCS11ASSERT (source!=NULL); - PKCS11ASSERT (target_size!=NULL); + (void)p; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_signRecover entry pkcs11h_certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p", - (void *)pkcs11h_certificate, - mech_type, - source, - source_size, - target, - (void *)target_size + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_manager entry" ); - if (rv == CKR_OK) { - rv = _pkcs11h_validateSession (pkcs11h_certificate->session); - } + /* + * Trigger hook, so application may + * depend on initial slot change + */ + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling slotevent hook" + ); + s_pkcs11h_data->hooks.slotevent (s_pkcs11h_data->hooks.slotevent_data); - while (rv == CKR_OK && !fOpSuccess) { + while ( + fFirst || /* Must enter wait or mutex will never be free */ + !s_pkcs11h_data->fSlotEventShouldTerminate + ) { + pkcs11h_provider_t current_provider; + + fFirst = FALSE; /* - * Don't try invalid object + * Start each provider thread + * if not already started. + * This is required in order to allow + * adding new providers. */ - if ( - rv == CKR_OK && - pkcs11h_certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE + for ( + current_provider = s_pkcs11h_data->providers; + current_provider != NULL; + current_provider = current_provider->next ) { - rv = CKR_OBJECT_HANDLE_INVALID; + if (!current_provider->fEnabled) { + if (current_provider->threadSlotEvent == PKCS11H_THREAD_NULL) { + _pkcs11h_threadStart ( + ¤t_provider->threadSlotEvent, + _pkcs11h_slotevent_provider, + current_provider + ); + } + } + else { + if (current_provider->threadSlotEvent != PKCS11H_THREAD_NULL) { + _pkcs11h_threadJoin (¤t_provider->threadSlotEvent); + } + } } - if (rv == CKR_OK) { - rv = pkcs11h_certificate->session->provider->f->C_SignRecoverInit ( - pkcs11h_certificate->session->hSession, - &mech, - pkcs11h_certificate->hKey + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_manager waiting for slotevent" + ); + _pkcs11h_condWait (&s_pkcs11h_data->condSlotEvent, PKCS11H_COND_INFINITE); + + if (s_pkcs11h_data->fSlotEventSkipEvent) { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Slotevent skipping event" ); + s_pkcs11h_data->fSlotEventSkipEvent = FALSE; } - - if (rv == CKR_OK) { - CK_ULONG size = *target_size; - rv = pkcs11h_certificate->session->provider->f->C_SignRecover ( - pkcs11h_certificate->session->hSession, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size + else { + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, + "PKCS#11: Calling slotevent hook" ); - - *target_size = (int)size; + s_pkcs11h_data->hooks.slotevent (s_pkcs11h_data->hooks.slotevent_data); } + } + { + pkcs11h_provider_t current_provider; - if (rv == CKR_OK) { - fOpSuccess = true; - } - else { - if (!fLogonRetry) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Private key operation failed rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) - ); - fLogonRetry = true; - rv = _pkcs11h_resetCertificateSession (pkcs11h_certificate); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_manager joining threads" + ); + + + for ( + current_provider = s_pkcs11h_data->providers; + current_provider != NULL; + current_provider = current_provider->next + ) { + if (current_provider->threadSlotEvent != PKCS11H_THREAD_NULL) { + _pkcs11h_threadJoin (¤t_provider->threadSlotEvent); } } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_signRecover return rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_manager return" ); - return rv; + return NULL; } +static CK_RV -pkcs11h_decrypt ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - IN const CK_MECHANISM_TYPE mech_type, - IN const unsigned char * const source, - IN const size_t source_size, - OUT unsigned char * const target, - IN OUT size_t * const target_size -) { - CK_MECHANISM mech = { - mech_type, NULL, 0 - }; - CK_ULONG size; +_pkcs11h_slotevent_init () { CK_RV rv = CKR_OK; - bool fLogonRetry = false; - bool fOpSuccess = false; - - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); - PKCS11ASSERT (pkcs11h_certificate!=NULL); - PKCS11ASSERT (source!=NULL); - PKCS11ASSERT (target_size!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_decrypt entry pkcs11h_certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p", - (void *)pkcs11h_certificate, - mech_type, - source, - source_size, - target, - (void *)target_size + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_init entry" ); - if (rv != CKR_OK) { - rv = _pkcs11h_validateSession (pkcs11h_certificate->session); - } - - while (rv == CKR_OK && !fOpSuccess) { - - /* - * Don't try invalid object - */ - if ( - rv == CKR_OK && - pkcs11h_certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE - ) { - rv = CKR_OBJECT_HANDLE_INVALID; - } - + if (!s_pkcs11h_data->fSlotEventInitialized) { if (rv == CKR_OK) { - rv = pkcs11h_certificate->session->provider->f->C_DecryptInit ( - pkcs11h_certificate->session->hSession, - &mech, - pkcs11h_certificate->hKey - ); + rv = _pkcs11h_condInit (&s_pkcs11h_data->condSlotEvent); } - + if (rv == CKR_OK) { - size = *target_size; - rv = pkcs11h_certificate->session->provider->f->C_Decrypt ( - pkcs11h_certificate->session->hSession, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size + rv = _pkcs11h_threadStart ( + &s_pkcs11h_data->threadSlotEvent, + _pkcs11h_slotevent_manager, + NULL ); - - *target_size = (int)size; } - + if (rv == CKR_OK) { - fOpSuccess = true; - } - else { - if (!fLogonRetry) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, - "PKCS#11: Private key operation failed rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) - ); - fLogonRetry = true; - rv = _pkcs11h_resetCertificateSession (pkcs11h_certificate); - } + s_pkcs11h_data->fSlotEventInitialized = TRUE; } } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_decrypt return rv=%ld-'%s'", + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_init return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); @@ -2495,173 +8531,79 @@ pkcs11h_decrypt ( return rv; } +static CK_RV -pkcs11h_getCertificate ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - OUT unsigned char * const certificate, - IN OUT size_t * const certificate_size -) { - CK_RV rv = CKR_OK; +_pkcs11h_slotevent_notify () { - PKCS11ASSERT (pkcs11h_data!=NULL); - PKCS11ASSERT (pkcs11h_data->fInitialized); - PKCS11ASSERT (certificate_size!=NULL); - - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_getCertificate entry pkcs11h_certificate=%p, certificate=%p, certificate_size=%p", - (void *)pkcs11h_certificate, - certificate, - (void *)certificate_size + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_notify entry" ); - if ( - rv == CKR_OK && - pkcs11h_certificate->certificate == NULL - ) { - rv = CKR_FUNCTION_REJECTED; + if (s_pkcs11h_data->fSlotEventInitialized) { + s_pkcs11h_data->fSlotEventSkipEvent = TRUE; + _pkcs11h_condSignal (&s_pkcs11h_data->condSlotEvent); } - if (rv == CKR_OK) { - *certificate_size = pkcs11h_certificate->certificate_size; - } + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_notify return" + ); - if (certificate != NULL) { - if ( - rv == CKR_OK && - *certificate_size > pkcs11h_certificate->certificate_size - ) { - rv = CKR_BUFFER_TOO_SMALL; - } + return CKR_OK; +} + +static +CK_RV +_pkcs11h_slotevent_terminate () { - if (rv == CKR_OK) { - memmove (certificate, pkcs11h_certificate->certificate, *certificate_size); + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_terminate entry" + ); + + if (s_pkcs11h_data->fSlotEventInitialized) { + s_pkcs11h_data->fSlotEventShouldTerminate = TRUE; + + _pkcs11h_slotevent_notify (); + + if (s_pkcs11h_data->threadSlotEvent != PKCS11H_THREAD_NULL) { + _pkcs11h_threadJoin (&s_pkcs11h_data->threadSlotEvent); } + + _pkcs11h_condFree (&s_pkcs11h_data->condSlotEvent); + s_pkcs11h_data->fSlotEventInitialized = FALSE; } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_getCertificate return rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: _pkcs11h_slotevent_terminate return" ); return CKR_OK; } -char * -pkcs11h_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"; - } -} +#endif -/*========================================== - * openssl interface - */ +#if defined(ENABLE_PKCS11H_OPENSSL) +/*======================================================================* + * OPENSSL INTERFACE + *======================================================================*/ static pkcs11h_openssl_session_t -_pkcs11h_openssl_get_pkcs11h_openssl_session ( +_pkcs11h_openssl_get_openssl_session ( IN OUT const RSA *rsa ) { pkcs11h_openssl_session_t session; - PKCS11ASSERT (rsa!=NULL); + PKCS11H_ASSERT (rsa!=NULL); #if OPENSSL_VERSION_NUMBER < 0x00907000L session = (pkcs11h_openssl_session_t)RSA_get_app_data ((RSA *)rsa); #else session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa); #endif - PKCS11ASSERT (session!=NULL); + PKCS11H_ASSERT (session!=NULL); return session; } @@ -2671,12 +8613,10 @@ pkcs11h_certificate_t _pkcs11h_openssl_get_pkcs11h_certificate ( IN OUT const RSA *rsa ) { - pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_pkcs11h_openssl_session (rsa); + pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_openssl_session (rsa); - PKCS11ASSERT (session!=NULL); - PKCS11ASSERT (session->certificate!=NULL); - PKCS11ASSERT (session->certificate->session!=NULL); - PKCS11ASSERT (session->certificate->session->fValid); + PKCS11H_ASSERT (session!=NULL); + PKCS11H_ASSERT (session->certificate!=NULL); return session->certificate; } @@ -2702,12 +8642,12 @@ _pkcs11h_openssl_dec ( IN int padding ) { #endif - PKCS11ASSERT (from!=NULL); - PKCS11ASSERT (to!=NULL); - PKCS11ASSERT (rsa!=NULL); + PKCS11H_ASSERT (from!=NULL); + PKCS11H_ASSERT (to!=NULL); + PKCS11H_ASSERT (rsa!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d", flen, from, @@ -2716,13 +8656,13 @@ _pkcs11h_openssl_dec ( padding ); - PKCS11LOG ( - PKCS11_LOG_ERROR, + PKCS11H_LOG ( + PKCS11H_LOG_ERROR, "PKCS#11: Private key decryption is not supported" ); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_dec return" ); @@ -2752,7 +8692,7 @@ _pkcs11h_openssl_sign ( IN OUT const RSA *rsa ) { #endif - pkcs11h_certificate_t pkcs11h_certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa); + pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa); CK_RV rv = CKR_OK; int myrsa_size = 0; @@ -2761,12 +8701,12 @@ _pkcs11h_openssl_sign ( unsigned char *enc = NULL; int enc_len = 0; - PKCS11ASSERT (m!=NULL); - PKCS11ASSERT (sigret!=NULL); - PKCS11ASSERT (siglen!=NULL); + PKCS11H_ASSERT (m!=NULL); + PKCS11H_ASSERT (sigret!=NULL); + PKCS11H_ASSERT (siglen!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_sign entered - type=%d, m=%p, m_len=%u, signret=%p, signlen=%p, rsa=%p", type, m, @@ -2794,18 +8734,18 @@ _pkcs11h_openssl_sign ( if ( rv == CKR_OK && - (enc=enc_alloc=(unsigned char *)malloc ((unsigned int)myrsa_size+1)) == NULL + (rv = _pkcs11h_malloc ((void*)&enc, myrsa_size+1)) == CKR_OK ) { - rv = CKR_HOST_MEMORY; + enc_alloc = enc; } if (rv == CKR_OK) { - sig.algor= &algor; + sig.algor = &algor; } if ( rv == CKR_OK && - (sig.algor->algorithm=OBJ_nid2obj(type)) == NULL + (sig.algor->algorithm = OBJ_nid2obj (type)) == NULL ) { rv = CKR_FUNCTION_FAILED; } @@ -2818,26 +8758,26 @@ _pkcs11h_openssl_sign ( } if (rv == CKR_OK) { - parameter.type=V_ASN1_NULL; - parameter.value.ptr=NULL; + parameter.type = V_ASN1_NULL; + parameter.value.ptr = NULL; - sig.algor->parameter= ¶meter; + sig.algor->parameter = ¶meter; - sig.digest=&digest; - sig.digest->data=(unsigned char *)m; - sig.digest->length=m_len; + sig.digest = &digest; + sig.digest->data = (unsigned char *)m; + sig.digest->length = m_len; } if ( rv == CKR_OK && - (enc_len=i2d_X509_SIG(&sig,NULL)) < 0 + (enc_len=i2d_X509_SIG (&sig, NULL)) < 0 ) { rv = CKR_FUNCTION_FAILED; } if (rv == CKR_OK) { - unsigned char *p=enc; - i2d_X509_SIG(&sig,&p); + unsigned char *p = enc; + i2d_X509_SIG (&sig, &p); } } @@ -2848,65 +8788,34 @@ _pkcs11h_openssl_sign ( rv = CKR_KEY_SIZE_RANGE; } - /* - * Get key attributes - * so signature mode will - * be available - */ - if (rv == CKR_OK) { - rv = _pkcs11h_getCertificateKeyAttributes (pkcs11h_certificate); - } - if (rv == CKR_OK) { - PKCS11DLOG ( - PKCS11_LOG_DEBUG1, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG1, "PKCS#11: Performing signature" ); - *siglen = myrsa_size; - - switch (pkcs11h_certificate->signmode) { - case pkcs11h_signmode_sign: - if ( - (rv = pkcs11h_sign ( - pkcs11h_certificate, - CKM_RSA_PKCS, - enc, - enc_len, - sigret, - siglen - )) != CKR_OK - ) { - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11h_getMessage (rv)); - } - break; - case pkcs11h_signmode_recover: - if ( - (rv = pkcs11h_signRecover ( - pkcs11h_certificate, - CKM_RSA_PKCS, - enc, - enc_len, - sigret, - siglen - )) != CKR_OK - ) { - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11h_getMessage (rv)); - } - break; - default: - rv = CKR_FUNCTION_REJECTED; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Invalid signature mode"); - break; + *siglen = myrsa_size; + + if ( + (rv = pkcs11h_certificate_signAny ( + certificate, + CKM_RSA_PKCS, + enc, + enc_len, + sigret, + siglen + )) != CKR_OK + ) { + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11h_getMessage (rv)); } } if (enc_alloc != NULL) { - free (enc_alloc); + _pkcs11h_free ((void *)&enc_alloc); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_sign - return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) @@ -2920,18 +8829,18 @@ int _pkcs11h_openssl_finish ( IN OUT RSA *rsa ) { - pkcs11h_openssl_session_t pkcs11h_openssl_session = _pkcs11h_openssl_get_pkcs11h_openssl_session (rsa); + pkcs11h_openssl_session_t openssl_session = _pkcs11h_openssl_get_openssl_session (rsa); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_finish - entered rsa=%p", (void *)rsa ); RSA_set_app_data (rsa, NULL); - if (pkcs11h_openssl_session->orig_finish != NULL) { - pkcs11h_openssl_session->orig_finish (rsa); + if (openssl_session->orig_finish != NULL) { + openssl_session->orig_finish (rsa); #ifdef BROKEN_OPENSSL_ENGINE { @@ -2950,10 +8859,10 @@ _pkcs11h_openssl_finish ( #endif } - pkcs11h_openssl_freeSession (pkcs11h_openssl_session); + pkcs11h_openssl_freeSession (openssl_session); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_finish - return" ); @@ -2961,192 +8870,187 @@ _pkcs11h_openssl_finish ( } pkcs11h_openssl_session_t -pkcs11h_openssl_createSession () { - pkcs11h_openssl_session_t pkcs11h_openssl_session = NULL; - bool fOK = true; +pkcs11h_openssl_createSession ( + IN const pkcs11h_certificate_t certificate +) { + pkcs11h_openssl_session_t openssl_session = NULL; + PKCS11H_BOOL fOK = TRUE; - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_createSession - entry" ); if ( fOK && - (pkcs11h_openssl_session = (pkcs11h_openssl_session_t)malloc (sizeof (struct pkcs11h_openssl_session_s))) == NULL + _pkcs11h_malloc ( + (void*)&openssl_session, + sizeof (struct pkcs11h_openssl_session_s)) != CKR_OK ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot allocate memory"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate memory"); } if (fOK) { - memset (pkcs11h_openssl_session, 0, sizeof (struct pkcs11h_openssl_session_s)); - } + const RSA_METHOD *def = RSA_get_default_method(); - if (fOK) { - pkcs11h_openssl_session->nReferenceCount = 1; + memmove (&openssl_session->smart_rsa, def, sizeof(RSA_METHOD)); + + openssl_session->orig_finish = def->finish; + + openssl_session->smart_rsa.name = "pkcs11"; + openssl_session->smart_rsa.rsa_priv_dec = _pkcs11h_openssl_dec; + openssl_session->smart_rsa.rsa_sign = _pkcs11h_openssl_sign; + openssl_session->smart_rsa.finish = _pkcs11h_openssl_finish; + openssl_session->smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY; + openssl_session->certificate = certificate; + openssl_session->nReferenceCount = 1; } if (!fOK) { - free (pkcs11h_openssl_session); - pkcs11h_openssl_session = NULL; + _pkcs11h_free ((void *)&openssl_session); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_openssl_createSession - return pkcs11h_openssl_session=%p", - (void *)pkcs11h_openssl_session + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_openssl_createSession - return openssl_session=%p", + (void *)openssl_session ); - return pkcs11h_openssl_session; + return openssl_session; } void pkcs11h_openssl_freeSession ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ) { - PKCS11ASSERT (pkcs11h_openssl_session!=NULL); - PKCS11ASSERT (pkcs11h_openssl_session->nReferenceCount>0); + PKCS11H_ASSERT (openssl_session!=NULL); + PKCS11H_ASSERT (openssl_session->nReferenceCount>0); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_openssl_freeSession - entry pkcs11h_openssl_session=%p, count=%d", - (void *)pkcs11h_openssl_session, - pkcs11h_openssl_session->nReferenceCount + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_openssl_freeSession - entry openssl_session=%p, count=%d", + (void *)openssl_session, + openssl_session->nReferenceCount ); - pkcs11h_openssl_session->nReferenceCount--; + openssl_session->nReferenceCount--; - if (pkcs11h_openssl_session->nReferenceCount == 0) { - if (pkcs11h_openssl_session->x509) { - X509_free (pkcs11h_openssl_session->x509); - pkcs11h_openssl_session->x509 = NULL; + if (openssl_session->nReferenceCount == 0) { + if (openssl_session->x509 != NULL) { + X509_free (openssl_session->x509); + openssl_session->x509 = NULL; } - if (pkcs11h_openssl_session->certificate != NULL) { - pkcs11h_freeCertificateSession (pkcs11h_openssl_session->certificate); - pkcs11h_openssl_session->certificate = NULL; + if (openssl_session->certificate != NULL) { + pkcs11h_freeCertificate (openssl_session->certificate); + openssl_session->certificate = NULL; } - free (pkcs11h_openssl_session); + _pkcs11h_free ((void *)&openssl_session); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_freeSession - return" ); } RSA * pkcs11h_openssl_getRSA ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ) { X509 *x509 = NULL; RSA *rsa = NULL; EVP_PKEY *pubkey = NULL; CK_RV rv = CKR_OK; - unsigned char certificate[10*1024]; - size_t certificate_size; pkcs11_openssl_d2i_t d2i1 = NULL; - bool fOK = true; + PKCS11H_BOOL fOK = TRUE; - PKCS11ASSERT (pkcs11h_openssl_session!=NULL); - PKCS11ASSERT (!pkcs11h_openssl_session->fInitialized); + PKCS11H_ASSERT (openssl_session!=NULL); + PKCS11H_ASSERT (!openssl_session->fInitialized); + PKCS11H_ASSERT (openssl_session!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_openssl_getRSA - entry pkcs11h_openssl_session=%p", - (void *)pkcs11h_openssl_session + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_openssl_getRSA - entry openssl_session=%p", + (void *)openssl_session ); if ( fOK && (x509 = X509_new ()) == NULL ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable to allocate certificate object"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to allocate certificate object"); } - certificate_size = sizeof (certificate); if ( fOK && - (rv = pkcs11h_getCertificate ( - pkcs11h_openssl_session->certificate, - certificate, - &certificate_size - )) != CKR_OK - ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv)); + (rv = _pkcs11h_ensureCertificateBlob (openssl_session->certificate)) != CKR_OK + ) { + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv)); } - d2i1 = (pkcs11_openssl_d2i_t)certificate; + d2i1 = (pkcs11_openssl_d2i_t)openssl_session->certificate->id->certificate_blob; if ( fOK && - !d2i_X509 (&x509, &d2i1, certificate_size) + !d2i_X509 (&x509, &d2i1, openssl_session->certificate->id->certificate_blob_size) ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate"); } if ( fOK && (pubkey = X509_get_pubkey (x509)) == NULL ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot get public key"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get public key"); } if ( fOK && pubkey->type != EVP_PKEY_RSA ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Invalid public key algorithm"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Invalid public key algorithm"); } if ( fOK && (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL ) { - fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot get RSA key"); + fOK = FALSE; + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get RSA key"); } - if (fOK) { - const RSA_METHOD *def = RSA_get_default_method(); - - memmove (&pkcs11h_openssl_session->smart_rsa, def, sizeof(RSA_METHOD)); - - pkcs11h_openssl_session->orig_finish = def->finish; - - pkcs11h_openssl_session->smart_rsa.name = "pkcs11"; - pkcs11h_openssl_session->smart_rsa.rsa_priv_dec = _pkcs11h_openssl_dec; - pkcs11h_openssl_session->smart_rsa.rsa_sign = _pkcs11h_openssl_sign; - pkcs11h_openssl_session->smart_rsa.finish = _pkcs11h_openssl_finish; - pkcs11h_openssl_session->smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY; + if (fOK) { - RSA_set_method (rsa, &pkcs11h_openssl_session->smart_rsa); - RSA_set_app_data (rsa, pkcs11h_openssl_session); - pkcs11h_openssl_session->nReferenceCount++; + RSA_set_method (rsa, &openssl_session->smart_rsa); + RSA_set_app_data (rsa, openssl_session); + openssl_session->nReferenceCount++; } #ifdef BROKEN_OPENSSL_ENGINE if (fOK) { - if (!rsa->engine) + if (!rsa->engine) { rsa->engine = ENGINE_get_default_RSA(); + } - ENGINE_set_RSA(ENGINE_get_default_RSA(), &pkcs11h_openssl_session->smart_rsa); - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled"); + ENGINE_set_RSA(ENGINE_get_default_RSA(), &openssl_session->smart_rsa); + PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled"); } #endif if (fOK) { /* - So that it won't hold RSA - */ - pkcs11h_openssl_session->x509 = X509_dup (x509); + * dup x509 so that it won't hold RSA + */ + openssl_session->x509 = X509_dup (x509); rsa->flags |= RSA_FLAG_SIGN_VER; - pkcs11h_openssl_session->fInitialized = true; + openssl_session->fInitialized = TRUE; } else { if (rsa != NULL) { @@ -3169,8 +9073,8 @@ pkcs11h_openssl_getRSA ( x509 = NULL; } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_getRSA - return rsa=%p", (void *)rsa ); @@ -3180,24 +9084,24 @@ pkcs11h_openssl_getRSA ( X509 * pkcs11h_openssl_getX509 ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ) { X509 *x509 = NULL; - PKCS11ASSERT (pkcs11h_openssl_session!=NULL); + PKCS11H_ASSERT (openssl_session!=NULL); - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, - "PKCS#11: pkcs11h_openssl_getX509 - entry pkcs11h_openssl_session=%p", - (void *)pkcs11h_openssl_session + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, + "PKCS#11: pkcs11h_openssl_getX509 - entry openssl_session=%p", + (void *)openssl_session ); - if (pkcs11h_openssl_session->x509 != NULL) { - x509 = X509_dup (pkcs11h_openssl_session->x509); + if (openssl_session->x509 != NULL) { + x509 = X509_dup (openssl_session->x509); } - PKCS11DLOG ( - PKCS11_LOG_DEBUG2, + PKCS11H_DEBUG ( + PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_getX509 - return x509=%p", (void *)x509 ); @@ -3205,6 +9109,12 @@ pkcs11h_openssl_getX509 ( return x509; } +#endif /* ENABLE_PKCS11H_OPENSSL */ + +#if defined(ENABLE_PKCS11H_STANDALONE) +/*======================================================================* + * STANDALONE INTERFACE + *======================================================================*/ void pkcs11h_standalone_dump_slots ( @@ -3216,7 +9126,9 @@ pkcs11h_standalone_dump_slots ( pkcs11h_provider_t pkcs11h_provider; - PKCS11ASSERT (provider!=NULL); + PKCS11H_ASSERT (my_output!=NULL); + /*PKCS11H_ASSERT (pData) NOT NEEDED */ + PKCS11H_ASSERT (provider!=NULL); if ( rv == CKR_OK && @@ -3227,7 +9139,18 @@ pkcs11h_standalone_dump_slots ( if ( rv == CKR_OK && - (rv = pkcs11h_addProvider (provider, NULL)) != CKR_OK + (rv = pkcs11h_addProvider ( + provider, + provider, + FALSE, + ( + PKCS11H_SIGNMODE_MASK_SIGN | + PKCS11H_SIGNMODE_MASK_RECOVER + ), + PKCS11H_SLOTEVENT_METHOD_AUTO, + 0, + FALSE + )) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); } @@ -3236,7 +9159,7 @@ pkcs11h_standalone_dump_slots ( * our provider is head */ if (rv == CKR_OK) { - pkcs11h_provider = pkcs11h_data->providers; + pkcs11h_provider = s_pkcs11h_data->providers; if (pkcs11h_provider == NULL || !pkcs11h_provider->fEnabled) { my_output (pData, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); rv = CKR_GENERAL_ERROR; @@ -3254,8 +9177,8 @@ pkcs11h_standalone_dump_slots ( char szManufacturerID[sizeof (info.manufacturerID)+1]; _pkcs11h_fixupFixedString ( - (char *)info.manufacturerID, szManufacturerID, + (char *)info.manufacturerID, sizeof (info.manufacturerID) ); @@ -3277,17 +9200,17 @@ pkcs11h_standalone_dump_slots ( } if (rv == CKR_OK) { - CK_SLOT_ID slots[1024]; + CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; - CK_SLOT_ID s; + CK_SLOT_ID slot_index; - slotnum = sizeof (slots) / sizeof (CK_SLOT_ID); if ( - (rv = pkcs11h_provider->f->C_GetSlotList ( - FALSE, - slots, + _pkcs11h_getSlotList ( + pkcs11h_provider, + CK_FALSE, + &slots, &slotnum - )) != CKR_OK + ) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot get slot list %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); } @@ -3301,47 +9224,92 @@ pkcs11h_standalone_dump_slots ( "\n" "Slots: (id - name)\n" ), - PKCS11_PRM_SLOT_TYPE, - PKCS11_PRM_SLOT_ID + PKCS11H_PRM_SLOT_TYPE, + PKCS11H_PRM_SLOT_ID ); - for (s=0;sf->C_GetSlotInfo ( - slots[s], + slots[slot_index], &info )) == CKR_OK ) { char szCurrentName[sizeof (info.slotDescription)+1]; _pkcs11h_fixupFixedString ( - (char *)info.slotDescription, szCurrentName, + (char *)info.slotDescription, sizeof (info.slotDescription) ); - my_output (pData, "\t%lu - %s\n", slots[s], szCurrentName); + my_output (pData, "\t%lu - %s\n", slots[slot_index], szCurrentName); } } } + + if (slots != NULL) { + _pkcs11h_free ((void *)&slots); + } } pkcs11h_terminate (); } static -bool +PKCS11H_BOOL _pkcs11h_standalone_dump_objects_pin_prompt ( IN const void *pData, - IN const char * const szLabel, + IN const pkcs11h_token_id_t token, OUT char * const szPIN, IN const size_t nMaxPIN ) { strncpy (szPIN, (char *)pData, nMaxPIN); - return true; + return TRUE; } +void +_pkcs11h_standalone_dump_objects_hex ( + IN const unsigned char * const p, + IN const size_t p_size, + OUT char * const sz, + IN const size_t max, + IN const char * const szLinePrefix +) { + size_t j; + + sz[0] = '\0'; + + for (j=0;jproviders; + pkcs11h_provider = s_pkcs11h_data->providers; if (pkcs11h_provider == NULL || !pkcs11h_provider->fEnabled) { my_output (pData, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); rv = CKR_GENERAL_ERROR; @@ -3403,6 +9386,7 @@ pkcs11h_standalone_dump_objects ( )) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv)); + /* Ignore this error */ rv = CKR_OK; } else { @@ -3412,23 +9396,23 @@ pkcs11h_standalone_dump_objects ( char szSerialNumber[sizeof (info.serialNumber)+1]; _pkcs11h_fixupFixedString ( - (char *)info.label, szLabel, + (char *)info.label, sizeof (info.label) ); _pkcs11h_fixupFixedString ( - (char *)info.manufacturerID, szManufacturerID, + (char *)info.manufacturerID, sizeof (info.manufacturerID) ); _pkcs11h_fixupFixedString ( - (char *)info.model, szModel, + (char *)info.model, sizeof (info.model) ); _pkcs11h_fixupFixedString ( - (char *)info.serialNumber, szSerialNumber, + (char *)info.serialNumber, sizeof (info.serialNumber) ); @@ -3451,256 +9435,449 @@ pkcs11h_standalone_dump_objects ( szModel, szSerialNumber, (unsigned)info.flags, - PKCS11_PRM_SLOT_TYPE, - PKCS11_PRM_SLOT_ID, + PKCS11H_PRM_SLOT_TYPE, + PKCS11H_PRM_SLOT_ID, szLabel ); + + if ( + rv == CKR_OK && + (rv = _pkcs11h_getTokenId ( + &info, + &token_id + )) != CKR_OK + ) { + my_output (pData, "PKCS#11: Cannot get token id for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv)); + rv = CKR_OK; + } } } - if (rv == CKR_OK) { - CK_SESSION_HANDLE session; - + if (token_id != NULL) { if ( - (rv = pkcs11h_provider->f->C_OpenSession ( - s, - CKF_SERIAL_SESSION, - NULL_PTR, - NULL_PTR, + (rv = _pkcs11h_getSessionByTokenId ( + token_id, &session )) != CKR_OK ) { - my_output (pData, "PKCS#11: Cannot open session to slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv)); + my_output (pData, "PKCS#11: Cannot session for token '%s' %ld-'%s'\n", token_id->label, rv, pkcs11h_getMessage (rv)); rv = CKR_OK; } - else { - CK_OBJECT_HANDLE objects[10]; - CK_ULONG objects_found; + } + + if (session != NULL) { + CK_OBJECT_HANDLE *objects = NULL; + CK_ULONG objects_found = 0; + CK_ULONG i; + + if ( + (rv = _pkcs11h_login ( + session, + FALSE, + TRUE, + PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT + )) != CKR_OK + ) { + my_output (pData, "PKCS#11: Cannot open session to token '%s' %ld-'%s'\n", session->token_id->label, rv, pkcs11h_getMessage (rv)); + } + my_output ( + pData, + ( + "The following objects are available for use with this token.\n" + "Each object shown below may be used as a parameter to\n" + "%s and %s options.\n" + "\n" + ), + PKCS11H_PRM_OBJ_TYPE, + PKCS11H_PRM_OBJ_ID + ); + + if ( + rv == CKR_OK && + (rv = _pkcs11h_findObjects ( + session, + NULL, + 0, + &objects, + &objects_found + )) != CKR_OK + ) { + my_output (pData, "PKCS#11: Cannot query objects for token '%s' %ld-'%s'\n", session->token_id->label, rv, pkcs11h_getMessage (rv)); + } + + for (i=0;rv == CKR_OK && i < objects_found;i++) { + CK_OBJECT_CLASS attrs_class = 0; + CK_ATTRIBUTE attrs[] = { + {CKA_CLASS, &attrs_class, sizeof (attrs_class)} + }; + if ( - (rv = pkcs11h_provider->f->C_Login ( - session, - CKU_USER, - (CK_CHAR_PTR)pin, - (CK_ULONG)strlen (pin) - )) != CKR_OK && - rv != CKR_USER_ALREADY_LOGGED_IN - ) { - my_output (pData, "PKCS#11: Cannot login to token on slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv)); - } - - if ( - (rv = pkcs11h_provider->f->C_FindObjectsInit ( + _pkcs11h_getObjectAttributes ( session, - NULL, - 0 - )) != CKR_OK + objects[i], + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ) == CKR_OK ) { - my_output (pData, "PKCS#11: Cannot query objects for token on slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv)); - } - - my_output ( - pData, - ( - "The following objects are available for use with this token.\n" - "Each object shown below may be used as a parameter to\n" - "%s and %s options.\n" - "\n" - ), - PKCS11_PRM_OBJ_TYPE, - PKCS11_PRM_OBJ_ID - ); - - while ( - (rv = pkcs11h_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;if->C_GetAttributeValue ( + _pkcs11h_getObjectAttributes ( session, objects[i], - attrs, - sizeof (attrs) / sizeof (CK_ATTRIBUTE) + attrs_cert, + sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE) + ) == CKR_OK && + _pkcs11h_malloc ( + (void *)&attrs_label, + attrs_cert[1].ulValueLen+1 ) == CKR_OK ) { - int id_len = attrs[1].ulValueLen; - int j; - - attrs_label[attrs[2].ulValueLen] = 0; - - my_output ( - pData, - ( - "Object\n" - "\tLabel:\t\t%s\n" - "\tId:\n" - ), - attrs_label + attrs_id = (unsigned char *)attrs_cert[0].pValue; + attrs_id_size = attrs_cert[0].ulValueLen; + attrs_value = (unsigned char *)attrs_cert[2].pValue; + attrs_value_size = attrs_cert[2].ulValueLen; + + memset (attrs_label, 0, attrs_cert[1].ulValueLen+1); + memmove (attrs_label, attrs_cert[1].pValue, attrs_cert[1].ulValueLen); + _pkcs11h_standalone_dump_objects_hex ( + attrs_id, + attrs_id_size, + szHexId, + sizeof (szHexId), + "\t\t" ); - - - for (j=0;jf->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) { - my_output (pData, "Cannot create x509 context\n"); - } - else { - pkcs11_openssl_d2i_t d2i1 = (pkcs11_openssl_d2i_t)certificate; - if (d2i_X509 (&x509, &d2i1, 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) { - my_output (pData, "Cannot create BIO context\n"); - } - 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; + else { + pkcs11_openssl_d2i_t d2i1 = (pkcs11_openssl_d2i_t)attrs_value; + if (d2i_X509 (&x509, &d2i1, attrs_value_size)) { + + 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'; } - - my_output ( - pData, - ( - "\tsubject:\t%s\n" - "\tserialNumber:\t%s\n" - "\tnotBefore:\t%s\n" - ), + + X509_NAME_oneline ( + X509_get_subject_name (x509), szSubject, - szSerial, - szNotBefore + sizeof (szSubject) ); + szSubject[sizeof (szSubject) - 1] = '\0'; } } - 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)} - }; - - my_output (pData, "\tType:\t\tPrivate Key\n"); - - if ( - pkcs11h_provider->f->C_GetAttributeValue ( - session, - objects[i], - attrs_key, - sizeof (attrs_key) / sizeof (CK_ATTRIBUTE) - ) == CKR_OK - ) { - my_output ( - pData, - ( - "\tSign:\t\t%s\n" - "\tSign Recover:\t%s\n" - ), - sign ? "TRUE" : "FALSE", - sign_recover ? "TRUE" : "FALSE" - ); - } + + if ((bioSerial = BIO_new (BIO_s_mem ())) == NULL) { + my_output (pData, "Cannot create BIO context\n"); } else { - my_output (pData, "\tType:\t\tUnsupported\n"); + 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; } } + + my_output ( + pData, + ( + "Object\n" + "\tType:\t\t\tCertificate\n" + "\tCKA_ID:\n" + "%s" + "\tCKA_LABEL:\t\t%s\n" + "\tsubject:\t\t%s\n" + "\tserialNumber:\t\t%s\n" + "\tnotBefore:\t\t%s\n" + ), + szHexId, + attrs_label, + szSubject, + szSerial, + szNotBefore + ); + + _pkcs11h_free ((void *)&attrs_label); + + _pkcs11h_freeObjectAttributes ( + attrs_cert, + sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE) + ); + } + else if (attrs_class == CKO_PRIVATE_KEY) { + CK_BBOOL sign_recover = CK_FALSE; + CK_BBOOL sign = CK_FALSE; + CK_ATTRIBUTE attrs_key[] = { + {CKA_SIGN, &sign_recover, sizeof (sign_recover)}, + {CKA_SIGN_RECOVER, &sign, sizeof (sign)} + }; + CK_ATTRIBUTE attrs_key_common[] = { + {CKA_ID, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + unsigned char *attrs_id = NULL; + int attrs_id_size = 0; + char *attrs_label = NULL; + char szHexId[1024]; + + pkcs11h_provider->f->C_GetAttributeValue ( + session->hSession, + objects[i], + attrs_key, + sizeof (attrs_key) / sizeof (CK_ATTRIBUTE) + ); + + if ( + _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ) == CKR_OK && + _pkcs11h_malloc ( + (void *)&attrs_label, + attrs_key_common[1].ulValueLen+1 + ) == CKR_OK + ) { + attrs_id = (unsigned char *)attrs_key_common[0].pValue; + attrs_id_size = attrs_key_common[0].ulValueLen; + + memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1); + memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen); + + _pkcs11h_standalone_dump_objects_hex ( + attrs_id, + attrs_id_size, + szHexId, + sizeof (szHexId), + "\t\t" + ); + + } + + my_output ( + pData, + ( + "Object\n" + "\tType:\t\t\tPrivate Key\n" + "\tCKA_ID:\n" + "%s" + "\tCKA_LABEL:\t\t%s\n" + "\tCKA_SIGN:\t\t%s\n" + "\tCKA_SIGN_RECOVER:\t%s\n" + ), + szHexId, + attrs_label, + sign ? "TRUE" : "FALSE", + sign_recover ? "TRUE" : "FALSE" + ); + + _pkcs11h_free ((void *)&attrs_label); + + _pkcs11h_freeObjectAttributes ( + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ); + } + else if (attrs_class == CKO_PUBLIC_KEY) { + CK_ATTRIBUTE attrs_key_common[] = { + {CKA_ID, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + unsigned char *attrs_id = NULL; + int attrs_id_size = 0; + char *attrs_label = NULL; + char szHexId[1024]; + + if ( + _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ) == CKR_OK && + _pkcs11h_malloc ( + (void *)&attrs_label, + attrs_key_common[1].ulValueLen+1 + ) == CKR_OK + ) { + attrs_id = (unsigned char *)attrs_key_common[0].pValue; + attrs_id_size = attrs_key_common[0].ulValueLen; + + memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1); + memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen); + + _pkcs11h_standalone_dump_objects_hex ( + attrs_id, + attrs_id_size, + szHexId, + sizeof (szHexId), + "\t\t" + ); + + } + + my_output ( + pData, + ( + "Object\n" + "\tType:\t\t\tPublic Key\n" + "\tCKA_ID:\n" + "%s" + "\tCKA_LABEL:\t\t%s\n" + ), + szHexId, + attrs_label + ); + + _pkcs11h_free ((void *)&attrs_label); + + _pkcs11h_freeObjectAttributes ( + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ); + } + else if (attrs_class == CKO_DATA) { + CK_ATTRIBUTE attrs_key_common[] = { + {CKA_APPLICATION, NULL, 0}, + {CKA_LABEL, NULL, 0} + }; + char *attrs_application = NULL; + char *attrs_label = NULL; + + if ( + _pkcs11h_getObjectAttributes ( + session, + objects[i], + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ) == CKR_OK && + _pkcs11h_malloc ( + (void *)&attrs_application, + attrs_key_common[0].ulValueLen+1 + ) == CKR_OK && + _pkcs11h_malloc ( + (void *)&attrs_label, + attrs_key_common[1].ulValueLen+1 + ) == CKR_OK + ) { + memset (attrs_application, 0, attrs_key_common[0].ulValueLen+1); + memmove (attrs_application, attrs_key_common[0].pValue, attrs_key_common[0].ulValueLen); + memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1); + memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen); + } + + my_output ( + pData, + ( + "Object\n" + "\tType:\t\t\tData\n" + "\tCKA_APPLICATION\t\t%s\n" + "\tCKA_LABEL:\t\t%s\n" + ), + attrs_application, + attrs_label + ); + + _pkcs11h_free ((void *)&attrs_application); + _pkcs11h_free ((void *)&attrs_label); + + _pkcs11h_freeObjectAttributes ( + attrs_key_common, + sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE) + ); + } + else { + my_output ( + pData, + ( + "Object\n" + "\tType:\t\t\tUnsupported\n" + ) + ); } - - pkcs11h_provider->f->C_FindObjectsFinal (session); - pkcs11h_provider->f->C_Logout (session); - pkcs11h_provider->f->C_CloseSession (session); } + + _pkcs11h_freeObjectAttributes ( + attrs, + sizeof (attrs) / sizeof (CK_ATTRIBUTE) + ); + + /* + * Ignore any error and + * perform next iteration + */ + rv = CKR_OK; } + + if (objects != NULL) { + _pkcs11h_free ((void *)&objects); + } + + /* + * Ignore this error + */ + rv = CKR_OK; + } + + if (session != NULL) { + _pkcs11h_releaseSession (session); + session = NULL; + } + + if (token_id != NULL) { + pkcs11h_freeTokenId (token_id); + token_id = NULL; } pkcs11h_terminate (); } +#endif /* ENABLE_PKCS11H_STANDALONE */ + #ifdef BROKEN_OPENSSL_ENGINE static void broken_openssl_init() __attribute__ ((constructor)); static void broken_openssl_init() @@ -3713,4 +9890,5 @@ static void broken_openssl_init() #else static void dummy (void) {} -#endif /* PKCS11_HELPER_ENABLE */ +#endif /* PKCS11H_HELPER_ENABLE */ + diff --git a/pkcs11-helper.h b/pkcs11-helper.h index df3db66..27289c4 100644 --- a/pkcs11-helper.h +++ b/pkcs11-helper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Alon Bar-Lev + * Copyright (c) 2005-2006 Alon Bar-Lev * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifi- @@ -34,225 +34,895 @@ * */ -#ifndef __PKCS11_HELPER_H -#define __PKCS11_HELPER_H +#ifndef __PKCS11H_HELPER_H +#define __PKCS11H_HELPER_H + +#if defined(__cplusplus) +extern "C" { +#endif #include "pkcs11-helper-config.h" -#define PKCS11H_MAX_ATTRIBUTE_SIZE (10*1024) +#if defined(ENABLE_PKCS11H_SLOTEVENT) && !defined(ENABLE_PKCS11H_THREADING) +#error PKCS#11: ENABLE_PKCS11H_SLOTEVENT requires ENABLE_PKCS11H_THREADING +#endif +#if defined(ENABLE_PKCS11H_OPENSSL) && !defined(ENABLE_PKCS11H_CERTIFICATE) +#error PKCS#11: ENABLE_PKCS11H_OPENSSL requires ENABLE_PKCS11H_CERTIFICATE +#endif + +#define PKCS11H_LOG_DEBUG2 5 +#define PKCS11H_LOG_DEBUG1 4 +#define PKCS11H_LOG_INFO 3 +#define PKCS11H_LOG_WARN 2 +#define PKCS11H_LOG_ERROR 1 +#define PKCS11H_LOG_QUITE 0 + #define PKCS11H_PIN_CACHE_INFINITE -1 +#define PKCS11H_SIGNMODE_MASK_SIGN (1<<0) +#define PKCS11H_SIGNMODE_MASK_RECOVER (1<<1) + +#define PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT (1<<0) +#define PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT (1<<1) + +#define PKCS11H_SLOTEVENT_METHOD_AUTO 0 +#define PKCS11H_SLOTEVENT_METHOD_TRIGGER 1 +#define PKCS11H_SLOTEVENT_METHOD_POLL 2 + +#define PKCS11H_ENUM_METHOD_CACHE 0 +#define PKCS11H_ENUM_METHOD_CACHE_EXIST 1 +#define PKCS11H_ENUM_METHOD_RELOAD 2 + typedef void (*pkcs11h_output_print_t)( IN const void *pData, IN const char * const szFormat, IN ... +) +#ifdef __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + ; + +struct pkcs11h_token_id_s; +typedef struct pkcs11h_token_id_s *pkcs11h_token_id_t; + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +struct pkcs11h_certificate_id_s; +struct pkcs11h_certificate_s; +typedef struct pkcs11h_certificate_id_s *pkcs11h_certificate_id_t; +typedef struct pkcs11h_certificate_s *pkcs11h_certificate_t; + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#if defined(ENABLE_PKCS11H_ENUM) + +struct pkcs11h_token_id_list_s; +typedef struct pkcs11h_token_id_list_s *pkcs11h_token_id_list_t; + +#if defined(ENABLE_PKCS11H_DATA) + +struct pkcs11h_data_id_list_s; +typedef struct pkcs11h_data_id_list_s *pkcs11h_data_id_list_t; + +#endif /* ENABLE_PKCS11H_DATA */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +struct pkcs11h_certificate_id_list_s; +typedef struct pkcs11h_certificate_id_list_s *pkcs11h_certificate_id_list_t; + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#endif /* ENABLE_PKCS11H_ENUM */ + +typedef void (*pkcs11h_hook_log_t)( + IN const void *pData, + IN const unsigned flags, + IN const char * const szFormat, + IN va_list args ); -typedef bool (*pkcs11h_hook_card_prompt_t)( +typedef void (*pkcs11h_hook_slotevent_t)( + IN const void *pData +); + +typedef PKCS11H_BOOL (*pkcs11h_hook_token_prompt_t)( IN const void *pData, - IN const char * const szLabel + IN const pkcs11h_token_id_t token ); -typedef bool (*pkcs11h_hook_pin_prompt_t)( +typedef PKCS11H_BOOL (*pkcs11h_hook_pin_prompt_t)( IN const void *pData, - IN const char * const szLabel, + IN const pkcs11h_token_id_t token, OUT char * const szPIN, IN const size_t nMaxPIN ); +struct pkcs11h_token_id_s { + char label[1024]; + char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1]; + char model[sizeof (((CK_TOKEN_INFO *)NULL)->model)+1]; + char serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)+1]; +}; + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +struct pkcs11h_certificate_id_s { + pkcs11h_token_id_t token_id; -typedef struct pkcs11h_hooks_s { - void *card_prompt_data; - void *pin_prompt_data; - pkcs11h_hook_card_prompt_t card_prompt; - pkcs11h_hook_pin_prompt_t pin_prompt; -} *pkcs11h_hooks_t; + char displayName[1024]; + CK_BYTE_PTR attrCKA_ID; + size_t attrCKA_ID_size; -typedef struct pkcs11h_provider_s { - struct pkcs11h_provider_s *next; + unsigned char *certificate_blob; + size_t certificate_blob_size; +}; - bool fEnabled; - char *szName; - -#if defined(WIN32) - HANDLE hLibrary; -#else - void *hLibrary; #endif - CK_FUNCTION_LIST_PTR f; - bool fShouldFinalize; - char *szSignMode; -} *pkcs11h_provider_t; +#if defined(ENABLE_PKCS11H_ENUM) -typedef struct pkcs11h_session_s { - struct pkcs11h_session_s *next; +struct pkcs11h_token_id_list_s { + pkcs11h_token_id_list_t next; + pkcs11h_token_id_t token_id; +}; - int nReferenceCount; - bool fValid; +#if defined(ENABLE_PKCS11H_DATA) - pkcs11h_provider_t provider; +struct pkcs11h_data_id_list_s { + pkcs11h_data_id_list_t next; - bool fProtectedAuthentication; + char *application; + char *label; +}; - char szLabel[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1]; - CK_CHAR serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)]; +#endif /* ENABLE_PKCS11H_DATA */ - CK_SESSION_HANDLE hSession; +#if defined(ENABLE_PKCS11H_CERTIFICATE) - int nPINCachePeriod; - time_t timePINExpire; -} *pkcs11h_session_t; +struct pkcs11h_certificate_id_list_s { + pkcs11h_certificate_id_list_t next; + pkcs11h_certificate_id_t certificate_id; +}; -typedef struct pkcs11h_certificate_s { +#endif /* ENABLE_PKCS11H_CERTIFICATE */ - pkcs11h_session_t session; +#endif /* ENABLE_PKCS11H_CERTIFICATE */ - unsigned char *certificate; - size_t certificate_size; - unsigned char *certificate_id; - size_t certificate_id_size; +#if defined(ENABLE_PKCS11H_OPENSSL) - enum { - pkcs11h_signmode_none = 0, - pkcs11h_signmode_sign, - pkcs11h_signmode_recover - } signmode; +struct pkcs11h_openssl_session_s; +typedef struct pkcs11h_openssl_session_s *pkcs11h_openssl_session_t; - CK_OBJECT_HANDLE hKey; +#endif /* ENABLE_PKCS11H_OPENSSL */ - bool fCertPrivate; -} *pkcs11h_certificate_t; +/* + * pkcs11h_getMessage - Get message by return value. + * + * Parameters: + * rv - Return value. + */ +char * +pkcs11h_getMessage ( + IN const int rv +); -typedef struct pkcs11h_data_s { - bool fInitialized; - int nPINCachePeriod; +/* + * pkcs11h_initialize - Inititalize helper interface. + * + * Must be called once, from main thread. + * Defaults: + * Protected authentication enabled. + * PIN cached is infinite. + */ +CK_RV +pkcs11h_initialize (); - pkcs11h_provider_t providers; - pkcs11h_session_t sessions; - pkcs11h_hooks_t hooks; +/* + * pkcs11h_terminate - Terminate helper interface. + * + * Must be called once, from main thread, after all + * related resources freed. + */ +CK_RV +pkcs11h_terminate (); - CK_SESSION_HANDLE session; -} *pkcs11h_data_t; +/* + * pkcs11h_setLogLevel - Set current log level of the helper. + * + * Parameters: + * flags - current log level. + * + * The log level can be set to maximum, but setting it to lower + * level will improve performance. + */ +void +pkcs11h_setLogLevel ( + IN const unsigned flags +); -typedef struct pkcs11h_openssl_session_s { - int nReferenceCount; - bool fInitialized; - X509 *x509; - RSA_METHOD smart_rsa; - int (*orig_finish)(RSA *rsa); - pkcs11h_certificate_t certificate; -} *pkcs11h_openssl_session_t; +/* + * pkcs11h_getLogLevel - Get current log level. + */ +unsigned +pkcs11h_getLogLevel (); +/* + * pkcs11h_setLogHook - Set a log callback. + * + * Parameters: + * hook - Callback. + * pData - Data to send to callback. + */ CK_RV -pkcs11h_initialize (); +pkcs11h_setLogHook ( + IN const pkcs11h_hook_log_t hook, + IN void * const pData +); +/* + * pkcs11h_setSlotEventHook - Set a slot event callback. + * + * Parameters: + * hook - Callback. + * pData - Data to send to callback. + * + * Calling this function initialize slot event notifications, these + * notifications can be started, but never terminate due to PKCS#11 limitation. + * + * In order to use slot events you must have threading enabled. + */ CK_RV -pkcs11h_terminate (); +pkcs11h_setSlotEventHook ( + IN const pkcs11h_hook_slotevent_t hook, + IN void * const pData +); +/* + * pkcs11h_setTokenPromptHook - Set a token prompt callback. + * + * Parameters: + * hook - Callback. + * pData - Data to send to callback. + */ CK_RV -pkcs11h_setCardPromptHook ( - IN const pkcs11h_hook_card_prompt_t hook, +pkcs11h_setTokenPromptHook ( + IN const pkcs11h_hook_token_prompt_t hook, IN void * const pData ); +/* + * pkcs11h_setPINPromptHook - Set a pin prompt callback. + * + * Parameters: + * hook - Callback. + * pData - Data to send to callback. + */ CK_RV pkcs11h_setPINPromptHook ( IN const pkcs11h_hook_pin_prompt_t hook, IN void * const pData ); +/* + * pkcs11h_setProtectedAuthentication - Set global protected authentication mode. + * + * Parameters: + * fProtectedAuthentication - Allow protected authentication if enabled by token. + */ +CK_RV +pkcs11h_setProtectedAuthentication ( + IN const PKCS11H_BOOL fProtectedAuthentication +); + +/* + * pkcs11h_setPINCachePeriod - Set global PIN cache timeout. + * + * Parameters: + * nPINCachePeriod - Cache period in seconds, or PKCS11H_PIN_CACHE_INFINITE. + */ CK_RV pkcs11h_setPINCachePeriod ( IN const int nPINCachePeriod ); +/* + * pkcs11h_setMaxLoginRetries - Set global login retries attempts. + * + * Parameters: + * nMaxLoginRetries - Login retries handled by the helper. + */ +CK_RV +pkcs11h_setMaxLoginRetries ( + IN const int nMaxLoginRetries +); + +/* + * pkcs11h_addProvider - Add a PKCS#11 provider. + * + * Parameters: + * szReferenceName - Reference name for this provider. + * szProvider - Provider library location. + * fProtectedAuthentication - Allow this provider to use protected authentication. + * maskSignMode - Provider signmode override. + * nSlotEventMethod - Provider slot event method. + * nSlotEventPollInterval - Slot event poll interval (If in polling mode). + * fCertIsPrivate - Provider's certificate access should be done after login. + * + * This function must be called from the main thread. + * + * The global fProtectedAuthentication must be enabled in order to allow provider specific. + * The maskSignMode can be 0 in order to automatically detect key sign mode. + */ CK_RV pkcs11h_addProvider ( + IN const char * const szReferenceName, IN const char * const szProvider, - IN const char * const szSignMode + IN const PKCS11H_BOOL fProtectedAuthentication, + IN const unsigned maskSignMode, + IN const int nSlotEventMethod, + IN const int nSlotEventPollInterval, + IN const PKCS11H_BOOL fCertIsPrivate ); +/* + * pkcs11h_delProvider - Delete a PKCS#11 provider. + * + * Parameters: + * szReferenceName - Reference name for this provider. + * + * This function must be called from the main thread. + */ +CK_RV +pkcs11h_removeProvider ( + IN const char * const szReferenceName +); + +/* + * pkcs11h_forkFixup - Handle special case of Unix fork() + * + * This function should be called after fork is called. This is required + * due to a limitation of the PKCS#11 standard. + * + * This function must be called from the main thread. + * + * The helper library handles fork automatically if ENABLE_PKCS11H_THREADING + * is set on configuration file, by use of pthread_atfork. + */ CK_RV pkcs11h_forkFixup (); +/* + * pkcs11h_plugAndPlay - Handle slot rescan. + * + * This function must be called from the main thread. + * + * PKCS#11 providers do not allow plug&play, plug&play can be established by + * finalizing all providers and initializing them again. + * + * The cost of this process is invalidating all sessions, and require user + * login at the next access. + */ CK_RV -pkcs11h_createCertificateSession ( - IN const char * const szSlotType, - IN const char * const szSlot, - IN const char * const szIdType, - IN const char * const szId, - IN const bool fProtectedAuthentication, - IN const bool fCertPrivate, +pkcs11h_plugAndPlay (); + +/* + * pkcs11h_freeTokenId - Free token_id object. + */ +CK_RV +pkcs11h_freeTokenId ( + IN pkcs11h_token_id_t certificate_id +); + +/* + * pkcs11h_duplicateTokenId - Duplicate token_id object. + */ +CK_RV +pkcs11h_duplicateTokenId ( + OUT pkcs11h_token_id_t * const to, + IN const pkcs11h_token_id_t from +); + +/* + * pkcs11h_sameTokenId - Returns TRUE if same token id + */ +PKCS11H_BOOL +pkcs11h_sameTokenId ( + IN const pkcs11h_token_id_t a, + IN const pkcs11h_token_id_t b +); + +#if defined(ENABLE_PKCS11H_TOKEN) + +/* + * pkcs11h_token_ensureAccess - Ensure token is accessible. + * + * Parameters: + * token_id - Token id object. + * maskPrompt - Allow prompt. + */ +CK_RV +pkcs11h_token_ensureAccess ( + IN const pkcs11h_token_id_t token_id, + IN const unsigned maskPrompt +); + +#endif /* ENABLE_PKCS11H_TOKEN */ + +#if defined(ENABLE_PKCS11H_DATA) + +CK_RV +pkcs11h_data_get ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel, + OUT char * const blob, + IN OUT size_t * const p_blob_size +); + +CK_RV +pkcs11h_data_put ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel, + OUT char * const blob, + IN const size_t blob_size +); + +CK_RV +pkcs11h_data_del ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + IN const char * const szApplication, + IN const char * const szLabel +); + +#endif /* ENABLE_PKCS11H_DATA */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) +/*======================================================================* + * CERTIFICATE INTERFACE + *======================================================================*/ + +/* + * pkcs11h_freeCertificateId - Free certificate_id object. + */ +CK_RV +pkcs11h_freeCertificateId ( + IN pkcs11h_certificate_id_t certificate_id +); + +/* + * pkcs11h_duplicateCertificateId - Duplicate certificate_id object. + */ +CK_RV +pkcs11h_duplicateCertificateId ( + OUT pkcs11h_certificate_id_t * const to, + IN const pkcs11h_certificate_id_t from +); + +/* + * pkcs11h_freeCertificate - Free certificate object. + */ +CK_RV +pkcs11h_freeCertificate ( + IN pkcs11h_certificate_t certificate +); + +/* + * pkcs11h_certificate_create - Create a certificate object out of certificate_id. + * + * Parameters: + * certificate_id - Certificate id object to be based on. + * nPINCachePeriod - Session specific cache period. + * p_certificate - Receives certificate object. + * + * The certificate id object may not specify the full certificate. + * The certificate object must be freed by caller. + */ +CK_RV +pkcs11h_certificate_create ( + IN const pkcs11h_certificate_id_t certificate_id, IN const int nPINCachePeriod, - OUT pkcs11h_certificate_t * const pkcs11h_certificate + OUT pkcs11h_certificate_t * const p_certificate +); + +/* + * pkcs11h_certificate_getCertificateId - Get certifiate id object out of a certifiate + * + * Parameters: + * certificate - Certificate object. + * p_certificate_id - Certificate id object pointer. + * + * The certificate id must be freed by caller. + */ +CK_RV +pkcs11h_certificate_getCertificateId ( + IN const pkcs11h_certificate_t certificate, + OUT pkcs11h_certificate_id_t * const p_certificate_id +); + +/* + * pkcs11h_certificate_getCertificateBlob - Get the certificate blob out of the certificate object. + * + * ParametersL + * certificate - Certificate object. + * certificate_blob - Buffer. + * certificate_blob_size - Buffer size. + * + * Buffer may be NULL in order to get size. + */ +CK_RV +pkcs11h_certificate_getCertificateBlob ( + IN const pkcs11h_certificate_t certificate, + OUT unsigned char * const certificate_blob, + IN OUT size_t * const p_certificate_blob_size ); +/* + * pkcs11h_certificate_ensureCertificateAccess - Ensure certificate is accessible. + * + * Parameters: + * certificate - Certificate object. + * maskPrompt - Allow prompt. + */ CK_RV -pkcs11h_freeCertificateSession ( - IN const pkcs11h_certificate_t pkcs11h_certificate +pkcs11h_certificate_ensureCertificateAccess ( + IN const pkcs11h_certificate_t certificate, + IN const unsigned maskPrompt ); +/* + * pkcs11h_certificate_ensureKeyAccess - Ensure key is accessible. + * + * Parameters: + * certificate - Certificate object. + * maskPrompt - Allow prompt. + */ CK_RV -pkcs11h_sign ( - IN const pkcs11h_certificate_t pkcs11h_certificate, +pkcs11h_certificate_ensureKeyAccess ( + IN const pkcs11h_certificate_t certificate, + IN const unsigned maskPrompt +); + +/* + * pkcs11h_certificate_sign - Sign data. + * + * Parameters: + * certificate - Certificate object. + * mech_type - PKCS#11 mechanism. + * source - Buffer to sign. + * source_size - Buffer size. + * target - Target buffer, can be NULL to get size. + * target_size - Target buffer size. + */ +CK_RV +pkcs11h_certificate_sign ( + IN const pkcs11h_certificate_t certificate, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, IN const size_t source_size, OUT unsigned char * const target, - IN OUT size_t * const target_size + IN OUT size_t * const p_target_size ); +/* + * pkcs11h_certificate_signRecover - Sign data. + * + * Parameters: + * certificate - Certificate object. + * mech_type - PKCS#11 mechanism. + * source - Buffer to sign. + * source_size - Buffer size. + * target - Target buffer, can be NULL to get size. + * target_size - Target buffer size. + */ CK_RV -pkcs11h_signRecover ( - IN const pkcs11h_certificate_t pkcs11h_certificate, +pkcs11h_certificate_signRecover ( + IN const pkcs11h_certificate_t certificate, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, IN const size_t source_size, OUT unsigned char * const target, - IN OUT size_t * const target_size + IN OUT size_t * const p_target_size ); +/* + * pkcs11h_certificate_signAny - Sign data mechanism determined by key attributes. + * + * Parameters: + * certificate - Certificate object. + * mech_type - PKCS#11 mechanism. + * source - Buffer to sign. + * source_size - Buffer size. + * target - Target buffer, can be NULL to get size. + * target_size - Target buffer size. + */ CK_RV -pkcs11h_decrypt ( - IN const pkcs11h_certificate_t pkcs11h_certificate, +pkcs11h_certificate_signAny ( + IN const pkcs11h_certificate_t certificate, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, IN const size_t source_size, OUT unsigned char * const target, - IN OUT size_t * const target_size + IN OUT size_t * const p_target_size ); +/* + * pkcs11h_certificate_decrypt - Decrypt data. + * + * Parameters: + * certificate - Certificate object. + * mech_type - PKCS#11 mechanism. + * source - Buffer to sign. + * source_size - Buffer size. + * target - Target buffer, can be NULL to get size. + * target_size - Target buffer size. + */ CK_RV -pkcs11h_getCertificate ( - IN const pkcs11h_certificate_t pkcs11h_certificate, - OUT unsigned char * const certificate, - IN OUT size_t * const certificate_size +pkcs11h_certificate_decrypt ( + IN const pkcs11h_certificate_t certificate, + IN const CK_MECHANISM_TYPE mech_type, + IN const unsigned char * const source, + IN const size_t source_size, + OUT unsigned char * const target, + IN OUT size_t * const p_target_size ); -char * -pkcs11h_getMessage ( - IN const int rv +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#if defined(ENABLE_PKCS11H_LOCATE) +/*======================================================================* + * LOCATE INTERFACE + *======================================================================*/ + +#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE) + +/* + * pkcs11h_locate_token - Locate token based on atributes. + * + * Parameters: + * szSlotType - How to locate slot. + * szSlot - Slot name. + * p_token_id - Token object. + * + * Slot: + * id - Slot number. + * name - Slot name. + * label - Available token label. + * + * Caller must free token id. + */ +CK_RV +pkcs11h_locate_token ( + IN const char * const szSlotType, + IN const char * const szSlot, + OUT pkcs11h_token_id_t * const p_token_id ); +#endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +/* + * pkcs11h_locate_certificate - Locate certificate based on atributes. + * + * Parameters: + * szSlotType - How to locate slot. + * szSlot - Slot name. + * szIdType - How to locate object. + * szId - Object name. + * p_certificate_id - Certificate object. + * + * Slot: + * Same as pkcs11h_locate_token. + * + * Object: + * id - Certificate CKA_ID (hex string) (Fastest). + * label - Certificate CKA_LABEL (string). + * subject - Certificate subject (OpenSSL DN). + * + * Caller must free certificate id. + */ +CK_RV +pkcs11h_locate_certificate ( + IN const char * const szSlotType, + IN const char * const szSlot, + IN const char * const szIdType, + IN const char * const szId, + OUT pkcs11h_certificate_id_t * const p_certificate_id +); + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#endif /* ENABLE_PKCS11H_LOCATE */ + +#if defined(ENABLE_PKCS11H_ENUM) +/*======================================================================* + * ENUM INTERFACE + *======================================================================*/ + +#if defined(ENABLE_PKCS11H_TOKEN) + +/* + * pkcs11h_freeCertificateIdList - Free certificate_id list. + */ +CK_RV +pkcs11h_freeTokenIdList ( + IN const pkcs11h_token_id_list_t token_id_list +); + +/* + * pkcs11h_enum_getTokenIds - Enumerate available tokens + * + * Parameters: + * p_token_id_list - A list of token ids. + * + * Caller must free the list. + */ +CK_RV +pkcs11h_enum_getTokenIds ( + IN const int method, + OUT pkcs11h_token_id_list_t * const p_token_id_list +); + +#endif /* ENABLE_PKCS11H_TOKEN */ + +#if defined(ENABLE_PKCS11H_DATA) + +CK_RV +pkcs11h_freeDataIdList ( + IN const pkcs11h_data_id_list_t data_id_list +); + +CK_RV +pkcs11h_enumDataObjects ( + IN const pkcs11h_token_id_t token_id, + IN const PKCS11H_BOOL fPublic, + OUT pkcs11h_data_id_list_t * const p_data_id_list +); + +#endif /* ENABLE_PKCS11H_DATA */ + +#if defined(ENABLE_PKCS11H_CERTIFICATE) + +/* + * pkcs11h_freeCertificateIdList - Free certificate_id list. + */ +CK_RV +pkcs11h_freeCertificateIdList ( + IN const pkcs11h_certificate_id_list_t cert_id_list +); + +/* + * pkcs11h_enum_getTokenCertificateIds - Enumerate available certificates on specific token + * + * Parameters: + * token_id - Token id to enum. + * method - How to fetch certificates. + * p_cert_id_issuers_list - Receives issues list, can be NULL. + * p_cert_id_end_list - Receives end certificates list. + * + * This function will likely take long time. + * + * Method can be one of the following: + * PKCS11H_ENUM_METHOD_CACHE + * Return available certificates, even if token was once detected and + * was removed. + * PKCS11H_ENUM_METHOD_CACHE_EXIST + * Return available certificates for available tokens only, don't + * read the contents of the token if already read, even if this token + * removed and inserted. + * PKCS11H_ENUM_METHOD_RELOAD + * Clear all caches and then enum. + * + * Caller must free the lists. + */ +CK_RV +pkcs11h_enum_getTokenCertificateIds ( + IN const pkcs11h_token_id_t token_id, + IN const int method, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list +); + +/* + * pkcs11h_enum_getCertificateIds - Enumerate available certificates. + * + * Parameters: + * method - How to fetch certificates. + * p_cert_id_issuers_list - Receives issues list, can be NULL. + * p_cert_id_end_list - Receives end certificates list. + * + * This function will likely take long time. + * + * Method can be one of the following: + * PKCS11H_ENUM_METHOD_CACHE + * Return available certificates, even if token was once detected and + * was removed. + * PKCS11H_ENUM_METHOD_CACHE_EXIST + * Return available certificates for available tokens only, don't + * read the contents of the token if already read, even if this token + * removed and inserted. + * PKCS11H_ENUM_METHOD_RELOAD + * Clear all caches and then enum. + * + * Caller must free lists. + */ +CK_RV +pkcs11h_enum_getCertificateIds ( + IN const int method, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list, + OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list +); + +#endif /* ENABLE_PKCS11H_CERTIFICATE */ + +#endif /* ENABLE_PKCS11H_ENUM */ + +#if defined(ENABLE_PKCS11H_OPENSSL) +/*======================================================================* + * OPENSSL INTERFACE + *======================================================================*/ + +/* + * pkcs11h_openssl_createSession - Create OpenSSL session based on a certificate object. + * + * Parameters: + * certificate - Certificate object. + * + * The certificate object will be freed by the OpenSSL interface on session end. + */ pkcs11h_openssl_session_t -pkcs11h_openssl_createSession (); +pkcs11h_openssl_createSession ( + IN const pkcs11h_certificate_t certificate +); +/* + * pkcs11h_openssl_freeSession - Free OpenSSL session. + * + * Parameters: + * openssl_session - Session to free. + * + * The openssl_session object has a reference count just like other OpenSSL objects. + */ void pkcs11h_openssl_freeSession ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ); +/* + * pkcs11h_openssl_getRSA - Returns an RSA object out of the openssl_session object. + * + * Parameters: + * openssl_session - Session. + */ RSA * pkcs11h_openssl_getRSA ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ); +/* + * pkcs11h_openssl_getX509 - Returns an X509 object out of the openssl_session object. + * + * Parameters: + * openssl_session - Session. + */ X509 * pkcs11h_openssl_getX509 ( - IN const pkcs11h_openssl_session_t pkcs11h_openssl_session + IN const pkcs11h_openssl_session_t openssl_session ); +#endif /* ENABLE_PKCS11H_OPENSSL */ + +#if defined(ENABLE_PKCS11H_STANDALONE) +/*======================================================================* + * STANDALONE INTERFACE + *======================================================================*/ + void pkcs11h_standalone_dump_slots ( IN const pkcs11h_output_print_t my_output, @@ -269,4 +939,10 @@ pkcs11h_standalone_dump_objects ( IN const char * const pin ); +#endif /* ENABLE_PKCS11H_STANDALONE */ + +#ifdef __cplusplus +} #endif + +#endif /* __PKCS11H_HELPER_H */ diff --git a/pkcs11.c b/pkcs11.c index a8875cf..3b136c5 100644 --- a/pkcs11.c +++ b/pkcs11.c @@ -43,6 +43,74 @@ #include "pkcs11-helper.h" #include "pkcs11.h" +static +unsigned +_pkcs11_msg_pkcs112openvpn ( + IN const unsigned flags +) { + unsigned openvpn_flags; + + switch (flags) { + case PKCS11H_LOG_DEBUG2: + openvpn_flags = D_PKCS11_DEBUG; + break; + case PKCS11H_LOG_DEBUG1: + openvpn_flags = D_SHOW_PKCS11; + break; + case PKCS11H_LOG_INFO: + openvpn_flags = M_INFO; + break; + case PKCS11H_LOG_WARN: + openvpn_flags = M_WARN; + break; + case PKCS11H_LOG_ERROR: + openvpn_flags = M_FATAL; + break; + default: + openvpn_flags = M_FATAL; + break; + } + +#if defined(ENABLE_PKCS11_FORCE_DEBUG) + openvpn_flags=M_INFO; +#endif + + return openvpn_flags; +} + +static +unsigned +_pkcs11_msg_openvpn2pkcs11 ( + IN const unsigned flags +) { + unsigned pkcs11_flags; + + if ((flags & D_PKCS11_DEBUG) != 0) { + pkcs11_flags = PKCS11H_LOG_DEBUG2; + } + else if ((flags & D_SHOW_PKCS11) != 0) { + pkcs11_flags = PKCS11H_LOG_DEBUG1; + } + else if ((flags & M_INFO) != 0) { + pkcs11_flags = PKCS11H_LOG_INFO; + } + else if ((flags & M_WARN) != 0) { + pkcs11_flags = PKCS11H_LOG_WARN; + } + else if ((flags & M_FATAL) != 0) { + pkcs11_flags = PKCS11H_LOG_ERROR; + } + else { + pkcs11_flags = PKCS11H_LOG_ERROR; + } + +#if defined(ENABLE_PKCS11_FORCE_DEBUG) + pkcs11_flags = PKCS11H_LOG_DEBUG2; +#endif + + return pkcs11_flags; +} + static void _pkcs11_openvpn_print ( @@ -61,21 +129,47 @@ _pkcs11_openvpn_print ( msg (M_INFO|M_NOPREFIX|M_NOLF, "%s", Buffer); } +static +void +_pkcs11_openvpn_log ( + IN const void *pData, + IN unsigned flags, + IN const char * const szFormat, + IN va_list args +) { + char Buffer[10*1024]; + + vsnprintf (Buffer, sizeof (Buffer), szFormat, args); + Buffer[sizeof (Buffer)-1] = 0; + + msg (_pkcs11_msg_pkcs112openvpn (flags), "%s", Buffer); +} + static bool -_pkcs11_openvpn_card_prompt ( +_pkcs11_openvpn_token_prompt ( IN const void *pData, - IN const char * const szLabel + IN const pkcs11h_token_id_t token ) { static struct user_pass token_resp; - ASSERT (szLabel!=NULL); + ASSERT (token!=NULL); CLEAR (token_resp); token_resp.defined = false; token_resp.nocache = true; - openvpn_snprintf (token_resp.username, sizeof (token_resp.username), "Please insert %s token", szLabel); - get_user_pass (&token_resp, NULL, "token-insertion-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK); + openvpn_snprintf ( + token_resp.username, + sizeof (token_resp.username), + "Please insert %s token", + token->label + ); + get_user_pass ( + &token_resp, + NULL, + "token-insertion-request", + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK + ); return strcmp (token_resp.password, "ok") == 0; } @@ -84,16 +178,16 @@ static bool _pkcs11_openvpn_pin_prompt ( IN const void *pData, - IN const char * const szLabel, + IN const pkcs11h_token_id_t token, OUT char * const szPIN, IN const size_t nMaxPIN ) { static struct user_pass token_pass; char szPrompt[1024]; - ASSERT (szLabel!=NULL); + ASSERT (token!=NULL); - openvpn_snprintf (szPrompt, sizeof (szPrompt), "%s token", szLabel); + openvpn_snprintf (szPrompt, sizeof (szPrompt), "%s token", token->label); token_pass.defined = false; token_pass.nocache = true; @@ -111,12 +205,13 @@ _pkcs11_openvpn_pin_prompt ( bool pkcs11_initialize ( - const int nPINCachePeriod + IN const bool fProtectedAuthentication, + IN const int nPINCachePeriod ) { CK_RV rv = CKR_OK; - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_initialize - entered" ); @@ -124,32 +219,50 @@ pkcs11_initialize ( rv == CKR_OK && (rv = pkcs11h_initialize ()) != CKR_OK ) { - PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv)); + msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv)); } if ( rv == CKR_OK && - (rv = pkcs11h_setCardPromptHook (_pkcs11_openvpn_card_prompt, NULL)) != CKR_OK + (rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK ) { - PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); + } + + if (rv == CKR_OK) { + pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ())); + } + + if ( + rv == CKR_OK && + (rv = pkcs11h_setTokenPromptHook (_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK + ) { + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); } if ( rv == CKR_OK && (rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK ) { - PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); + } + + if ( + rv == CKR_OK && + (rv = pkcs11h_setProtectedAuthentication (fProtectedAuthentication)) != CKR_OK + ) { + msg (M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage (rv)); } if ( rv == CKR_OK && (rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK ) { - PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11h_getMessage (rv)); + msg (M_FATAL, "PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11h_getMessage (rv)); } - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_initialize - return %ld-'%s'", rv, pkcs11h_getMessage (rv) @@ -160,15 +273,15 @@ pkcs11_initialize ( void pkcs11_terminate () { - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_terminate - entered" ); pkcs11h_terminate (); - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_terminate - return" ); } @@ -181,32 +294,69 @@ pkcs11_forkFixup () { bool pkcs11_addProvider ( IN const char * const provider, - IN const char * const sign_mode + IN const bool fProtectedAuthentication, + IN const char * const sign_mode, + IN const bool fCertIsPrivate ) { + unsigned maskSignMode = 0; + CK_RV rv = CKR_OK; - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + ASSERT (provider!=NULL); + /*ASSERT (sign_mode!=NULL); NULL is default */ + + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_addProvider - entered - provider='%s', sign_mode='%s'", provider, sign_mode == NULL ? "default" : sign_mode ); - PKCS11LOG ( - PKCS11_LOG_INFO, + msg ( + M_INFO, "PKCS#11: Adding PKCS#11 provider '%s'", provider ); + if (rv == CKR_OK) { + if (sign_mode == NULL || !strcmp (sign_mode, "auto")) { + maskSignMode = 0; + } + else if (!strcmp (sign_mode, "sign")) { + maskSignMode = PKCS11H_SIGNMODE_MASK_SIGN; + } + else if (!strcmp (sign_mode, "recover")) { + maskSignMode = PKCS11H_SIGNMODE_MASK_RECOVER; + } + else if (!strcmp (sign_mode, "any")) { + maskSignMode = ( + PKCS11H_SIGNMODE_MASK_SIGN | + PKCS11H_SIGNMODE_MASK_RECOVER + ); + } + else { + msg (M_FATAL, "PKCS#11: Invalid sign mode '%s'", sign_mode); + rv = CKR_ARGUMENTS_BAD; + } + } + if ( rv == CKR_OK && - (rv = pkcs11h_addProvider (provider, sign_mode)) != CKR_OK + (rv = pkcs11h_addProvider ( + provider, + provider, + fProtectedAuthentication, + maskSignMode, + PKCS11H_SLOTEVENT_METHOD_AUTO, + 0, + fCertIsPrivate + )) != CKR_OK ) { - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv)); + msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv)); } - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) @@ -221,73 +371,94 @@ SSL_CTX_use_pkcs11 ( 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 bool pkcs11_protected_authentication, - IN const bool pkcs11_cert_private + IN const char * const pkcs11_id ) { X509 *x509 = NULL; RSA *rsa = NULL; - pkcs11h_openssl_session_t pkcs11h_openssl_session = NULL; + pkcs11h_certificate_id_t certificate_id = NULL; + pkcs11h_certificate_t certificate = NULL; + pkcs11h_openssl_session_t openssl_session = NULL; CK_RV rv = CKR_OK; bool fOK = true; - PKCS11LOG ( - PKCS11_LOG_DEBUG2, - "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", + ASSERT (ssl_ctx!=NULL); + ASSERT (pkcs11_slot_type!=NULL); + ASSERT (pkcs11_slot!=NULL); + ASSERT (pkcs11_id_type!=NULL); + ASSERT (pkcs11_id!=NULL); + + dmsg ( + 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'", (void *)ssl_ctx, pkcs11_slot_type, pkcs11_slot, pkcs11_id_type, - pkcs11_id, - pkcs11_protected_authentication ? 1 : 0 + pkcs11_id ); - PKCS11ASSERT (ssl_ctx!=NULL); - PKCS11ASSERT (pkcs11_slot_type!=NULL); - PKCS11ASSERT (pkcs11_slot!=NULL); - PKCS11ASSERT (pkcs11_id_type!=NULL); - PKCS11ASSERT (pkcs11_id!=NULL); + ASSERT (ssl_ctx!=NULL); + ASSERT (pkcs11_slot_type!=NULL); + ASSERT (pkcs11_slot!=NULL); + ASSERT (pkcs11_id_type!=NULL); + ASSERT (pkcs11_id!=NULL); if ( fOK && - (pkcs11h_openssl_session = pkcs11h_openssl_createSession ()) == NULL + (rv = pkcs11h_locate_certificate ( + pkcs11_slot_type, + pkcs11_slot, + pkcs11_id_type, + pkcs11_id, + &certificate_id + )) != CKR_OK ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot initialize openssh session"); + msg (M_WARN, "PKCS#11: Cannot set parameters %ld-'%s'", rv, pkcs11h_getMessage (rv)); } if ( fOK && - (rv = pkcs11h_createCertificateSession ( - pkcs11_slot_type, - pkcs11_slot, - pkcs11_id_type, - pkcs11_id, - pkcs11_protected_authentication, - pkcs11_cert_private, + (rv = pkcs11h_certificate_create ( + certificate_id, PKCS11H_PIN_CACHE_INFINITE, - &pkcs11h_openssl_session->certificate + &certificate )) != CKR_OK ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set parameters %ld-'%s'", rv, pkcs11h_getMessage (rv)); + msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); } if ( fOK && - (rsa = pkcs11h_openssl_getRSA (pkcs11h_openssl_session)) == NULL + (openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable get rsa object"); + msg (M_WARN, "PKCS#11: Cannot initialize openssl session"); + } + + if (fOK) { + /* + * Will be released by openssl_session + */ + certificate = NULL; } if ( fOK && - (x509 = pkcs11h_openssl_getX509 (pkcs11h_openssl_session)) == NULL + (rsa = pkcs11h_openssl_getRSA (openssl_session)) == NULL ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable get certificate object"); + msg (M_WARN, "PKCS#11: Unable get rsa object"); + } + + if ( + fOK && + (x509 = pkcs11h_openssl_getX509 (openssl_session)) == NULL + ) { + fOK = false; + msg (M_WARN, "PKCS#11: Unable get certificate object"); } if ( @@ -295,7 +466,7 @@ SSL_CTX_use_pkcs11 ( !SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa) ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set private key for openssl"); + msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); } if ( @@ -303,7 +474,7 @@ SSL_CTX_use_pkcs11 ( !SSL_CTX_use_certificate (ssl_ctx, x509) ) { fOK = false; - PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set certificate for openssl"); + msg (M_WARN, "PKCS#11: Cannot set certificate for openssl"); } /* @@ -320,14 +491,24 @@ SSL_CTX_use_pkcs11 ( RSA_free (rsa); rsa = NULL; } + + if (certificate != NULL) { + pkcs11h_freeCertificate (certificate); + certificate = NULL; + } + + if (certificate_id != NULL) { + pkcs11h_freeCertificateId (certificate_id); + certificate_id = NULL; + } - if (pkcs11h_openssl_session != NULL) { - pkcs11h_openssl_freeSession (pkcs11h_openssl_session); - pkcs11h_openssl_session = NULL; + if (openssl_session != NULL) { + pkcs11h_openssl_freeSession (openssl_session); + openssl_session = NULL; } - PKCS11LOG ( - PKCS11_LOG_DEBUG2, + dmsg ( + D_PKCS11_DEBUG, "PKCS#11: SSL_CTX_use_pkcs11 - return fOK=%d, rv=%ld", fOK ? 1 : 0, rv diff --git a/pkcs11.h b/pkcs11.h index 652647f..0e69d11 100644 --- a/pkcs11.h +++ b/pkcs11.h @@ -31,6 +31,7 @@ bool pkcs11_initialize ( + const bool fProtectedAuthentication, const int nPINCachePeriod ); @@ -43,7 +44,9 @@ pkcs11_forkFixup (); bool pkcs11_addProvider ( const char * const provider, - const char * const sign_mode + const bool fProtectedAuthentication, + const char * const sign_mode, + const bool fCertIsPrivate ); int @@ -52,9 +55,7 @@ SSL_CTX_use_pkcs11 ( const char * const pkcs11_slot_type, const char * const pkcs11_slot, const char * const pkcs11_id_type, - const char * const pkcs11_id, - const bool pkcs11_protected_authentication, - const bool pkcs11_cert_private + const char * const pkcs11_id ); void @@ -71,4 +72,4 @@ show_pkcs11_objects ( #endif /* ENABLE_PKCS11 */ -#endif /* OPENVPN_PKCS11_H */ +#endif /* OPENVPN_PKCS11H_H */ diff --git a/ssl.c b/ssl.c index 42fd904..2aa6e4a 100644 --- a/ssl.c +++ b/ssl.c @@ -1145,7 +1145,7 @@ init_ssl (const struct options *options) if (options->pkcs11_providers[0]) { /* Load Certificate and Private Key */ - if (!SSL_CTX_use_pkcs11 (ctx, options->pkcs11_slot_type, options->pkcs11_slot, options->pkcs11_id_type, options->pkcs11_id, options->pkcs11_protected_authentication, options->pkcs11_cert_private)) + if (!SSL_CTX_use_pkcs11 (ctx, options->pkcs11_slot_type, options->pkcs11_slot, options->pkcs11_id_type, options->pkcs11_id)) msg (M_SSLERR, "Cannot load certificate \"%s:%s\" from slot \"%s:%s\" using PKCS#11 interface", options->pkcs11_id_type, options->pkcs11_id, options->pkcs11_slot_type, options->pkcs11_slot); } -- cgit v1.2.3