diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-10-17 07:39:41 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-10-17 07:39:41 +0000 |
commit | 6835555ef8ede3ac0997a0fe8365aa95391b32a3 (patch) | |
tree | c89421dd8a4f17615ad5936a11ae6e9903bc0d55 | |
parent | VERSION 2.1_beta4 (re-released) (diff) | |
download | openvpn-6835555ef8ede3ac0997a0fe8365aa95391b32a3.tar.xz |
Brought up-to-date with Alon's PKCS11 patch at
https://svn.openvpn.net/projects/openvpn/contrib/alon/BETA21/openvpn@645
Pre-2.1_beta5
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@648 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to '')
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | init.c | 12 | ||||
-rw-r--r-- | options.c | 254 | ||||
-rw-r--r-- | options.h | 1 | ||||
-rw-r--r-- | pkcs11.c | 1402 | ||||
-rw-r--r-- | pkcs11.h | 31 | ||||
-rw-r--r-- | ssl.c | 11 |
8 files changed, 1147 insertions, 570 deletions
@@ -3,6 +3,10 @@ Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net> $Id$ +2005.10.xx -- Version 2.1-beta5 + +* More PKCS#11 additions/changes (Alon Bar-Lev). + 2005.10.17 -- Version 2.1-beta4 * Fixed bug introduced in 2.1-beta3 where management diff --git a/configure.ac b/configure.ac index 9befab2..2fed39b 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT([OpenVPN], [2.1_beta4], [openvpn-users@lists.sourceforge.net], [openvpn]) +AC_INIT([OpenVPN], [2.1_beta5], [openvpn-users@lists.sourceforge.net], [openvpn]) AM_CONFIG_HEADER(config.h) AC_CONFIG_SRCDIR(syshead.h) @@ -111,15 +111,16 @@ context_init_1 (struct context *c) /* Certificate password input */ if (c->options.key_pass_file) pem_password_setup (c->options.key_pass_file); +#endif #if defined(ENABLE_PKCS11) { int i; + init_pkcs11 (c->options.pkcs11_pin_cache_period); for (i=0;i<MAX_PARMS && c->options.pkcs11_providers[i] != NULL;i++) add_pkcs11 (c->options.pkcs11_providers[i], c->options.pkcs11_sign_mode[i]); } #endif -#endif #if P2MP /* Auth user/pass input */ @@ -232,13 +233,11 @@ uninit_static (void) #ifdef USE_CRYPTO free_ssl_lib (); +#endif -#ifdef USE_SSL #ifdef ENABLE_PKCS11 free_pkcs11 (); #endif -#endif -#endif #if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(USE_CRYPTO) && defined(USE_SSL) show_tls_performance_stats (); @@ -375,6 +374,11 @@ possibly_become_daemon (const struct options *options, const bool first_time) msg (M_ERR, "daemon() failed"); if (options->log) set_std_files_to_null (true); + +#if defined(ENABLE_PKCS11) + fork_fix_pkcs11 (); +#endif + ret = true; } return ret; @@ -425,24 +425,6 @@ static const char usage_message[] = "--key file : Local private key in .pem format.\n" "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" " and optionally the root CA certificate.\n" -#ifdef ENABLE_PKCS11 - "--pkcs11-providers provider ... : PKCS#11 provider to load.\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" - "--pkcs11-slot-type method : Slot locate method:\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" - "--pkcs11-id-type method : Certificate and key locate method:\n" - " id : By the object id (hex format).\n" - " label : By the object label (string).\n" - " subject : By certificate subject (String).\n" - "--pkcs11-id name : The object name.\n" - "--pkcs11-protected-authentication : Use PKCS#11 protected authentication path.\n" -#endif #ifdef WIN32 "--cryptoapicert select-string : Load the certificate and private key from the\n" " Windows Certificate System Store.\n" @@ -479,7 +461,29 @@ static const char usage_message[] = "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" " nsCertType designation t = 'client' | 'server'.\n" #endif /* USE_SSL */ +#ifdef ENABLE_PKCS11 "\n" + "PKCS#11 Options:\n" + "--pkcs11-providers provider ... : PKCS#11 provider to load.\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" + "--pkcs11-slot-type method : Slot locate method:\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" + "--pkcs11-id-type method : Certificate and key locate method:\n" + " id : By the object id (hex format).\n" + " 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" +#endif /* ENABLE_PKCS11 */ + "\n" "SSL Library information:\n" "--show-ciphers : Show cipher algorithms to use with --cipher option.\n" "--show-digests : Show message digest algorithms to use with --auth option.\n" @@ -554,14 +558,12 @@ static const char usage_message[] = "--dev tunX|tapX : tun/tap device\n" "--dev-type dt : Device type. See tunnel options above for details.\n" #endif -#ifdef USE_SSL #ifdef ENABLE_PKCS11 "\n" - "PKCS#11 specific:\n" + "PKCS#11 standalone options:\n" "--show-pkcs11-slots provider : Show PKCS#11 provider available slots.\n" "--show-pkcs11-objects provider slot : Show PKCS#11 token objects.\n" -#endif -#endif +#endif /* ENABLE_PKCS11 */ ; #endif /* !ENABLE_SMALL */ @@ -646,11 +648,12 @@ init_options (struct options *o) o->renegotiate_seconds = 3600; o->handshake_window = 60; o->transition_window = 3600; -#ifdef ENABLE_PKCS11 - o->pkcs11_protected_authentication = false; -#endif #endif #endif +#ifdef ENABLE_PKCS11 + o->pkcs11_pin_cache_period = -1; + o->pkcs11_protected_authentication = false; +#endif /* ENABLE_PKCS11 */ } void @@ -1178,23 +1181,6 @@ show_settings (const struct options *o) SHOW_STR (cert_file); SHOW_STR (priv_key_file); SHOW_STR (pkcs12_file); -#ifdef ENABLE_PKCS11 - { - int i; - for (i=0;i<MAX_PARMS && o->pkcs11_providers[i] != NULL;i++) - SHOW_PARM (pkcs11_providers, o->pkcs11_providers[i], "%s"); - } - { - int i; - for (i=0;i<MAX_PARMS && o->pkcs11_sign_mode[i] != NULL;i++) - SHOW_PARM (pkcs11_sign_mode, o->pkcs11_sign_mode[i], "%s"); - } - SHOW_STR (pkcs11_slot_type); - SHOW_STR (pkcs11_slot); - SHOW_STR (pkcs11_id_type); - SHOW_STR (pkcs11_id); - SHOW_BOOL (pkcs11_protected_authentication); -#endif #ifdef WIN32 SHOW_STR (cryptoapi_cert); #endif @@ -1220,6 +1206,25 @@ show_settings (const struct options *o) #endif #endif +#ifdef ENABLE_PKCS11 + { + int i; + for (i=0;i<MAX_PARMS && o->pkcs11_providers[i] != NULL;i++) + SHOW_PARM (pkcs11_providers, o->pkcs11_providers[i], "%s"); + } + { + int i; + for (i=0;i<MAX_PARMS && o->pkcs11_sign_mode[i] != NULL;i++) + SHOW_PARM (pkcs11_sign_mode, o->pkcs11_sign_mode[i], "%s"); + } + 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); +#endif /* ENABLE_PKCS11 */ + #if P2MP show_p2mp_parms (o); #endif @@ -1702,11 +1707,6 @@ options_postprocess (struct options *options, bool first_time) notnull (options->pkcs11_id, "PKCS#11 id (--pkcs11-id)"); - if (options->pkcs11_protected_authentication && options->key_pass_file != NULL) - msg(M_USAGE, "Parameter --askpass cannot be used when --pkcs11-protected-authentication is also specified."); - if (!options->pkcs11_protected_authentication && options->key_pass_file == NULL) - msg (M_USAGE, "Please specify one of --askpass or --pkcs11-protected-autentication options."); - if (options->cert_file) msg(M_USAGE, "Parameter --cert cannot be used when --pkcs11-provider is also specified."); if (options->priv_key_file) @@ -4733,83 +4733,6 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->cert_file = p[1]; } -#ifdef ENABLE_PKCS11 - else if (streq (p[0], "show-pkcs11-slots") && p[1]) - { - char *module = p[i++]; - VERIFY_PERMISSION (OPT_P_GENERAL); - show_pkcs11_slots (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, module); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ - } - else if (streq (p[0], "show-pkcs11-objects") && p[1] && p[2]) - { - char *provider = p[i++]; - char *slot = p[i++]; - struct gc_arena gc = gc_new (); - struct buffer pass_prompt = alloc_buf_gc (128, &gc); - char pin[256]; - - VERIFY_PERMISSION (OPT_P_GENERAL); - - buf_printf (&pass_prompt, "PIN:"); - - if (!get_console_input (BSTR (&pass_prompt), false, pin, sizeof (pin))) - msg (M_FATAL, "Cannot read password from stdin"); - - gc_free (&gc); - - show_pkcs11_objects (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, provider, slot, pin); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ - } - else if (streq (p[0], "pkcs11-providers") && p[1]) - { - int j; - - VERIFY_PERMISSION (OPT_P_GENERAL); - - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j, ++i) - options->pkcs11_providers[j-1] = p[j]; - } - else if (streq (p[0], "pkcs11-sign-mode") && p[1]) - { - int j; - - VERIFY_PERMISSION (OPT_P_GENERAL); - - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j, ++i) - options->pkcs11_sign_mode[j-1] = p[j]; - } - else if (streq (p[0], "pkcs11-slot-type") && p[1]) - { - ++i; - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_slot_type = p[1]; - } - else if (streq (p[0], "pkcs11-slot") && p[1]) - { - ++i; - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_slot = p[1]; - } - else if (streq (p[0], "pkcs11-id-type") && p[1]) - { - ++i; - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_id_type = p[1]; - } - else if (streq (p[0], "pkcs11-id") && p[1]) - { - ++i; - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_id = p[1]; - } - else if (streq (p[0], "pkcs11-protected-authentication")) - { - ++i; - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_protected_authentication = true; - } -#endif #ifdef WIN32 else if (streq (p[0], "cryptoapicert") && p[1]) { @@ -4968,6 +4891,89 @@ add_option (struct options *options, } #endif /* USE_SSL */ #endif /* USE_CRYPTO */ +#ifdef ENABLE_PKCS11 + else if (streq (p[0], "show-pkcs11-slots") && p[1]) + { + char *module = p[i++]; + VERIFY_PERMISSION (OPT_P_GENERAL); + show_pkcs11_slots (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, module); + openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + } + else if (streq (p[0], "show-pkcs11-objects") && p[1] && p[2]) + { + char *provider = p[i++]; + char *slot = p[i++]; + struct gc_arena gc = gc_new (); + struct buffer pass_prompt = alloc_buf_gc (128, &gc); + char pin[256]; + + VERIFY_PERMISSION (OPT_P_GENERAL); + + buf_printf (&pass_prompt, "PIN:"); + + if (!get_console_input (BSTR (&pass_prompt), false, pin, sizeof (pin))) + msg (M_FATAL, "Cannot read password from stdin"); + + gc_free (&gc); + + show_pkcs11_objects (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, provider, slot, pin); + openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + } + else if (streq (p[0], "pkcs11-providers") && p[1]) + { + int j; + + VERIFY_PERMISSION (OPT_P_GENERAL); + + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j, ++i) + options->pkcs11_providers[j-1] = p[j]; + } + else if (streq (p[0], "pkcs11-sign-mode") && p[1]) + { + int j; + + VERIFY_PERMISSION (OPT_P_GENERAL); + + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j, ++i) + options->pkcs11_sign_mode[j-1] = p[j]; + } + else if (streq (p[0], "pkcs11-slot-type") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_slot_type = p[1]; + } + else if (streq (p[0], "pkcs11-slot") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_slot = p[1]; + } + else if (streq (p[0], "pkcs11-id-type") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_id_type = p[1]; + } + else if (streq (p[0], "pkcs11-id") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_id = p[1]; + } + else if (streq (p[0], "pkcs11-pin-cache") && p[1]) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_pin_cache_period = atoi (p[1]); + } + else if (streq (p[0], "pkcs11-protected-authentication")) + { + ++i; + VERIFY_PERMISSION (OPT_P_GENERAL); + options->pkcs11_protected_authentication = true; + } +#endif #ifdef TUNSETPERSIST else if (streq (p[0], "rmtun")) { @@ -385,6 +385,7 @@ struct options const char *pkcs11_slot; const char *pkcs11_id_type; const char *pkcs11_id; + int pkcs11_pin_cache_period; bool pkcs11_protected_authentication; #ifdef WIN32 const char *cryptoapi_cert; @@ -58,6 +58,12 @@ #include "pkcs11.h" /*=========================================== + * MACROS + */ + +#define snprintf openvpn_snprintf + +/*=========================================== * Constants */ @@ -78,6 +84,25 @@ * Types */ +typedef bool (*pkcs11_hook_card_prompt_t)( + IN const void *pData, + IN const char * const szLabel +); + +typedef bool (*pkcs11_hook_pin_prompt_t)( + IN const void *pData, + IN const char * const szLabel, + OUT char * const szPIN, + IN const size_t nMaxPIN +); + +typedef struct pkcs11_hooks_s { + void *card_prompt_data; + void *pin_prompt_data; + pkcs11_hook_card_prompt_t card_prompt; + pkcs11_hook_pin_prompt_t pin_prompt; +} *pkcs11_hooks_t; + typedef struct pkcs11_provider_s { struct pkcs11_provider_s *next; @@ -91,27 +116,39 @@ typedef struct pkcs11_provider_s { CK_FUNCTION_LIST_PTR f; bool fShouldFinalize; char *szSignMode; + } *pkcs11_provider_t; typedef struct pkcs11_session_s { pkcs11_provider_t provider; + bool fProtectedAuthentication; + + char szLabel[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1]; + CK_CHAR serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)]; + unsigned char *certificate; - int certificate_size; + size_t certificate_size; unsigned char *certificate_id; - int certificate_id_size; - - char *szPIN; - bool fLoginFailed; + size_t certificate_id_size; CK_SLOT_ID slot; bool fKeySignRecover; CK_SESSION_HANDLE session; CK_OBJECT_HANDLE key; + + time_t timePINExpire; } *pkcs11_session_t; +typedef struct pkcs11_data_s { + bool fInitialized; + int nPINCachePeriod; + pkcs11_provider_t providers; + pkcs11_hooks_t hooks; +} *pkcs11_data_t; + /*=========================================== * Low level prototypes */ @@ -121,14 +158,14 @@ void _fixupFixedString ( IN const char * const szSource, OUT char * const szTarget, /* MUST BE >= nLength+1 */ - IN const int nLength /* FIXED STRING LENGTH */ + IN const size_t nLength /* FIXED STRING LENGTH */ ); static void _hexToBinary ( IN const char * const szSource, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ); static CK_RV @@ -154,11 +191,21 @@ _pkcs11_getObjectById ( IN const pkcs11_session_t pkcs11_session, IN const CK_OBJECT_CLASS class, IN const unsigned char * const id, - IN const int id_size, + IN const size_t id_size, OUT CK_OBJECT_HANDLE * const handle ); static CK_RV +_pkcs11_setSessionTokenInfo ( + IN const pkcs11_session_t pkcs11_session +); +static +CK_RV +_pkcs11_resetSlot ( + IN const pkcs11_session_t pkcs11_session +); +static +CK_RV _pkcs11_loadCertificate ( IN const pkcs11_session_t pkcs11_session, IN const char * const szIdType, @@ -173,15 +220,66 @@ static bool _isBetterCertificate ( IN const unsigned char * const pCurrent, - IN const int nCurrentSize, + IN const size_t nCurrentSize, IN const unsigned char * const pNew, - IN const int nNewSize + IN const size_t nNewSize +); +static +CK_RV +_pkcs11_validateSession ( + IN const pkcs11_session_t pkcs11_session +); +static +CK_RV +_pkcs11_login ( + IN const pkcs11_session_t pkcs11_session +); +static +CK_RV +_pkcs11_logout ( + IN const pkcs11_session_t pkcs11_session ); /*========================================= * Simplified functions prototypes */ - +static +bool +_pkcs11_hooks_card_prompt_default ( + IN const void *pData, + IN const char * const szLabel +); +static +bool +_pkcs11_hooks_pin_prompt_default ( + IN const void *pData, + IN const char * const szLabel, + OUT char * const szPIN, + IN const size_t nMaxPIN +); +static +CK_RV +pkcs11_initialize (); +static +CK_RV +pkcs11_terminate (); +static +CK_RV +pkcs11_setCardPromptHook ( + IN const pkcs11_hook_card_prompt_t hook, + IN void * const pData +); +static +CK_RV +pkcs11_setPINPromptHook ( + IN const pkcs11_hook_pin_prompt_t hook, + IN void * const pData +); +static +CK_RV +pkcs11_setPINCachePeriod ( + IN const int nPINCachePeriod +); static CK_RV pkcs11_addProvider ( @@ -190,7 +288,7 @@ pkcs11_addProvider ( ); static CK_RV -pkcs11_finalize (); +pkcs11_forkFixup (); static CK_RV pkcs11_createSession ( @@ -198,7 +296,6 @@ pkcs11_createSession ( IN const char * const szSlot, IN const char * const szIdType, IN const char * const szId, - IN const char * const szPIN, IN const bool fProtectedAuthentication, OUT pkcs11_session_t * const pkcs11_session ); @@ -209,23 +306,13 @@ pkcs11_freeSession ( ); static CK_RV -pkcs11_login ( - IN const pkcs11_session_t pkcs11_session -); -static -CK_RV -pkcs11_logout ( - IN const pkcs11_session_t pkcs11_session -); -static -CK_RV pkcs11_sign ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ); static CK_RV @@ -233,9 +320,9 @@ pkcs11_signRecover ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ); static CK_RV @@ -243,16 +330,16 @@ pkcs11_decrypt ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ); static CK_RV pkcs11_getCertificate ( IN const pkcs11_session_t pkcs11_session, - OUT char * const certificate, - IN OUT int * const certificate_size + OUT unsigned char * const certificate, + IN OUT size_t * const certificate_size ); static char * @@ -264,7 +351,7 @@ pkcs11_getMessage ( * Static data */ -static pkcs11_provider_t pkcs11_provider = NULL; +static pkcs11_data_t pkcs11_data = NULL; /*========================================== * Internal utility functions @@ -275,7 +362,7 @@ void _fixupFixedString ( IN const char * const szSource, OUT char * const szTarget, /* MUST BE >= nLength+1 */ - IN const int nLength /* FIXED STRING LENGTH */ + IN const size_t nLength /* FIXED STRING LENGTH */ ) { char *p; @@ -297,9 +384,9 @@ void _hexToBinary ( IN const char * const szSource, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ) { - int target_max_size; + size_t target_max_size; const char *p; char buf[3] = {'\0', '\0', '\0'}; int i = 0; @@ -317,7 +404,7 @@ _hexToBinary ( buf[i%2] = *p; if ((i%2) == 1) { - int v; + unsigned v; sscanf (buf, "%x", &v); target[*target_size] = v & 0xff; (*target_size)++; @@ -333,9 +420,9 @@ static bool _isBetterCertificate ( IN const unsigned char * const pCurrent, - IN const int nCurrentSize, + IN const size_t nCurrentSize, IN const unsigned char * const pNew, - IN const int nNewSize + IN const size_t nNewSize ) { /* * This function compare the notBefore @@ -427,7 +514,7 @@ _pkcs11_getSlotById ( } for ( - i=0, provider=pkcs11_provider; + i=0, provider=pkcs11_data->providers; i < provider_number && provider != NULL; i++, provider = provider->next ); @@ -453,9 +540,6 @@ _pkcs11_getSlotByName ( IN const pkcs11_session_t pkcs11_session, IN const char * const szName ) { - CK_SLOT_ID slots[1024]; - CK_ULONG slotnum; - CK_SLOT_ID s; CK_RV rv; pkcs11_provider_t provider; @@ -465,13 +549,16 @@ _pkcs11_getSlotByName ( ASSERT (szName!=NULL); for ( - provider = pkcs11_provider; + provider = pkcs11_data->providers; ( provider != NULL && !fFound ); provider = provider->next ) { + CK_SLOT_ID slots[1024]; + CK_ULONG slotnum; + if (!provider->fEnabled) { continue; } @@ -484,6 +571,8 @@ _pkcs11_getSlotByName ( &slotnum )) == CKR_OK ) { + CK_SLOT_ID s; + for (s=0;!fFound && s<slotnum;s++) { CK_SLOT_INFO info; @@ -496,7 +585,7 @@ _pkcs11_getSlotByName ( char szCurrentName[sizeof (info.slotDescription)+1]; _fixupFixedString ( - info.slotDescription, + (char *)info.slotDescription, szCurrentName, sizeof (info.slotDescription) ); @@ -520,9 +609,6 @@ _pkcs11_getSlotByLabel ( IN const pkcs11_session_t pkcs11_session, IN const char * const szLabel ) { - CK_SLOT_ID slots[1024]; - CK_ULONG slotnum; - CK_SLOT_ID s; CK_RV rv; pkcs11_provider_t provider; @@ -532,13 +618,16 @@ _pkcs11_getSlotByLabel ( ASSERT (szLabel!=NULL); for ( - provider = pkcs11_provider; + provider = pkcs11_data->providers; ( provider != NULL && !fFound ); provider = provider->next ) { + CK_SLOT_ID slots[1024]; + CK_ULONG slotnum; + if (!provider->fEnabled) { continue; } @@ -551,6 +640,8 @@ _pkcs11_getSlotByLabel ( &slotnum )) == CKR_OK ) { + CK_SLOT_ID s; + for (s=0;!fFound && s<slotnum;s++) { CK_TOKEN_INFO info; @@ -563,7 +654,7 @@ _pkcs11_getSlotByLabel ( char szCurrentLabel[sizeof (info.label)+1]; _fixupFixedString ( - info.label, + (char *)info.label, szCurrentLabel, sizeof (info.label) ); @@ -583,16 +674,105 @@ _pkcs11_getSlotByLabel ( static CK_RV +_pkcs11_setSessionTokenInfo ( + IN const pkcs11_session_t pkcs11_session +) { + CK_TOKEN_INFO info; + CK_RV rv; + + ASSERT (pkcs11_session!=NULL); + + if ( + (rv = pkcs11_session->provider->f->C_GetTokenInfo ( + pkcs11_session->slot, + &info + )) == CKR_OK + ) { + _fixupFixedString ( + (char *)info.label, + pkcs11_session->szLabel, + sizeof (info.label) + ); + + memmove ( + pkcs11_session->serialNumber, + info.serialNumber, + sizeof (pkcs11_session->serialNumber) + ); + } + + return rv; +} + +static +CK_RV +_pkcs11_resetSlot ( + IN const pkcs11_session_t pkcs11_session +) { + CK_SLOT_ID slots[1024]; + CK_ULONG slotnum; + CK_RV rv; + bool fFound = false; + bool fCancel = false; + + ASSERT (pkcs11_session!=NULL); + + do { + slotnum = sizeof (slots) / sizeof (CK_SLOT_ID); + if ( + (rv = pkcs11_session->provider->f->C_GetSlotList ( + TRUE, + slots, + &slotnum + )) == CKR_OK + ) { + CK_SLOT_ID s; + + for (s=0;!fFound && s<slotnum;s++) { + CK_TOKEN_INFO info; + + if ( + (rv = pkcs11_session->provider->f->C_GetTokenInfo ( + slots[s], + &info + )) == CKR_OK + ) { + if ( + !memcmp ( + pkcs11_session->serialNumber, + info.serialNumber, + sizeof (pkcs11_session->serialNumber) + ) + ) { + pkcs11_session->slot = slots[s]; + fFound = true; + } + } + } + } + + if (!fFound) { + fCancel = !pkcs11_data->hooks->card_prompt ( + pkcs11_data->hooks->card_prompt_data, + pkcs11_session->szLabel + ); + } + } while (!fFound && !fCancel); + + return fFound ? CKR_OK : CKR_SLOT_ID_INVALID; +} + +static +CK_RV _pkcs11_getObjectById ( IN const pkcs11_session_t pkcs11_session, IN const CK_OBJECT_CLASS class, IN const unsigned char * const id, - IN const int id_size, + IN const size_t id_size, OUT CK_OBJECT_HANDLE * const handle ) { CK_ULONG count; - bool fFound = false; - CK_RV rv; + CK_RV rv = CKR_OK; CK_ATTRIBUTE filter[] = { {CKA_CLASS, (void *)&class, sizeof (class)}, @@ -603,34 +783,35 @@ _pkcs11_getObjectById ( ASSERT (id!=NULL); ASSERT (handle!=NULL); - if ( - (rv = pkcs11_session->provider->f->C_FindObjectsInit ( + if (rv == CKR_OK) { + rv = pkcs11_session->provider->f->C_FindObjectsInit ( pkcs11_session->session, filter, sizeof (filter) / sizeof (CK_ATTRIBUTE) - )) != CKR_OK - ) { - return rv; + ); } - if ( - (rv = pkcs11_session->provider->f->C_FindObjects ( + if (rv == CKR_OK) { + rv = pkcs11_session->provider->f->C_FindObjects ( pkcs11_session->session, handle, 1, &count - )) == CKR_OK + ); + } + + if ( + rv == CKR_OK && + count == 0 ) { - if (count > 0) { - fFound = true; - } + rv = CKR_FUNCTION_REJECTED; } pkcs11_session->provider->f->C_FindObjectsFinal ( pkcs11_session->session ); - return fFound ? CKR_OK : CKR_FUNCTION_REJECTED; + return rv; } static @@ -674,7 +855,7 @@ _pkcs11_loadCertificate ( ); } else if (!strcmp (szIdType, "id")) { - int s = sizeof (cert_filter_by); + size_t s = sizeof (cert_filter_by); cert_filter[1].type = CKA_ID; _hexToBinary ( @@ -876,11 +1057,303 @@ _pkcs11_loadKeyProperties ( return CKR_OK; } +static +CK_RV +_pkcs11_validateSession ( + IN const pkcs11_session_t pkcs11_session +) { + if ( + pkcs11_session->timePINExpire != (time_t)0 && + pkcs11_session->timePINExpire < time (NULL) + ) { + _pkcs11_logout (pkcs11_session); + } + return CKR_OK; +} + +static +CK_RV +_pkcs11_login ( + IN const pkcs11_session_t pkcs11_session +) { + CK_RV rv = CKR_OK; + + + ASSERT (pkcs11_session!=NULL); + + _pkcs11_logout (pkcs11_session); + + if (rv == CKR_OK) { + rv = _pkcs11_resetSlot (pkcs11_session); + } + + if (rv == CKR_OK) { + rv = pkcs11_session->provider->f->C_OpenSession ( + pkcs11_session->slot, + CKF_SERIAL_SESSION, + NULL_PTR, + NULL_PTR, + &pkcs11_session->session + ); + } + + if (rv == CKR_OK) { + int nRetryCount = 0; + do { + CK_UTF8CHAR_PTR utfPIN = NULL; + CK_ULONG lPINLength = 0; + char szPIN[1024]; + + /* + * Assume OK for next iteration + */ + rv = CKR_OK; + + if ( + rv == CKR_OK && + !pkcs11_session->fProtectedAuthentication + ) { + if ( + !pkcs11_data->hooks->pin_prompt ( + pkcs11_data->hooks->pin_prompt_data, + pkcs11_session->szLabel, + szPIN, + sizeof (szPIN) + ) + ) { + rv = CKR_FUNCTION_FAILED; + } + else { + utfPIN = (CK_UTF8CHAR_PTR)szPIN; + lPINLength = strlen (szPIN); + } + } + + if (pkcs11_data->nPINCachePeriod == -1) { + pkcs11_session->timePINExpire = 0; + } + else { + pkcs11_session->timePINExpire = ( + time (NULL) + + (time_t)pkcs11_data->nPINCachePeriod + ); + } + if ( + rv == CKR_OK && + (rv = pkcs11_session->provider->f->C_Login ( + pkcs11_session->session, + CKU_USER, + utfPIN, + lPINLength + )) != CKR_OK + ) { + if (rv == CKR_USER_ALREADY_LOGGED_IN) { + rv = CKR_OK; + } + } + + /* + * Clean PIN buffer + */ + memset (szPIN, 0, sizeof (szPIN)); + } while ( + ++nRetryCount < 3 && + ( + rv == CKR_PIN_INCORRECT || + rv == CKR_PIN_INVALID + ) + ); + } + + if ( + rv == CKR_OK && + pkcs11_session->certificate_id != NULL + ) { + rv = _pkcs11_getObjectById ( + pkcs11_session, + CKO_PRIVATE_KEY, + pkcs11_session->certificate_id, + pkcs11_session->certificate_id_size, + &pkcs11_session->key + ); + } + + return rv; +} + +static +CK_RV +_pkcs11_logout ( + IN const pkcs11_session_t pkcs11_session +) { + ASSERT (pkcs11_session!=NULL); + + if (pkcs11_session->session != (CK_SESSION_HANDLE)-1) { + pkcs11_session->provider->f->C_Logout (pkcs11_session->session); + pkcs11_session->provider->f->C_CloseSession (pkcs11_session->session); + pkcs11_session->key = (CK_OBJECT_HANDLE)-1; + pkcs11_session->session = (CK_SESSION_HANDLE)-1; + } + + return CKR_OK; +} + + /*======================================= * Simplified PKCS#11 functions */ static +bool +_pkcs11_hooks_card_prompt_default ( + IN const void * pData, + IN const char * const szLabel +) { + return false; +} + +static +bool +_pkcs11_hooks_pin_prompt_default ( + IN const void * pData, + IN const char * const szLabel, + OUT char * const szPIN, + IN const size_t nMaxPIN +) { + return false; +} + +static +CK_RV +pkcs11_initialize () { + + pkcs11_terminate (); + + pkcs11_data = (pkcs11_data_t)malloc (sizeof (struct pkcs11_data_s)); + if (pkcs11_data == NULL) { + return CKR_HOST_MEMORY; + } + + memset (pkcs11_data, 0, sizeof (struct pkcs11_data_s)); + + pkcs11_data->nPINCachePeriod = -1; + + pkcs11_data->hooks = (pkcs11_hooks_t)malloc (sizeof (struct pkcs11_hooks_s)); + if (pkcs11_data->hooks == NULL) { + return CKR_HOST_MEMORY; + } + + memset (pkcs11_data->hooks, 0, sizeof (struct pkcs11_hooks_s)); + + pkcs11_data->fInitialized = true; + + pkcs11_setCardPromptHook (_pkcs11_hooks_card_prompt_default, NULL); + pkcs11_setPINPromptHook (_pkcs11_hooks_pin_prompt_default, NULL); + + return CKR_OK; +} + +static +CK_RV +pkcs11_terminate () { + + if (pkcs11_data != NULL) { + pkcs11_provider_t last = NULL; + + for ( + ; + pkcs11_data->providers != NULL; + pkcs11_data->providers = pkcs11_data->providers->next + ) { + if (last != NULL) { + free (last); + } + last = pkcs11_data->providers; + + if (pkcs11_data->providers->szSignMode != NULL) { + free (pkcs11_data->providers->szSignMode); + pkcs11_data->providers->szSignMode = NULL; + } + + if (pkcs11_data->providers->fShouldFinalize) { + pkcs11_data->providers->f->C_Finalize (NULL); + pkcs11_data->providers->fShouldFinalize = false; + } + + if (pkcs11_data->providers->f != NULL) { + pkcs11_data->providers->f = NULL; + } + + if (pkcs11_data->providers->hLibrary != NULL) { +#if defined(WIN32) + FreeLibrary (pkcs11_data->providers->hLibrary); +#else + dlclose (pkcs11_data->providers->hLibrary); +#endif + pkcs11_data->providers->hLibrary = NULL; + } + } + + if (last != NULL) { + free (last); + } + + if (pkcs11_data->hooks != NULL) { + free (pkcs11_data->hooks); + pkcs11_data->hooks = NULL; + } + + free (pkcs11_data); + pkcs11_data = NULL; + } + + return CKR_OK; +} + +static +CK_RV +pkcs11_setPINPromptHook ( + IN const pkcs11_hook_pin_prompt_t hook, + IN void * const pData +) { + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); + + pkcs11_data->hooks->pin_prompt = hook; + pkcs11_data->hooks->pin_prompt_data = pData; + + return CKR_OK; +} + +static +CK_RV +pkcs11_setCardPromptHook ( + IN const pkcs11_hook_card_prompt_t hook, + IN void * const pData +) { + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); + + pkcs11_data->hooks->card_prompt = hook; + pkcs11_data->hooks->card_prompt_data = pData; + + return CKR_OK; +} + +static +CK_RV +pkcs11_setPINCachePeriod ( + IN const int nPINCachePeriod +) { + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); + + pkcs11_data->nPINCachePeriod = nPINCachePeriod; + + return CKR_OK; +} + +static CK_RV pkcs11_addProvider ( IN const char * const szProvider, @@ -890,6 +1363,8 @@ pkcs11_addProvider ( CK_C_GetFunctionList gfl = NULL; CK_RV rv = CKR_OK; + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (szProvider!=NULL); if ( @@ -930,10 +1405,18 @@ pkcs11_addProvider ( "C_GetFunctionList" ); #else - gfl = (CK_C_GetFunctionList)dlsym ( + /* + * Make compiler happy! + */ + void *p = dlsym ( provider->hLibrary, "C_GetFunctionList" ); + memmove ( + &gfl, + &p, + sizeof (void *) + ); #endif if (gfl == NULL) { rv = CKR_FUNCTION_FAILED; @@ -960,14 +1443,14 @@ pkcs11_addProvider ( } if (provider != NULL) { - if (pkcs11_provider == NULL) { - pkcs11_provider = provider; + if (pkcs11_data->providers == NULL) { + pkcs11_data->providers = provider; } else { pkcs11_provider_t last = NULL; for ( - last = pkcs11_provider; + last = pkcs11_data->providers; last->next != NULL; last = last->next ); @@ -977,54 +1460,29 @@ pkcs11_addProvider ( return rv; } - + static CK_RV -pkcs11_finalize () { - - pkcs11_provider_t last = NULL; +pkcs11_forkFixup () { + + pkcs11_provider_t current; + + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); for ( - ; - pkcs11_provider != NULL; - pkcs11_provider = pkcs11_provider->next + current = pkcs11_data->providers; + current != NULL; + current = current->next ) { - if (last != NULL) { - free (last); - } - last = pkcs11_provider; - - if (pkcs11_provider->szSignMode != NULL) { - free (pkcs11_provider->szSignMode); - pkcs11_provider->szSignMode = NULL; - } - - if (pkcs11_provider->fShouldFinalize) { - pkcs11_provider->f->C_Finalize (NULL); - pkcs11_provider->fShouldFinalize = false; - } - - if (pkcs11_provider->f != NULL) { - pkcs11_provider->f = NULL; + if (current->fEnabled) { + current->f->C_Initialize (NULL); } - - if (pkcs11_provider->hLibrary != NULL) { -#if defined(WIN32) - FreeLibrary (pkcs11_provider->hLibrary); -#else - dlclose (pkcs11_provider->hLibrary); -#endif - pkcs11_provider->hLibrary = NULL; - } - } - - if (last != NULL) { - free (last); } return CKR_OK; } - + static CK_RV pkcs11_createSession ( @@ -1032,18 +1490,18 @@ pkcs11_createSession ( IN const char * const szSlot, IN const char * const szIdType, IN const char * const szId, - IN const char * const szPIN, IN const bool fProtectedAuthentication, OUT pkcs11_session_t * const p_pkcs11_session ) { pkcs11_session_t pkcs11_session; CK_RV rv = CKR_OK; + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (szSlotType!=NULL); ASSERT (szSlot!=NULL); ASSERT (szIdType!=NULL); ASSERT (szId!=NULL); - ASSERT (szPIN!=NULL); ASSERT (p_pkcs11_session!=NULL); if ( @@ -1058,36 +1516,46 @@ pkcs11_createSession ( memset (pkcs11_session, 0, sizeof (struct pkcs11_session_s)); } - if ( - rv == CKR_OK && - !fProtectedAuthentication - ) { - if ((pkcs11_session->szPIN = strdup (szPIN)) == NULL) { - rv = CKR_HOST_MEMORY; - } - } - if (rv == CKR_OK) { - pkcs11_session->fLoginFailed = false; pkcs11_session->key = (CK_OBJECT_HANDLE)-1; pkcs11_session->session = (CK_SESSION_HANDLE)-1; + pkcs11_session->fProtectedAuthentication = fProtectedAuthentication; + } - if (!strcmp (szSlotType, "id")) { - rv = _pkcs11_getSlotById (pkcs11_session, szSlot); - } - else if (!strcmp (szSlotType, "name")) { - rv = _pkcs11_getSlotByName (pkcs11_session, szSlot); - } - else if (!strcmp (szSlotType, "label")) { - rv = _pkcs11_getSlotByLabel (pkcs11_session, szSlot); - } - else { - rv = CKR_ARGUMENTS_BAD; - } + if (rv == CKR_OK) { + bool fCancel = false; + + do { + if (!strcmp (szSlotType, "id")) { + rv = _pkcs11_getSlotById (pkcs11_session, szSlot); + } + else if (!strcmp (szSlotType, "name")) { + rv = _pkcs11_getSlotByName (pkcs11_session, szSlot); + } + else if (!strcmp (szSlotType, "label")) { + rv = _pkcs11_getSlotByLabel (pkcs11_session, szSlot); + } + else { + rv = CKR_ARGUMENTS_BAD; + } + + if (rv == CKR_SLOT_ID_INVALID) { + char szLabel[1024]; + snprintf (szLabel, sizeof (szLabel), "SLOT(%s=%s)", szSlotType, szSlot); + fCancel = !pkcs11_data->hooks->card_prompt ( + pkcs11_data->hooks->card_prompt_data, + szLabel + ); + } + } while (rv == CKR_SLOT_ID_INVALID && !fCancel); + } + + if (rv == CKR_OK) { + rv = _pkcs11_setSessionTokenInfo (pkcs11_session); } if (rv == CKR_OK) { - rv = pkcs11_login ( + rv = _pkcs11_login ( pkcs11_session ); } @@ -1106,88 +1574,10 @@ pkcs11_createSession ( ); } - pkcs11_logout ( - pkcs11_session - ); - - return rv; -} - -CK_RV -pkcs11_freeSession ( - IN const pkcs11_session_t pkcs11_session -) { - if (pkcs11_session != NULL) { - pkcs11_logout (pkcs11_session); - - if (pkcs11_session->szPIN != NULL) { - free (pkcs11_session->szPIN); - } - if (pkcs11_session->certificate != NULL) { - free (pkcs11_session->certificate); - } - if (pkcs11_session->certificate_id != NULL) { - free (pkcs11_session->certificate_id); - } - - free (pkcs11_session); - } - - return CKR_OK; -} - -static -CK_RV -pkcs11_login ( - IN const pkcs11_session_t pkcs11_session -) { - CK_RV rv = CKR_OK; - - ASSERT (pkcs11_session!=NULL); - - pkcs11_logout (pkcs11_session); - - if (rv == CKR_OK) { - rv = pkcs11_session->provider->f->C_OpenSession ( - pkcs11_session->slot, - CKF_SERIAL_SESSION, - NULL_PTR, - NULL_PTR, - &pkcs11_session->session - ); - } - /* - * Do not lock the token + * Complete missing login process */ - if ( - rv == CKR_OK && - pkcs11_session->fLoginFailed - ) { - rv = CKR_PIN_INVALID; - } - - if ( - rv == CKR_OK && - (rv = pkcs11_session->provider->f->C_Login ( - pkcs11_session->session, - CKU_USER, - pkcs11_session->szPIN, - pkcs11_session->szPIN == NULL ? 0 : (CK_ULONG)strlen (pkcs11_session->szPIN) - )) != CKR_OK - ) { - if (rv == CKR_USER_ALREADY_LOGGED_IN) { - rv = CKR_OK; - } - else { - pkcs11_session->fLoginFailed = true; - } - } - - if ( - rv == CKR_OK && - pkcs11_session->certificate_id != NULL - ) { + if (rv == CKR_OK) { rv = _pkcs11_getObjectById ( pkcs11_session, CKO_PRIVATE_KEY, @@ -1197,25 +1587,27 @@ pkcs11_login ( ); } - if (rv != CKR_OK) { - pkcs11_logout (pkcs11_session); - } - return rv; } -static CK_RV -pkcs11_logout ( +pkcs11_freeSession ( IN const pkcs11_session_t pkcs11_session ) { - ASSERT (pkcs11_session!=NULL); + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); - if (pkcs11_session->session != (CK_SESSION_HANDLE)-1) { - pkcs11_session->provider->f->C_Logout (pkcs11_session->session); - pkcs11_session->provider->f->C_CloseSession (pkcs11_session->session); - pkcs11_session->key = (CK_OBJECT_HANDLE)-1; - pkcs11_session->session = (CK_SESSION_HANDLE)-1; + if (pkcs11_session != NULL) { + _pkcs11_logout (pkcs11_session); + + if (pkcs11_session->certificate != NULL) { + free (pkcs11_session->certificate); + } + if (pkcs11_session->certificate_id != NULL) { + free (pkcs11_session->certificate_id); + } + + free (pkcs11_session); } return CKR_OK; @@ -1227,40 +1619,55 @@ pkcs11_sign ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ) { CK_MECHANISM mech = { mech_type, NULL, 0 }; - CK_ULONG size; - CK_RV rv; + CK_RV rv = CKR_OK; + bool fLogonRetry = false; + bool fOpSuccess = false; + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (pkcs11_session!=NULL); ASSERT (source!=NULL); ASSERT (target_size!=NULL); - if ( - (rv = pkcs11_session->provider->f->C_SignInit ( + rv = _pkcs11_validateSession (pkcs11_session); + + while (rv == CKR_OK && !fOpSuccess) { + rv = pkcs11_session->provider->f->C_SignInit ( pkcs11_session->session, &mech, pkcs11_session->key - )) != CKR_OK - ) { - return rv; + ); + + if (rv == CKR_OK) { + fOpSuccess = true; + } + else { + if (!fLogonRetry) { + fLogonRetry = true; + rv = _pkcs11_login (pkcs11_session); + } + } } - size = *target_size; - rv = pkcs11_session->provider->f->C_Sign ( - pkcs11_session->session, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size - ); + if (rv == CKR_OK) { + CK_ULONG size = *target_size; + rv = pkcs11_session->provider->f->C_Sign ( + pkcs11_session->session, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); - *target_size = (int)size; + *target_size = (int)size; + } return rv; } @@ -1271,40 +1678,55 @@ pkcs11_signRecover ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ) { CK_MECHANISM mech = { mech_type, NULL, 0 }; - CK_ULONG size; - CK_RV rv; + CK_RV rv = CKR_OK; + bool fLogonRetry = false; + bool fOpSuccess = false; + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (pkcs11_session!=NULL); ASSERT (source!=NULL); ASSERT (target_size!=NULL); - if ( - (rv = pkcs11_session->provider->f->C_SignRecoverInit ( + rv = _pkcs11_validateSession (pkcs11_session); + + while (rv == CKR_OK && !fOpSuccess) { + rv = pkcs11_session->provider->f->C_SignRecoverInit ( pkcs11_session->session, &mech, pkcs11_session->key - )) != CKR_OK - ) { - return rv; + ); + + if (rv == CKR_OK) { + fOpSuccess = true; + } + else { + if (!fLogonRetry) { + fLogonRetry = true; + rv = _pkcs11_login (pkcs11_session); + } + } } - size = *target_size; - rv = pkcs11_session->provider->f->C_SignRecover ( - pkcs11_session->session, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size - ); + if (rv == CKR_OK) { + CK_ULONG size = *target_size; + rv = pkcs11_session->provider->f->C_SignRecover ( + pkcs11_session->session, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); - *target_size = (int)size; + *target_size = (int)size; + } return rv; } @@ -1315,40 +1737,56 @@ pkcs11_decrypt ( IN const pkcs11_session_t pkcs11_session, IN const CK_MECHANISM_TYPE mech_type, IN const unsigned char * const source, - IN const int source_size, + IN const size_t source_size, OUT unsigned char * const target, - IN OUT int * const target_size + IN OUT size_t * const target_size ) { CK_MECHANISM mech = { mech_type, NULL, 0 }; CK_ULONG size; - CK_RV rv; + CK_RV rv = CKR_OK; + bool fLogonRetry = false; + bool fOpSuccess = false; + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (pkcs11_session!=NULL); ASSERT (source!=NULL); ASSERT (target_size!=NULL); - if ( - (rv = pkcs11_session->provider->f->C_DecryptInit ( + rv = _pkcs11_validateSession (pkcs11_session); + + while (rv == CKR_OK && !fOpSuccess) { + rv = pkcs11_session->provider->f->C_DecryptInit ( pkcs11_session->session, &mech, pkcs11_session->key - )) != CKR_OK - ) { - return rv; + ); + + if (rv == CKR_OK) { + fOpSuccess = true; + } + else { + if (!fLogonRetry) { + fLogonRetry = true; + rv = _pkcs11_login (pkcs11_session); + } + } } - size = *target_size; - rv = pkcs11_session->provider->f->C_Decrypt ( - pkcs11_session->session, - (CK_BYTE_PTR)source, - source_size, - (CK_BYTE_PTR)target, - &size - ); + if (rv == CKR_OK) { + size = *target_size; + rv = pkcs11_session->provider->f->C_Decrypt ( + pkcs11_session->session, + (CK_BYTE_PTR)source, + source_size, + (CK_BYTE_PTR)target, + &size + ); - *target_size = (int)size; + *target_size = (int)size; + } return rv; } @@ -1357,9 +1795,11 @@ static CK_RV pkcs11_getCertificate ( IN const pkcs11_session_t pkcs11_session, - OUT char * const certificate, - IN OUT int * const certificate_size + OUT unsigned char * const certificate, + IN OUT size_t * const certificate_size ) { + ASSERT (pkcs11_data!=NULL); + ASSERT (pkcs11_data->fInitialized); ASSERT (certificate_size!=NULL); *certificate_size = pkcs11_session->certificate_size; @@ -1474,10 +1914,11 @@ pkcs11_getMessage ( } /*========================================== - * openvpn interface + * openssl interface */ typedef struct openssl_session_s { + RSA_METHOD smart_rsa; int (*orig_finish)(RSA *rsa); pkcs11_session_t pkcs11_session; } *openssl_session_t; @@ -1525,7 +1966,7 @@ openssl_pkcs11_priv_dec ( flen, from, to, - rsa, + (void *)rsa, padding ); @@ -1543,27 +1984,18 @@ openssl_pkcs11_priv_dec ( if ( rv == CKR_OK && - (rv = pkcs11_login (pkcs11_session)) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot login to token %ld:'%s'", rv, pkcs11_getMessage (rv)); - } - - if ( - rv == CKR_OK && (rv = pkcs11_decrypt ( pkcs11_session, CKM_RSA_PKCS, from, flen, to, - &flen + (size_t *)&flen )) != CKR_OK ) { msg (M_WARN, "PKCS#11: Cannot decrypt using private key %ld:'%s'", rv, pkcs11_getMessage (rv)); } - pkcs11_logout (pkcs11_session); - msg ( D_PKCS11_DEBUG, "PKCS#11: openssl_pkcs11_priv_dec - return rv=%ld", @@ -1593,8 +2025,8 @@ openssl_pkcs11_sign ( m, m_len, sigret, - siglen, - rsa + (void *)siglen, + (void *)rsa ); ASSERT (m!=NULL); @@ -1607,46 +2039,35 @@ openssl_pkcs11_sign ( *siglen = RSA_size(rsa); - if ( - rv == CKR_OK && - (rv = pkcs11_login (pkcs11_session)) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot login to token %ld:'%s'", rv, pkcs11_getMessage (rv)); - } - - if (rv == CKR_OK) { - if (pkcs11_session->fKeySignRecover) { - if ( - (rv = pkcs11_signRecover ( - pkcs11_session, - CKM_RSA_PKCS, - m, - m_len, - sigret, - siglen - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11_getMessage (rv)); - } + if (pkcs11_session->fKeySignRecover) { + if ( + (rv = pkcs11_signRecover ( + pkcs11_session, + CKM_RSA_PKCS, + m, + m_len, + sigret, + siglen + )) != CKR_OK + ) { + msg (M_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11_getMessage (rv)); } - else { - if ( - (rv = pkcs11_sign ( - pkcs11_session, - CKM_RSA_PKCS, - m, - m_len, - sigret, - siglen - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11_getMessage (rv)); - } + } + else { + if ( + (rv = pkcs11_sign ( + pkcs11_session, + CKM_RSA_PKCS, + m, + m_len, + sigret, + siglen + )) != CKR_OK + ) { + msg (M_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11_getMessage (rv)); } } - pkcs11_logout (pkcs11_session); - msg ( D_PKCS11_DEBUG, "PKCS#11: openssl_pkcs11_priv_sign - return rv=%ld", @@ -1664,8 +2085,8 @@ openssl_pkcs11_finish(RSA *rsa) { msg ( D_PKCS11_DEBUG, - "PKCS#11: openssl_pkcs11_finish - entered - rsa=%p", - rsa + "PKCS#11: openssl_pkcs11_finish - entered rsa=%p", + (void *)rsa ); openssl_session = (openssl_session_t)RSA_get_app_data (rsa); @@ -1703,27 +2124,37 @@ openssl_pkcs11_finish(RSA *rsa) { return 1; } -static RSA_METHOD * -openssl_pkcs11_get_rsa_method(RSA *rsa) +void +openssl_pkcs11_set_rsa(const openssl_session_t openssl_session, RSA *rsa) { - static RSA_METHOD smart_rsa; const RSA_METHOD *def = RSA_get_default_method(); - ASSERT (rsa); + ASSERT (openssl_session!=NULL); + ASSERT (rsa!=NULL); + + memmove (&openssl_session->smart_rsa, def, sizeof(RSA_METHOD)); - /* use the OpenSSL version */ - memmove (&smart_rsa, def, sizeof(smart_rsa)); + openssl_session->orig_finish = def->finish; - /* save original */ - ((openssl_session_t)RSA_get_app_data (rsa))->orig_finish = def->finish; + openssl_session->smart_rsa.name = "pkcs11"; + openssl_session->smart_rsa.rsa_priv_enc = openssl_pkcs11_priv_enc; + openssl_session->smart_rsa.rsa_priv_dec = openssl_pkcs11_priv_dec; + openssl_session->smart_rsa.rsa_sign = openssl_pkcs11_sign; + openssl_session->smart_rsa.finish = openssl_pkcs11_finish; + openssl_session->smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY; - smart_rsa.name = "pkcs11"; - smart_rsa.rsa_priv_enc = openssl_pkcs11_priv_enc; - smart_rsa.rsa_priv_dec = openssl_pkcs11_priv_dec; - smart_rsa.rsa_sign = openssl_pkcs11_sign; - smart_rsa.finish = openssl_pkcs11_finish; - smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY; - return &smart_rsa; + RSA_set_method (rsa, &openssl_session->smart_rsa); + RSA_set_app_data (rsa, openssl_session); + +#ifdef BROKEN_OPENSSL_ENGINE + if (fOK) { + if (!rsa->engine) + rsa->engine = ENGINE_get_default_RSA(); + + ENGINE_set_RSA(ENGINE_get_default_RSA(), openssl_session->smart_rsa); + msg(M_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled"); + } +#endif } @@ -1737,6 +2168,150 @@ static void broken_openssl_init() } #endif +/*========================================== + * openvpn interface + */ + +static +bool +_openvpn_pkcs11_card_prompt ( + IN const void *pData, + IN const char * const szLabel +) { + static struct user_pass token_pass; + char szPrompt[1024]; + char szTemp[1024]; + + ASSERT (szLabel!=NULL); + + openvpn_snprintf (szPrompt, sizeof (szPrompt), "INSERT"); + + token_pass.defined = false; + token_pass.nocache = true; + get_user_pass (&token_pass, NULL, true, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); + strncpynt (szTemp, token_pass.password, sizeof (szTemp)); + purge_user_pass (&token_pass, true); + + if (strlen (szTemp) == 0) { + return false; + } + else { + return true; + } +} + +static +bool +_openvpn_pkcs11_pin_prompt ( + IN const void *pData, + IN const char * const szLabel, + OUT char * const szPIN, + IN const size_t nMaxPIN +) { + static struct user_pass token_pass; + char szPrompt[1024]; + + ASSERT (szLabel!=NULL); + + openvpn_snprintf (szPrompt, sizeof (szPrompt), "%s token", szLabel); + + token_pass.defined = false; + token_pass.nocache = true; + get_user_pass (&token_pass, NULL, true, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); + strncpynt (szPIN, token_pass.password, nMaxPIN); + purge_user_pass (&token_pass, true); + + if (strlen (szPIN) == 0) { + return false; + } + else { + return true; + } +} + +void +init_pkcs11 ( + const int nPINCachePeriod +) { + CK_RV rv; + + msg ( + D_PKCS11_DEBUG, + "PKCS#11: init_pkcs11 - entered" + ); + + if ((rv = pkcs11_initialize ()) != CKR_OK) { + msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11_getMessage (rv)); + } +/*Until REQUEST/REPLY interface. + if ((rv = pkcs11_setCardPromptHook (_openvpn_pkcs11_card_prompt, NULL)) != CKR_OK) { + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv)); + } +*/ + if ((rv = pkcs11_setPINPromptHook (_openvpn_pkcs11_pin_prompt, NULL)) != CKR_OK) { + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + + if ((rv = pkcs11_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) { + msg (M_FATAL, "PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + + msg ( + D_PKCS11_DEBUG, + "PKCS#11: init_pkcs11 - return" + ); +} + +void +free_pkcs11 () { + msg ( + D_PKCS11_DEBUG, + "PKCS#11: free_pkcs11 - entered" + ); + + pkcs11_terminate (); + + msg ( + D_PKCS11_DEBUG, + "PKCS#11: free_pkcs11 - return" + ); +} + +void +fork_fix_pkcs11 () { + pkcs11_forkFixup (); +} + +void +add_pkcs11 ( + IN const char * const provider, + IN const char * const sign_mode +) { + CK_RV rv; + + msg ( + D_PKCS11_DEBUG, + "PKCS#11: add_pkcs11 - entered - provider='%s', sign_mode='%s'", + provider, + sign_mode == NULL ? "default" : sign_mode + ); + + msg ( + M_INFO, + "PKCS#11: Adding PKCS#11 provider '%s'", + provider + ); + + if ((rv = pkcs11_addProvider (provider, sign_mode)) != CKR_OK) { + msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11_getMessage (rv)); + } + + msg ( + D_PKCS11_DEBUG, + "PKCS#11: add_pkcs11 - return" + ); +} + int SSL_CTX_use_pkcs11 ( IN OUT SSL_CTX * const ssl_ctx, @@ -1744,7 +2319,6 @@ SSL_CTX_use_pkcs11 ( IN const char * const pkcs11_slot, IN const char * const pkcs11_id_type, IN const char * const pkcs11_id, - IN const char * const pin, IN const bool pkcs11_protected_authentication ) { X509 *x509 = NULL; @@ -1755,14 +2329,14 @@ SSL_CTX_use_pkcs11 ( CK_RV rv = CKR_OK; unsigned char certificate[10*1024]; - int certificate_size; + size_t certificate_size; unsigned char *p; bool fOK = true; msg ( D_PKCS11_DEBUG, "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_slot_type='%s', pkcs11_slot='%s', pkcs11_id_type='%s', pkcs11_id='%s', pkcs11_protected_authentication=%d", - ssl_ctx, + (void *)ssl_ctx, pkcs11_slot_type, pkcs11_slot, pkcs11_id_type, @@ -1775,9 +2349,6 @@ SSL_CTX_use_pkcs11 ( ASSERT (pkcs11_slot!=NULL); ASSERT (pkcs11_id_type!=NULL); ASSERT (pkcs11_id!=NULL); - if (!pkcs11_protected_authentication) { - ASSERT (pin!=NULL); - } if ( fOK && @@ -1798,7 +2369,6 @@ SSL_CTX_use_pkcs11 ( pkcs11_slot, pkcs11_id_type, pkcs11_id, - pin, pkcs11_protected_authentication, &openssl_session->pkcs11_session )) != CKR_OK @@ -1862,23 +2432,12 @@ SSL_CTX_use_pkcs11 ( } if (fOK) { - RSA_set_app_data (rsa, openssl_session); - RSA_set_method (rsa, openssl_pkcs11_get_rsa_method (rsa)); + openssl_pkcs11_set_rsa (openssl_session, rsa); rsa->flags |= RSA_FLAG_SIGN_VER; /* it will be freed when rsa usage count will be zero */ fShouldFreeOpenSSLSession = false; } - -#ifdef BROKEN_OPENSSL_ENGINE - if (fOK) { - if (!rsa->engine) - rsa->engine = ENGINE_get_default_RSA(); - - ENGINE_set_RSA(ENGINE_get_default_RSA(), openssl_pkcs11_get_rsa_method(rsa)); - msg(M_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled"); - } -#endif if ( fOK && @@ -1936,51 +2495,6 @@ SSL_CTX_use_pkcs11 ( } void -add_pkcs11 ( - IN const char * const provider, - IN const char * const sign_mode -) { - CK_RV rv; - - msg ( - D_PKCS11_DEBUG, - "PKCS#11: add_pkcs11 - entered - provider='%s', sign_mode='%s'", - provider, - sign_mode == NULL ? "default" : sign_mode - ); - - msg ( - M_INFO, - "PKCS#11: Adding PKCS#11 provider '%s'", - provider - ); - - if ((rv = pkcs11_addProvider (provider, sign_mode)) != CKR_OK) { - msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11_getMessage (rv)); - } - - msg ( - D_PKCS11_DEBUG, - "PKCS#11: add_pkcs11 - return" - ); -} - -void -free_pkcs11 () { - msg ( - D_PKCS11_DEBUG, - "PKCS#11: free_pkcs11 - entered" - ); - - pkcs11_finalize (); - - msg ( - D_PKCS11_DEBUG, - "PKCS#11: free_pkcs11 - return" - ); -} - -void show_pkcs11_slots ( IN const int msglev, IN const int warnlev, @@ -1992,14 +2506,30 @@ show_pkcs11_slots ( CK_SLOT_ID s; CK_RV rv; + pkcs11_provider_t pkcs11_provider; + ASSERT (provider!=NULL); if ( + (rv = pkcs11_initialize ()) != CKR_OK + ) { + msg (M_FATAL, "PKCS#11: Cannot initialize interface %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + + if ( (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK ) { msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv)); } + /* + * our provider is head + */ + pkcs11_provider = pkcs11_data->providers; + if (pkcs11_provider == NULL || !pkcs11_provider->fEnabled) { + msg (M_FATAL, "PKCS#11: Cannot get provider %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + if ( (rv = pkcs11_provider->f->C_GetInfo (&info)) != CKR_OK ) { @@ -2009,7 +2539,7 @@ show_pkcs11_slots ( char szManufacturerID[sizeof (info.manufacturerID)+1]; _fixupFixedString ( - info.manufacturerID, + (char *)info.manufacturerID, szManufacturerID, sizeof (info.manufacturerID) ); @@ -2062,7 +2592,7 @@ show_pkcs11_slots ( char szCurrentName[sizeof (info.slotDescription)+1]; _fixupFixedString ( - info.slotDescription, + (char *)info.slotDescription, szCurrentName, sizeof (info.slotDescription) ); @@ -2072,7 +2602,19 @@ show_pkcs11_slots ( } } - pkcs11_finalize (); + pkcs11_terminate (); +} + +static +bool +_show_pkcs11_objects_pin_prompt ( + IN const void *pData, + IN const char * const szLabel, + OUT char * const szPIN, + IN const size_t nMaxPIN +) { + strncpy (szPIN, (char *)pData, nMaxPIN); + return true; } void @@ -2090,6 +2632,8 @@ show_pkcs11_objects ( CK_SLOT_ID s; CK_RV rv; + pkcs11_provider_t pkcs11_provider; + ASSERT (provider!=NULL); ASSERT (slot!=NULL); ASSERT (pin!=NULL); @@ -2097,11 +2641,31 @@ show_pkcs11_objects ( s = atoi (slot); if ( + (rv = pkcs11_initialize ()) != CKR_OK + ) { + msg (M_FATAL, "PKCS#11: Cannot initialize interface %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + + if ( + (rv = pkcs11_setPINPromptHook (_show_pkcs11_objects_pin_prompt, (void *)pin)) != CKR_OK + ) { + msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + + if ( (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK ) { msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv)); } + /* + * our provider is head + */ + pkcs11_provider = pkcs11_data->providers; + if (pkcs11_provider == NULL || !pkcs11_provider->fEnabled) { + msg (M_FATAL, "PKCS#11: Cannot get provider %ld-'%s'", rv, pkcs11_getMessage (rv)); + } + if ( (rv = pkcs11_provider->f->C_GetTokenInfo ( s, @@ -2117,22 +2681,22 @@ show_pkcs11_objects ( char szSerialNumber[sizeof (info.serialNumber)+1]; _fixupFixedString ( - info.label, + (char *)info.label, szLabel, sizeof (info.label) ); _fixupFixedString ( - info.manufacturerID, + (char *)info.manufacturerID, szManufacturerID, sizeof (info.manufacturerID) ); _fixupFixedString ( - info.model, + (char *)info.model, szModel, sizeof (info.model) ); _fixupFixedString ( - info.serialNumber, + (char *)info.serialNumber, szSerialNumber, sizeof (info.serialNumber) ); @@ -2385,9 +2949,9 @@ show_pkcs11_objects ( pkcs11_provider->f->C_FindObjectsFinal (session); pkcs11_provider->f->C_Logout (session); pkcs11_provider->f->C_CloseSession (session); - pkcs11_finalize (); + pkcs11_terminate (); } #else static void dummy (void) {} -#endif /* USE_OPENSC && USE_SSL && USE_CRYPTO */ +#endif /* ENABLE_PKCS11 */ @@ -29,6 +29,23 @@ #include <openssl/ssl.h> +void +init_pkcs11 ( + const int nPINCachePeriod +); + +void +free_pkcs11 (); + +void +fork_fix_pkcs11 (); + +void +add_pkcs11 ( + const char * const provider, + const char * const sign_mode +); + int SSL_CTX_use_pkcs11 ( SSL_CTX * const ssl_ctx, @@ -36,20 +53,10 @@ SSL_CTX_use_pkcs11 ( const char * const pkcs11_slot, const char * const pkcs11_id_type, const char * const pkcs11_id, - const char * const pin, const bool pkcs11_protected_authentication ); void -add_pkcs11 ( - const char * const provider, - const char * const sign_mode -); - -void -free_pkcs11 (); - -void show_pkcs11_slots ( const int msglev, const int warnlev, @@ -65,6 +72,6 @@ show_pkcs11_objects ( const char * const pin ); -#endif +#endif /* ENABLE_PKCS11 */ -#endif +#endif /* OPENVPN_PKCS11_H */ @@ -854,17 +854,8 @@ init_ssl (const struct options *options) #ifdef ENABLE_PKCS11 if (options->pkcs11_providers[0]) { - char password[256]; - password[0] = '\0'; - if ( - !options->pkcs11_protected_authentication && - options->key_pass_file - ) { - pem_password_callback (password, sizeof(password) - 1, 0, NULL); - } - /* 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, password, options->pkcs11_protected_authentication)) + if (!SSL_CTX_use_pkcs11 (ctx, options->pkcs11_slot_type, options->pkcs11_slot, options->pkcs11_id_type, options->pkcs11_id, options->pkcs11_protected_authentication)) 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); } |