/* * Copyright (c) 2005-2006 Alon Bar-Lev * All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, or the OpenIB.org BSD license. * * GNU General Public License (GPL) Version 2 * =========================================== * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING[.GPL2] included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * OpenIB.org BSD license * ======================= * Redistribution and use in source and binary forms, with or without modifi- * cation, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright no- * tice, this list of conditions and the following disclaimer in the do- * cumentation and/or other materials provided with the distribution. * * o The names of the contributors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI- * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN- * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV- * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI- * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The routines in this file deal with providing private key cryptography * using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki). * */ /* * Changelog * * 2006.06.26 * - (alonbl) Fix handling mutiple providers. * - (alonbl) Release 01.01. * * 2006.05.14 * - (alonbl) First stable release. * - (alonbl) Release 01.00. * */ #include "pkcs11-helper-config.h" #if defined(ENABLE_PKCS11H_HELPER) #include "pkcs11-helper.h" /*=========================================== * Constants */ #if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE) # define RSA_get_default_method RSA_get_default_openssl_method #else # ifdef HAVE_ENGINE_GET_DEFAULT_RSA # include # if OPENSSL_VERSION_NUMBER < 0x0090704fL # define BROKEN_OPENSSL_ENGINE # endif # endif #endif #if OPENSSL_VERSION_NUMBER < 0x00907000L #if !defined(RSA_PKCS1_PADDING_SIZE) #define RSA_PKCS1_PADDING_SIZE 11 #endif #endif #define PKCS11H_INVALID_SLOT_ID ((CK_SLOT_ID)-1) #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 /*=========================================== * 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; unsigned 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 ( OUT char * const szTarget, /* MUST BE >= nLength+1 */ IN const char * const szSource, IN const size_t nLength /* FIXED STRING LENGTH */ ); static void _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 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_freeObjectAttributes ( IN OUT const CK_ATTRIBUTE_PTR attrs, IN const unsigned count ); static CK_RV _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_getTokenId ( IN const CK_TOKEN_INFO_PTR info, OUT pkcs11h_token_id_t * const p_token_id ); static CK_RV _pkcs11h_newTokenId ( OUT pkcs11h_token_id_t * const token_id ); static CK_RV _pkcs11h_getSessionByTokenId ( IN const pkcs11h_token_id_t token_id, OUT pkcs11h_session_t * const p_session ); static CK_RV _pkcs11h_releaseSession ( IN const pkcs11h_session_t session ); static CK_RV _pkcs11h_resetSession ( IN const pkcs11h_session_t session, IN const unsigned maskPrompt, OUT CK_SLOT_ID * const p_slot ); static CK_RV _pkcs11h_getObjectById ( IN const pkcs11h_session_t certificate, 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 ); static CK_RV _pkcs11h_validateSession ( IN const pkcs11h_session_t session ); 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 ); static CK_RV _pkcs11h_logout ( IN const pkcs11h_session_t session ); static void _pkcs11h_hooks_default_log ( IN const void * pData, IN const unsigned flags, IN const char * const szFormat, IN va_list args ); static PKCS11H_BOOL _pkcs11h_hooks_default_token_prompt ( IN const void * pData, IN const pkcs11h_token_id_t token, IN const unsigned retry ); static PKCS11H_BOOL _pkcs11h_hooks_default_pin_prompt ( IN const void * pData, IN const pkcs11h_token_id_t token, IN const unsigned retry, OUT char * const szPIN, IN const size_t nMaxPIN ); #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 void _pkcs11h_isBetterCertificate_getExpiration ( IN const unsigned char * const pCertificate, IN const size_t nCertificateSize, OUT char * const szNotBefore, IN const int nNotBeforeSize ); 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 ); static CK_RV _pkcs11h_newCertificateId ( OUT pkcs11h_certificate_id_t * const certificate_id ); static CK_RV _pkcs11h_loadCertificate ( IN const pkcs11h_certificate_t certificate ); static CK_RV _pkcs11h_updateCertificateIdDescription ( IN OUT pkcs11h_certificate_id_t certificate_id ); static CK_RV _pkcs11h_ensureCertificateBlob ( IN const pkcs11h_certificate_t certificate ); static 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 */ #if defined(ENABLE_PKCS11H_LOCATE) /*======================================================================* * LOCATE INTERFACE *======================================================================*/ static 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 unsigned 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 && !provider->fEnabled ) { rv = CKR_CRYPTOKI_NOT_INITIALIZED; } 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 entry 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; unsigned nRetry = 0; 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 all other providers, * if one was set in the past */ if ( session->provider != NULL && session->provider != current_provider ) { rv = CKR_CANCEL; } 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, nRetry++ ) ) { 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; unsigned 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, nRetryCount, 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 (rv == CKR_OK) { 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; } nRetryCount++; } /* * Retry limit */ if (!fSuccessLogin && rv == CKR_OK) { rv = CKR_PIN_INCORRECT; } } #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, IN const unsigned retry ) { PKCS11H_ASSERT (token!=NULL); (void)pData; (void)retry; 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, IN const unsigned retry, OUT char * const szPIN, IN const size_t nMaxPIN ) { PKCS11H_ASSERT (token!=NULL); (void)pData; (void)retry; (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 { /* * OpenSC workaround * It still allows C_FindObjectsInit when * token is removed/inserted but fails * private key operation. * So we force logout. * bug#108 at OpenSC trac */ if (fLoginRetry && rv == CKR_DEVICE_REMOVED) { fLoginRetry = FALSE; _pkcs11h_logout (certificate->session); } 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 ); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_duplicateCertificateId return rv=%ld-'%s', *to=%p", rv, pkcs11h_getMessage (rv), (void *)*to ); 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; } 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 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_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 ); if (target == NULL) { *p_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 ); } 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; } 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 (rv == CKR_OK && !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; } 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 ); } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_certificate_getCertificateBlob return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv; } CK_RV pkcs11h_certificate_ensureCertificateAccess ( IN const pkcs11h_certificate_t certificate, IN const unsigned maskPrompt ) { PKCS11H_BOOL fValidCert = FALSE; CK_RV rv = CKR_OK; PKCS11H_ASSERT (s_pkcs11h_data!=NULL); PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); PKCS11H_ASSERT (certificate!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_certificate_ensureCertificateAccess entry certificate=%p, maskPrompt=%08x", (void *)certificate, maskPrompt ); if (!fValidCert && rv == CKR_OK) { CK_OBJECT_HANDLE h = PKCS11H_INVALID_OBJECT_HANDLE; if ( (rv = _pkcs11h_getObjectById ( certificate->session, CKO_CERTIFICATE, certificate->id->attrCKA_ID, certificate->id->attrCKA_ID_size, &h )) == CKR_OK ) { fValidCert = TRUE; } 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 (!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; } CK_RV pkcs11h_certificate_ensureKeyAccess ( IN const pkcs11h_certificate_t certificate, IN const unsigned maskPrompt ) { CK_RV rv = CKR_OK; PKCS11H_BOOL fValidKey = FALSE; PKCS11H_ASSERT (s_pkcs11h_data!=NULL); PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); PKCS11H_ASSERT (certificate!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_certificate_ensureKeyAccess entry certificate=%p, maskPrompt=%08x", (void *)certificate, maskPrompt ); 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; } 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; certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE; } } if (!fValidKey && rv == CKR_OK) { if ( (rv = _pkcs11h_resetCertificateSession ( certificate, FALSE, maskPrompt )) == CKR_OK ) { fValidKey = TRUE; } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_certificate_ensureKeyAccess return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv; } #endif /* ENABLE_PKCS11H_CERTIFICATE */ #if defined(ENABLE_PKCS11H_LOCATE) /*======================================================================* * LOCATE INTERFACE *======================================================================*/ #if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE) static CK_RV _pkcs11h_locate_getTokenIdBySlotId ( IN const char * const szSlot, OUT pkcs11h_token_id_t * const p_token_id ) { 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; PKCS11H_ASSERT (szSlot!=NULL); PKCS11H_ASSERT (p_token_id!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_locate_getTokenIdBySlotId entry szSlot='%s', p_token_id=%p", szSlot, (void *)p_token_id ); *p_token_id = NULL; if (rv == CKR_OK) { if (strchr (szSlot, ':') == NULL) { szReferenceName[0] = '\0'; selected_slot = atol (szSlot); } else { 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) { 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 || ( current_provider != NULL && !current_provider->fEnabled ) ) { 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_getTokenIdBySlotId return rv=%ld-'%s', *p_token_id=%p", rv, pkcs11h_getMessage (rv), (void *)*p_token_id ); return rv; } static CK_RV _pkcs11h_locate_getTokenIdBySlotName ( IN const char * const szName, 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_BOOL fFound = FALSE; PKCS11H_ASSERT (szName!=NULL); PKCS11H_ASSERT (p_token_id!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_locate_getTokenIdBySlotName entry szName='%s', p_token_id=%p", szName, (void *)p_token_id ); *p_token_id = NULL; current_provider = s_pkcs11h_data->providers; while ( current_provider != NULL && rv == CKR_OK && !fFound ) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; CK_SLOT_ID slot_index; if (!current_provider->fEnabled) { rv = CKR_CRYPTOKI_NOT_INITIALIZED; } 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++ ) { CK_SLOT_INFO info; if ( (rv = current_provider->f->C_GetSlotInfo ( slots[slot_index], &info )) == CKR_OK ) { char szCurrentName[sizeof (info.slotDescription)+1]; _pkcs11h_fixupFixedString ( szCurrentName, (char *)info.slotDescription, sizeof (info.slotDescription) ); 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; } } 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 rv; } static CK_RV _pkcs11h_locate_getTokenIdByLabel ( IN const char * const szLabel, 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_BOOL fFound = FALSE; 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 *)p_token_id ); *p_token_id = NULL; current_provider = s_pkcs11h_data->providers; while ( current_provider != NULL && rv == CKR_OK && !fFound ) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; CK_SLOT_ID slot_index; if (!current_provider->fEnabled) { rv = CKR_CRYPTOKI_NOT_INITIALIZED; } 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++ ) { CK_TOKEN_INFO info; if (rv == CKR_OK) { rv = current_provider->f->C_GetTokenInfo ( slots[slot_index], &info ); } 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; selected_slot = slots[slot_index]; } } 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 (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; } } 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_getTokenIdByLabel return rv=%ld-'%s', *p_token_id=%p", rv, pkcs11h_getMessage (rv), (void *)*p_token_id ); return rv; } CK_RV pkcs11h_locate_token ( IN const char * const szSlotType, IN const char * const szSlot, OUT pkcs11h_token_id_t * const p_token_id ) { #if defined(ENABLE_PKCS11H_THREADING) PKCS11H_BOOL fMutexLocked = FALSE; #endif pkcs11h_token_id_t dummy_token_id = NULL; pkcs11h_token_id_t token_id = NULL; PKCS11H_BOOL fFound = FALSE; CK_RV rv = CKR_OK; unsigned nRetry = 0; 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); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_locate_token entry szSlotType='%s', szSlot='%s', p_token_id=%p", szSlotType, szSlot, (void *)p_token_id ); *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 = _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; } 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; } if (rv == CKR_OK) { fFound = TRUE; } 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 ( !s_pkcs11h_data->hooks.token_prompt ( s_pkcs11h_data->hooks.token_prompt_data, dummy_token_id, nRetry++ ) ) { rv = CKR_CANCEL; } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG1, "PKCS#11: token_prompt returned %ld", rv ); } } if (rv == CKR_OK && !fFound) { rv = CKR_SLOT_ID_INVALID; } if (rv == CKR_OK) { *p_token_id = token_id; token_id = NULL; } if (dummy_token_id != NULL) { pkcs11h_freeTokenId (dummy_token_id); dummy_token_id = 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_locate_token return rv=%ld-'%s', *p_token_id=%p", rv, pkcs11h_getMessage (rv), (void *)*p_token_id ); return rv; } #endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */ #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 ) { size_t target_max_size; const char *p; char buf[3] = {'\0', '\0', '\0'}; int i = 0; PKCS11H_ASSERT (szSource!=NULL); PKCS11H_ASSERT (target!=NULL); PKCS11H_ASSERT (p_target_size!=NULL); target_max_size = *p_target_size; p = szSource; *p_target_size = 0; while (*p != '\0' && *p_target_size < target_max_size) { if (isxdigit ((unsigned char)*p)) { buf[i%2] = *p; if ((i%2) == 1) { unsigned v; if (sscanf (buf, "%x", &v) != 1) { v = 0; } target[*p_target_size] = v & 0xff; (*p_target_size)++; } i++; } p++; } } 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 ) { 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_ULONG i; 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 ); if (rv == CKR_OK) { rv = _pkcs11h_validateSession (session); } 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++) { 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 && certificate_id->certificate_blob == NULL ) { rv = CKR_ATTRIBUTE_VALUE_INVALID; } 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_getCertificateIdByLabel return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv; } 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 ) { 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; CK_ULONG i; 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, (void *)certificate_id, szSubject ); if (rv == CKR_OK) { rv = _pkcs11h_validateSession (session); } 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++) { CK_ATTRIBUTE attrs[] = { {CKA_ID, NULL, 0}, {CKA_VALUE, NULL, 0} }; char szCurrentSubject[1024]; szCurrentSubject[0] = '\0'; if (rv == CKR_OK) { rv = _pkcs11h_getObjectAttributes ( session, objects[i], attrs, sizeof (attrs) / sizeof (CK_ATTRIBUTE) ); } if (rv == CKR_OK) { X509 *x509 = NULL; pkcs11_openssl_d2i_t d2i1; x509 = X509_new (); 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'; } 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; } 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) ); return rv; } 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 ) { 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; 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 ); *p_certificate_id = NULL; if (rv == CKR_OK) { rv = _pkcs11h_newCertificateId (&certificate_id); } if (rv == CKR_OK) { rv = pkcs11h_locate_token ( szSlotType, szSlot, &certificate_id->token_id ); } if (rv == CKR_OK) { rv = _pkcs11h_getSessionByTokenId ( certificate_id->token_id, &session ); } while (rv == CKR_OK && !fOpSuccess) { #if defined(ENABLE_PKCS11H_THREADING) PKCS11H_BOOL fMutexLocked = FALSE; #endif #if defined(ENABLE_PKCS11H_THREADING) if ( rv == CKR_OK && (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK ) { fMutexLocked = TRUE; } #endif if (!strcmp (szIdType, "id")) { certificate_id->attrCKA_ID_size = strlen (szId)/2; if (certificate_id->attrCKA_ID_size == 0) { rv = CKR_FUNCTION_FAILED; } 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, "label")) { rv = _pkcs11h_locate_getCertificateIdByLabel ( session, certificate_id, szId ); } else if (!strcmp (szIdType, "subject")) { rv = _pkcs11h_locate_getCertificateIdBySubject ( session, certificate_id, szId ); } else { rv = CKR_ARGUMENTS_BAD; } #if defined(ENABLE_PKCS11H_THREADING) if (fMutexLocked) { _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); fMutexLocked = FALSE; } #endif 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; } } } if (rv == CKR_OK) { *p_certificate_id = certificate_id; certificate_id = NULL; } if (certificate_id != NULL) { pkcs11h_freeCertificateId (certificate_id); certificate_id = NULL; } if (session != NULL) { _pkcs11h_releaseSession (session); session = NULL; } 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; } #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); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_freeTokenIdList return" ); return CKR_OK; } CK_RV 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; PKCS11H_ASSERT (s_pkcs11h_data!=NULL); PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); PKCS11H_ASSERT (p_token_id_list!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_enum_getTokenIds entry p_token_id_list=%p", (void *)p_token_id_list ); *p_token_id_list = NULL; #if defined(ENABLE_PKCS11H_THREADING) if ( rv == CKR_OK && (rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK ) { fMutexLocked = TRUE; } #endif 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) { rv = CKR_CRYPTOKI_NOT_INITIALIZED; } if (rv == CKR_OK) { rv = _pkcs11h_getSlotList ( current_provider, CK_TRUE, &slots, &slotnum ); } 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)); } if (rv == CKR_OK) { rv = current_provider->f->C_GetTokenInfo ( slots[slot_index], &info ); } 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_malloc ( (void *)&entry, sizeof (struct pkcs11h_token_id_list_s) ); } 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 (token_id_list != NULL) { pkcs11h_freeTokenIdList (token_id_list); token_id_list = NULL; } #if defined(ENABLE_PKCS11H_THREADING) if (fMutexLocked) { rv = _pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal); fMutexLocked = FALSE; } #endif PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_enum_getTokenIds return rv=%ld-'%s', *p_token_id_list=%p", rv, pkcs11h_getMessage (rv), (void *)p_token_id_list ); return rv; } #endif #if defined(ENABLE_PKCS11H_DATA) CK_RV pkcs11h_freeDataIdList ( IN const pkcs11h_data_id_list_t data_id_list ) { 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 ); while (_id != NULL) { pkcs11h_data_id_list_t x = _id; _id = _id->next; if (x->application != NULL) { _pkcs11h_free ((void *)&x->application); } if (x->label != NULL) { _pkcs11h_free ((void *)&x->label); } _pkcs11h_free ((void *)&x); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_freeDataIdList return" ); return CKR_OK; } 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 ) { pkcs11h_session_t session = NULL; pkcs11h_data_id_list_t data_id_list = NULL; CK_RV rv = CKR_OK; PKCS11H_BOOL fOpSuccess = FALSE; PKCS11H_BOOL fLoginRetry = FALSE; 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 ); *p_data_id_list = NULL; if (rv == CKR_OK) { rv = _pkcs11h_getSessionByTokenId ( token_id, &session ); } while (rv == CKR_OK && !fOpSuccess) { #if defined(ENABLE_PKCS11H_THREADING) PKCS11H_BOOL fMutexLocked = FALSE; #endif 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) { 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) { *p_data_id_list = data_id_list; data_id_list = NULL; } if (session != NULL) { _pkcs11h_releaseSession (session); session = NULL; } if (data_id_list != NULL) { pkcs11h_freeDataIdList (data_id_list); data_id_list = NULL; } 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), (void *)*p_data_id_list ); return rv; } #endif /* ENABLE_PKCS11H_DATA */ #if defined(ENABLE_PKCS11H_CERTIFICATE) static CK_RV _pkcs11h_enum_getSessionCertificates ( IN const pkcs11h_session_t session ) { PKCS11H_BOOL fOpSuccess = FALSE; PKCS11H_BOOL fLoginRetry = FALSE; 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 */ 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)} }; CK_OBJECT_HANDLE *objects = NULL; CK_ULONG objects_found = 0; CK_ULONG i; if (rv == CKR_OK) { rv = _pkcs11h_validateSession (session); } 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} }; if (rv == CKR_OK) { rv = _pkcs11h_getObjectAttributes ( session, objects[i], attrs, sizeof (attrs) / sizeof (CK_ATTRIBUTE) ); } if ( rv == CKR_OK && (rv = _pkcs11h_newCertificateId (&certificate_id)) == CKR_OK ) { rv = pkcs11h_duplicateTokenId ( &certificate_id->token_id, session->token_id ); } if (rv == CKR_OK) { rv = _pkcs11h_dupmem ( (void*)&certificate_id->attrCKA_ID, &certificate_id->attrCKA_ID_size, attrs[0].pValue, attrs[0].ulValueLen ); } if (rv == CKR_OK) { rv = _pkcs11h_dupmem ( (void*)&certificate_id->certificate_blob, &certificate_id->certificate_blob_size, attrs[1].pValue, attrs[1].ulValueLen ); } if (rv == CKR_OK) { rv = _pkcs11h_updateCertificateIdDescription (certificate_id); } 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 (certificate_id != NULL) { pkcs11h_freeCertificateId (certificate_id); certificate_id = NULL; } if (new_element != NULL) { _pkcs11h_free ((void *)&new_element); new_element = NULL; } _pkcs11h_freeObjectAttributes ( attrs, sizeof (attrs) / sizeof (CK_ATTRIBUTE) ); 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; } } if (objects != NULL) { _pkcs11h_free ((void *)&objects); } 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) ); rv = _pkcs11h_login ( session, TRUE, TRUE, PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT ); fLoginRetry = TRUE; } } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_enum_getSessionCertificates return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv; } 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 ) { typedef struct info_s { struct info_s *next; pkcs11h_certificate_id_t e; X509 *x509; PKCS11H_BOOL fIsIssuer; } *info_t; pkcs11h_certificate_id_list_t cert_id_issuers_list = NULL; pkcs11h_certificate_id_list_t cert_id_end_list = NULL; info_t head = NULL; info_t info = NULL; CK_RV rv = CKR_OK; /*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); 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 (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) { 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) { 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) { 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) { while (head != NULL) { info_t entry = head; head = head->next; if (entry->x509 != NULL) { X509_free (entry->x509); entry->x509 = NULL; } _pkcs11h_free ((void *)&entry); } } 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 (rv == CKR_OK) { *p_cert_id_end_list = cert_id_end_list; cert_id_end_list = NULL; } 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) ); return rv; } CK_RV pkcs11h_freeCertificateIdList ( IN const pkcs11h_certificate_id_list_t cert_id_list ) { pkcs11h_certificate_id_list_t _id = cert_id_list; PKCS11H_ASSERT (s_pkcs11h_data!=NULL); PKCS11H_ASSERT (s_pkcs11h_data->fInitialized); /*PKCS11H_ASSERT (cert_id_list!=NULL); NOT NEEDED*/ PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_freeCertificateIdList entry cert_id_list=%p", (void *)cert_id_list ); 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); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_freeCertificateIdList return" ); return CKR_OK; } 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 ) { #if defined(ENABLE_PKCS11H_THREADING) PKCS11H_BOOL fMutexLocked = FALSE; #endif 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_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 ); if (p_cert_id_issuers_list != NULL) { *p_cert_id_issuers_list = NULL; } *p_cert_id_end_list = NULL; #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 && (rv = _pkcs11h_getSessionByTokenId ( token_id, &session )) == CKR_OK ) { 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) { 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) ); 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 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) { rv = CKR_CRYPTOKI_NOT_INITIALIZED; } if (rv == CKR_OK) { 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) { 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; } } 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; } } } } 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) ); return rv; } #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 ) { unsigned long r = 0; size_t i; for (i=0;imanufacturerID ); if (rv == CKR_OK && !provider->fEnabled) { rv = CKR_OPERATION_NOT_INITIALIZED; } if (rv == CKR_OK) { if (provider->nSlotEventPollInterval == 0) { provider->nSlotEventPollInterval = PKCS11H_DEFAULT_SLOTEVENT_POLL; } /* * 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 ( 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 (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; 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 ); 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 (slots != NULL) { _pkcs11h_free ((void *)&slots); } if (!s_pkcs11h_data->fSlotEventShouldTerminate) { _pkcs11h_sleep (provider->nSlotEventPollInterval); } } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_provider provider='%s' return", provider->manufacturerID ); return NULL; } static void * _pkcs11h_slotevent_manager ( IN void *p ) { PKCS11H_BOOL fFirst = TRUE; (void)p; PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_manager entry" ); /* * 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 ( fFirst || /* Must enter wait or mutex will never be free */ !s_pkcs11h_data->fSlotEventShouldTerminate ) { pkcs11h_provider_t current_provider; fFirst = FALSE; /* * Start each provider thread * if not already started. * This is required in order to allow * adding new providers. */ for ( current_provider = s_pkcs11h_data->providers; current_provider != NULL; current_provider = current_provider->next ) { 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); } } } 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; } else { PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG1, "PKCS#11: Calling slotevent hook" ); s_pkcs11h_data->hooks.slotevent (s_pkcs11h_data->hooks.slotevent_data); } } { pkcs11h_provider_t current_provider; 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); } } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_manager return" ); return NULL; } static CK_RV _pkcs11h_slotevent_init () { CK_RV rv = CKR_OK; PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_init entry" ); if (!s_pkcs11h_data->fSlotEventInitialized) { if (rv == CKR_OK) { rv = _pkcs11h_condInit (&s_pkcs11h_data->condSlotEvent); } if (rv == CKR_OK) { rv = _pkcs11h_threadStart ( &s_pkcs11h_data->threadSlotEvent, _pkcs11h_slotevent_manager, NULL ); } if (rv == CKR_OK) { s_pkcs11h_data->fSlotEventInitialized = TRUE; } } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_init return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv; } static CK_RV _pkcs11h_slotevent_notify () { PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_notify entry" ); if (s_pkcs11h_data->fSlotEventInitialized) { s_pkcs11h_data->fSlotEventSkipEvent = TRUE; _pkcs11h_condSignal (&s_pkcs11h_data->condSlotEvent); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_notify return" ); return CKR_OK; } static CK_RV _pkcs11h_slotevent_terminate () { 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; } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_slotevent_terminate return" ); return CKR_OK; } #endif #if defined(ENABLE_PKCS11H_OPENSSL) /*======================================================================* * OPENSSL INTERFACE *======================================================================*/ static pkcs11h_openssl_session_t _pkcs11h_openssl_get_openssl_session ( IN OUT const RSA *rsa ) { pkcs11h_openssl_session_t session; 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 PKCS11H_ASSERT (session!=NULL); return session; } static pkcs11h_certificate_t _pkcs11h_openssl_get_pkcs11h_certificate ( IN OUT const RSA *rsa ) { pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_openssl_session (rsa); PKCS11H_ASSERT (session!=NULL); PKCS11H_ASSERT (session->certificate!=NULL); return session->certificate; } #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 ) { #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 ) { #endif PKCS11H_ASSERT (from!=NULL); PKCS11H_ASSERT (to!=NULL); PKCS11H_ASSERT (rsa!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d", flen, from, to, (void *)rsa, padding ); PKCS11H_LOG ( PKCS11H_LOG_ERROR, "PKCS#11: Private key decryption is not supported" ); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_dec return" ); return -1; } #if OPENSSL_VERSION_NUMBER < 0x00907000L 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_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 pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa); CK_RV rv = CKR_OK; int myrsa_size = 0; unsigned char *enc_alloc = NULL; unsigned char *enc = NULL; int enc_len = 0; PKCS11H_ASSERT (m!=NULL); PKCS11H_ASSERT (sigret!=NULL); PKCS11H_ASSERT (siglen!=NULL); 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, m_len, sigret, (void *)siglen, (void *)rsa ); if (rv == CKR_OK) { myrsa_size=RSA_size(rsa); } if (type == NID_md5_sha1) { if (rv == CKR_OK) { enc = (unsigned char *)m; enc_len = m_len; } } else { X509_SIG sig; ASN1_TYPE parameter; X509_ALGOR algor; ASN1_OCTET_STRING digest; if ( rv == CKR_OK && (rv = _pkcs11h_malloc ((void*)&enc, myrsa_size+1)) == CKR_OK ) { enc_alloc = enc; } if (rv == CKR_OK) { sig.algor = &algor; } if ( rv == CKR_OK && (sig.algor->algorithm = OBJ_nid2obj (type)) == NULL ) { rv = CKR_FUNCTION_FAILED; } if ( rv == CKR_OK && sig.algor->algorithm->length == 0 ) { rv = CKR_KEY_SIZE_RANGE; } if (rv == CKR_OK) { parameter.type = V_ASN1_NULL; parameter.value.ptr = NULL; sig.algor->parameter = ¶meter; 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 ) { rv = CKR_FUNCTION_FAILED; } if (rv == CKR_OK) { unsigned char *p = enc; i2d_X509_SIG (&sig, &p); } } if ( rv == CKR_OK && enc_len > (myrsa_size-RSA_PKCS1_PADDING_SIZE) ) { rv = CKR_KEY_SIZE_RANGE; } if (rv == CKR_OK) { PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG1, "PKCS#11: Performing signature" ); *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) { _pkcs11h_free ((void *)&enc_alloc); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_sign - return rv=%ld-'%s'", rv, pkcs11h_getMessage (rv) ); return rv == CKR_OK ? 1 : -1; } static int _pkcs11h_openssl_finish ( IN OUT RSA *rsa ) { pkcs11h_openssl_session_t openssl_session = _pkcs11h_openssl_get_openssl_session (rsa); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_finish - entered rsa=%p", (void *)rsa ); RSA_set_app_data (rsa, NULL); if (openssl_session->orig_finish != NULL) { openssl_session->orig_finish (rsa); #ifdef BROKEN_OPENSSL_ENGINE { /* We get called TWICE here, once for * releasing the key and also for * releasing the engine. * To prevent endless recursion, FIRST * clear rsa->engine, THEN call engine->finish */ ENGINE *e = rsa->engine; rsa->engine = NULL; if (e) { ENGINE_finish(e); } } #endif } pkcs11h_openssl_freeSession (openssl_session); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: _pkcs11h_openssl_finish - return" ); return 1; } pkcs11h_openssl_session_t pkcs11h_openssl_createSession ( IN const pkcs11h_certificate_t certificate ) { pkcs11h_openssl_session_t openssl_session = NULL; PKCS11H_BOOL fOK = TRUE; PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_createSession - entry" ); if ( fOK && _pkcs11h_malloc ( (void*)&openssl_session, sizeof (struct pkcs11h_openssl_session_s)) != CKR_OK ) { fOK = FALSE; PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate memory"); } if (fOK) { const RSA_METHOD *def = RSA_get_default_method(); 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) { _pkcs11h_free ((void *)&openssl_session); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_createSession - return openssl_session=%p", (void *)openssl_session ); return openssl_session; } void pkcs11h_openssl_freeSession ( IN const pkcs11h_openssl_session_t openssl_session ) { PKCS11H_ASSERT (openssl_session!=NULL); PKCS11H_ASSERT (openssl_session->nReferenceCount>0); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_freeSession - entry openssl_session=%p, count=%d", (void *)openssl_session, openssl_session->nReferenceCount ); openssl_session->nReferenceCount--; if (openssl_session->nReferenceCount == 0) { if (openssl_session->x509 != NULL) { X509_free (openssl_session->x509); openssl_session->x509 = NULL; } if (openssl_session->certificate != NULL) { pkcs11h_freeCertificate (openssl_session->certificate); openssl_session->certificate = NULL; } _pkcs11h_free ((void *)&openssl_session); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_freeSession - return" ); } RSA * pkcs11h_openssl_getRSA ( IN const pkcs11h_openssl_session_t openssl_session ) { X509 *x509 = NULL; RSA *rsa = NULL; EVP_PKEY *pubkey = NULL; CK_RV rv = CKR_OK; pkcs11_openssl_d2i_t d2i1 = NULL; PKCS11H_BOOL fOK = TRUE; PKCS11H_ASSERT (openssl_session!=NULL); PKCS11H_ASSERT (!openssl_session->fInitialized); PKCS11H_ASSERT (openssl_session!=NULL); 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; PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to allocate certificate object"); } if ( fOK && (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)openssl_session->certificate->id->certificate_blob; if ( fOK && !d2i_X509 (&x509, &d2i1, openssl_session->certificate->id->certificate_blob_size) ) { 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; PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get public key"); } if ( fOK && pubkey->type != EVP_PKEY_RSA ) { fOK = FALSE; PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Invalid public key algorithm"); } if ( fOK && (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL ) { fOK = FALSE; PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get RSA key"); } if (fOK) { 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) { rsa->engine = ENGINE_get_default_RSA(); } 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) { /* * dup x509 so that it won't hold RSA */ openssl_session->x509 = X509_dup (x509); rsa->flags |= RSA_FLAG_SIGN_VER; openssl_session->fInitialized = TRUE; } else { if (rsa != NULL) { RSA_free (rsa); rsa = NULL; } } /* * openssl objects have reference * count, so release them */ if (pubkey != NULL) { EVP_PKEY_free (pubkey); pubkey = NULL; } if (x509 != NULL) { X509_free (x509); x509 = NULL; } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_getRSA - return rsa=%p", (void *)rsa ); return rsa; } X509 * pkcs11h_openssl_getX509 ( IN const pkcs11h_openssl_session_t openssl_session ) { X509 *x509 = NULL; PKCS11H_ASSERT (openssl_session!=NULL); PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_getX509 - entry openssl_session=%p", (void *)openssl_session ); if (openssl_session->x509 != NULL) { x509 = X509_dup (openssl_session->x509); } PKCS11H_DEBUG ( PKCS11H_LOG_DEBUG2, "PKCS#11: pkcs11h_openssl_getX509 - return x509=%p", (void *)x509 ); return x509; } #endif /* ENABLE_PKCS11H_OPENSSL */ #if defined(ENABLE_PKCS11H_STANDALONE) /*======================================================================* * STANDALONE INTERFACE *======================================================================*/ void pkcs11h_standalone_dump_slots ( IN const pkcs11h_output_print_t my_output, IN const void *pData, IN const char * const provider ) { CK_RV rv = CKR_OK; pkcs11h_provider_t pkcs11h_provider; PKCS11H_ASSERT (my_output!=NULL); /*PKCS11H_ASSERT (pData) NOT NEEDED */ PKCS11H_ASSERT (provider!=NULL); if ( rv == CKR_OK && (rv = pkcs11h_initialize ()) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); } if ( rv == 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)); } /* * our provider is head */ if (rv == CKR_OK) { 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; } } if (rv == CKR_OK) { CK_INFO info; if ((rv = pkcs11h_provider->f->C_GetInfo (&info)) != CKR_OK) { my_output (pData, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); rv = CKR_OK; } else { char szManufacturerID[sizeof (info.manufacturerID)+1]; _pkcs11h_fixupFixedString ( szManufacturerID, (char *)info.manufacturerID, sizeof (info.manufacturerID) ); my_output ( pData, ( "Provider Information:\n" "\tcryptokiVersion:\t%u.%u\n" "\tmanufacturerID:\t\t%s\n" "\tflags:\t\t\t%d\n" "\n" ), info.cryptokiVersion.major, info.cryptokiVersion.minor, szManufacturerID, (unsigned)info.flags ); } } if (rv == CKR_OK) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slotnum; CK_SLOT_ID slot_index; if ( _pkcs11h_getSlotList ( pkcs11h_provider, CK_FALSE, &slots, &slotnum ) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot get slot list %ld-'%s'\n", rv, pkcs11h_getMessage (rv)); } else { my_output ( pData, ( "The following slots are available for use with this provider.\n" "Each slot shown below may be used as a parameter to a\n" "%s and %s options.\n" "\n" "Slots: (id - name)\n" ), PKCS11H_PRM_SLOT_TYPE, PKCS11H_PRM_SLOT_ID ); for (slot_index=0;slot_index < slotnum;slot_index++) { CK_SLOT_INFO info; if ( (rv = pkcs11h_provider->f->C_GetSlotInfo ( slots[slot_index], &info )) == CKR_OK ) { char szCurrentName[sizeof (info.slotDescription)+1]; _pkcs11h_fixupFixedString ( szCurrentName, (char *)info.slotDescription, sizeof (info.slotDescription) ); my_output (pData, "\t%lu - %s\n", slots[slot_index], szCurrentName); } } } if (slots != NULL) { _pkcs11h_free ((void *)&slots); } } pkcs11h_terminate (); } static PKCS11H_BOOL _pkcs11h_standalone_dump_objects_pin_prompt ( IN const void *pData, IN const pkcs11h_token_id_t token, IN const unsigned retry, OUT char * const szPIN, IN const size_t nMaxPIN ) { /* * Don't lock card */ if (retry == 0) { strncpy (szPIN, (char *)pData, nMaxPIN); return TRUE; } else { return FALSE; } } 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; 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; } } if (rv == CKR_OK) { CK_TOKEN_INFO info; if ( (rv = pkcs11h_provider->f->C_GetTokenInfo ( s, &info )) != 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 { char szLabel[sizeof (info.label)+1]; char szManufacturerID[sizeof (info.manufacturerID)+1]; char szModel[sizeof (info.model)+1]; char szSerialNumber[sizeof (info.serialNumber)+1]; _pkcs11h_fixupFixedString ( szLabel, (char *)info.label, sizeof (info.label) ); _pkcs11h_fixupFixedString ( szManufacturerID, (char *)info.manufacturerID, sizeof (info.manufacturerID) ); _pkcs11h_fixupFixedString ( szModel, (char *)info.model, sizeof (info.model) ); _pkcs11h_fixupFixedString ( szSerialNumber, (char *)info.serialNumber, sizeof (info.serialNumber) ); my_output ( pData, ( "Token Information:\n" "\tlabel:\t\t%s\n" "\tmanufacturerID:\t%s\n" "\tmodel:\t\t%s\n" "\tserialNumber:\t%s\n" "\tflags:\t\t%08x\n" "\n" "You can access this token using\n" "%s \"label\" %s \"%s\" options.\n" "\n" ), szLabel, szManufacturerID, szModel, szSerialNumber, (unsigned)info.flags, 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 (token_id != NULL) { if ( (rv = _pkcs11h_getSessionByTokenId ( token_id, &session )) != CKR_OK ) { my_output (pData, "PKCS#11: Cannot session for token '%s' %ld-'%s'\n", token_id->label, rv, pkcs11h_getMessage (rv)); rv = CKR_OK; } } 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 ( _pkcs11h_getObjectAttributes ( session, objects[i], attrs, sizeof (attrs) / sizeof (CK_ATTRIBUTE) ) == CKR_OK ) { if (attrs_class == CKO_CERTIFICATE) { CK_ATTRIBUTE attrs_cert[] = { {CKA_ID, NULL, 0}, {CKA_LABEL, NULL, 0}, {CKA_VALUE, NULL, 0} }; unsigned char *attrs_id = NULL; int attrs_id_size = 0; unsigned char *attrs_value = NULL; int attrs_value_size = 0; char *attrs_label = NULL; char szHexId[1024]; char szSubject[1024]; char szSerial[1024]; char szNotBefore[1024]; szSubject[0] = '\0'; szSerial[0] = '\0'; szNotBefore[0] = '\0'; if ( _pkcs11h_getObjectAttributes ( session, objects[i], attrs_cert, sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE) ) == CKR_OK && _pkcs11h_malloc ( (void *)&attrs_label, attrs_cert[1].ulValueLen+1 ) == CKR_OK ) { 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" ); } if (attrs_value != NULL) { X509 *x509 = NULL; BIO *bioSerial = NULL; if ((x509 = X509_new ()) == NULL) { my_output (pData, "Cannot create x509 context\n"); } 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'; } 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; } } 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, sizeof (sign)}, {CKA_SIGN_RECOVER, &sign_recover, sizeof (sign_recover)} }; 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_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() { SSL_library_init(); ENGINE_load_openssl(); ENGINE_register_all_RSA(); } #endif #else static void dummy (void) {} #endif /* PKCS11H_HELPER_ENABLE */