/*
* Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev@gmail.com>
* All rights reserved.
*
* 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).
*
*/
#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 <openssl/engine.h>
# if OPENSSL_VERSION_NUMBER < 0x0090704fL
# define BROKEN_OPENSSL_ENGINE
# endif
# 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;
int nMaxLoginRetries;
#if defined(ENABLE_PKCS11H_THREADING)
pkcs11h_mutex_t mutexGlobal;
pkcs11h_mutex_t mutexSession;
pkcs11h_mutex_t mutexCache;
#endif
#if defined(ENABLE_PKCS11H_SLOTEVENT)
PKCS11H_BOOL fSlotEventInitialized;
PKCS11H_BOOL fSlotEventShouldTerminate;
PKCS11H_BOOL fSlotEventSkipEvent;
pkcs11h_cond_t condSlotEvent;
pkcs11h_thread_t threadSlotEvent;
#endif
};
#if defined(ENABLE_PKCS11H_OPENSSL)
struct pkcs11h_openssl_session_s {
int nReferenceCount;
PKCS11H_BOOL fInitialized;
X509 *x509;
RSA_METHOD smart_rsa;
int (*orig_finish)(RSA *rsa);
pkcs11h_certificate_t certificate;
};
#endif
/*======================================================================*
* MEMORY INTERFACE
*======================================================================*/
static
CK_RV
_pkcs11h_malloc (
OUT const void ** const p,
IN const size_t s
);
static
CK_RV
_pkcs11h_free (
IN const void ** const p
);
static
CK_RV
_pkcs11h_dupmem (
OUT const void ** const dest,
OUT size_t * const dest_size,
IN const void * const src,
IN const size_t mem_size
);
#if defined(ENABLE_PKCS11H_THREADING)
/*======================================================================*
* THREADING INTERFACE
*======================================================================*/
static
void
_pkcs11h_sleep (
IN const unsigned milli
);
static
CK_RV
_pkcs11h_mutexInit (
OUT pkcs11h_mutex_t * const mutex
);
static
CK_RV
_pkcs11h_mutexLock (
IN OUT pkcs11h_mutex_t *const mutex
);
static
CK_RV
_pkcs11h_mutexRelease (
IN OUT pkcs11h_mutex_t *const mutex
);
static
CK_RV
_pkcs11h_mutexFree (
IN OUT pkcs11h_mutex_t *const mutex
);
#if !defined(WIN32)
static
void
__pkcs1h_mutexLockAll ();
static
void
__pkcs1h_mutexReleaseAll ();
#endif
static
CK_RV
_pkcs11h_condSignal (
IN OUT pkcs11h_cond_t *const cond
);
static
CK_RV
_pkcs11h_condInit (
OUT pkcs11h_cond_t * const cond
);
static
CK_RV
_pkcs11h_condWait (
IN OUT pkcs11h_cond_t *const cond,
IN const unsigned milli
);
static
CK_RV
_pkcs11h_condFree (
IN OUT pkcs11h_cond_t *const cond
);
static
CK_RV
_pkcs11h_threadStart (
OUT pkcs11h_thread_t * const thread,
IN pkcs11h_thread_start_t const start,
IN void * data
);
static
CK_RV
_pkcs11h_threadJoin (
IN pkcs11h_thread_t * const thread
);
#endif /* ENABLE_PKCS11H_THREADING */
/*======================================================================*
* COMMON INTERNAL INTERFACE
*======================================================================*/
static
void
_pkcs11h_fixupFixedString (
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
);
static
PKCS11H_BOOL
_pkcs11h_hooks_default_pin_prompt (
IN const void * pData,
IN const pkcs11h_token_id_t token,
OUT char * const szPIN,
IN const size_t nMaxPIN
);
#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 int nMaxLoginRetries
) {
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
s_pkcs11h_data->nMaxLoginRetries = nMaxLoginRetries;
return CKR_OK;
}
CK_RV
pkcs11h_setProtectedAuthentication (
IN const PKCS11H_BOOL fProtectedAuthentication
) {
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
s_pkcs11h_data->fProtectedAuthentication = fProtectedAuthentication;
return CKR_OK;
}
CK_RV
pkcs11h_addProvider (
IN const char * const szReferenceName,
IN const char * const szProvider,
IN const PKCS11H_BOOL fProtectedAuthentication,
IN const unsigned maskSignMode,
IN const int nSlotEventMethod,
IN const int nSlotEventPollInterval,
IN const PKCS11H_BOOL fCertIsPrivate
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
#if defined(WIN32)
int mypid = 0;
#else
pid_t mypid = getpid ();
#endif
pkcs11h_provider_t provider = NULL;
CK_C_GetFunctionList gfl = NULL;
CK_INFO info;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (szProvider!=NULL);
/*PKCS11H_ASSERT (szSignMode!=NULL); NOT NEEDED*/
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_addProvider entry pid=%d, szReferenceName=%s, szProvider='%s', fProtectedAuthentication=%d, maskSignMode=%08x, fCertIsPrivate=%d",
mypid,
szReferenceName,
szProvider,
fProtectedAuthentication ? 1 : 0,
maskSignMode,
fCertIsPrivate ? 1 : 0
);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Adding provider '%s'-'%s'",
szReferenceName,
szProvider
);
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (
rv == CKR_OK &&
(rv = _pkcs11h_malloc ((void *)&provider, sizeof (struct pkcs11h_provider_s))) == CKR_OK
) {
strncpy (
provider->szReferenceName,
szReferenceName,
sizeof (provider->szReferenceName)-1
);
provider->szReferenceName[sizeof (provider->szReferenceName)-1] = '\x0';
strncpy (
provider->manufacturerID,
(
strlen (szProvider) < sizeof (provider->manufacturerID) ?
szProvider :
szProvider+strlen (szProvider)-sizeof (provider->manufacturerID)+1
),
sizeof (provider->manufacturerID)-1
);
provider->manufacturerID[sizeof (provider->manufacturerID)-1] = '\x0';
provider->fProtectedAuthentication = fProtectedAuthentication;
provider->maskSignMode = maskSignMode;
provider->nSlotEventMethod = nSlotEventMethod;
provider->nSlotEventPollInterval = nSlotEventPollInterval;
provider->fCertIsPrivate = fCertIsPrivate;
}
if (rv == CKR_OK) {
#if defined(WIN32)
provider->hLibrary = LoadLibraryA (szProvider);
#else
provider->hLibrary = dlopen (szProvider, RTLD_NOW);
#endif
if (provider->hLibrary == NULL) {
rv = CKR_FUNCTION_FAILED;
}
}
if (rv == CKR_OK) {
#if defined(WIN32)
gfl = (CK_C_GetFunctionList)GetProcAddress (
provider->hLibrary,
"C_GetFunctionList"
);
#else
/*
* Make compiler happy!
*/
void *p = dlsym (
provider->hLibrary,
"C_GetFunctionList"
);
memmove (
&gfl,
&p,
sizeof (void *)
);
#endif
if (gfl == NULL) {
rv = CKR_FUNCTION_FAILED;
}
}
if (rv == CKR_OK) {
rv = gfl (&provider->f);
}
if (rv == CKR_OK) {
if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) {
if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) {
rv = CKR_OK;
}
}
else {
provider->fShouldFinalize = TRUE;
}
}
if (
rv == CKR_OK &&
(rv = provider->f->C_GetInfo (&info)) == CKR_OK
) {
_pkcs11h_fixupFixedString (
provider->manufacturerID,
(char *)info.manufacturerID,
sizeof (info.manufacturerID)
);
}
if (rv == CKR_OK) {
provider->fEnabled = TRUE;
}
if (provider != NULL) {
if (s_pkcs11h_data->providers == NULL) {
s_pkcs11h_data->providers = provider;
}
else {
pkcs11h_provider_t last = NULL;
for (
last = s_pkcs11h_data->providers;
last->next != NULL;
last = last->next
);
last->next = provider;
}
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal);
fMutexLocked = FALSE;
}
#endif
#if defined(ENABLE_PKCS11H_SLOTEVENT)
_pkcs11h_slotevent_notify ();
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Provider '%s' added rv=%ld-'%s'",
szReferenceName,
rv,
pkcs11h_getMessage (rv)
);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
CK_RV
pkcs11h_removeProvider (
IN const char * const szReferenceName
) {
#if defined(ENABLE_PKCS11H_THREADING)
pkcs11h_session_t current_session = NULL;
#endif
pkcs11h_provider_t provider = NULL;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (szReferenceName!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_removeProvider entry szReferenceName='%s'",
szReferenceName
);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Removing provider '%s'",
szReferenceName
);
#if defined(ENABLE_PKCS11H_THREADING)
_pkcs11h_mutexLock (&s_pkcs11h_data->mutexCache);
_pkcs11h_mutexLock (&s_pkcs11h_data->mutexSession);
_pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal);
for (
current_session = s_pkcs11h_data->sessions;
current_session != NULL;
current_session = current_session->next
) {
_pkcs11h_mutexLock (¤t_session->mutexSession);
}
#endif
provider = s_pkcs11h_data->providers;
while (
rv == CKR_OK &&
provider != NULL &&
strcmp (szReferenceName, provider->szReferenceName)
) {
provider = provider->next;
}
if (rv == CKR_OK && provider == NULL) {
rv = CKR_OBJECT_HANDLE_INVALID;
}
if (rv == CKR_OK) {
provider->fEnabled = FALSE;
provider->szReferenceName[0] = '\0';
if (provider->fShouldFinalize) {
provider->f->C_Finalize (NULL);
provider->fShouldFinalize = FALSE;
}
#if defined(ENABLE_PKCS11H_SLOTEVENT)
_pkcs11h_slotevent_notify ();
/*
* Wait until manager join this thread
* this happens saldom so I can poll
*/
while (provider->threadSlotEvent != PKCS11H_THREAD_NULL) {
_pkcs11h_sleep (500);
}
#endif
if (provider->f != NULL) {
provider->f = NULL;
}
if (provider->hLibrary != NULL) {
#if defined(WIN32)
FreeLibrary (provider->hLibrary);
#else
dlclose (provider->hLibrary);
#endif
provider->hLibrary = NULL;
}
}
#if defined(ENABLE_PKCS11H_THREADING)
for (
current_session = s_pkcs11h_data->sessions;
current_session != NULL;
current_session = current_session->next
) {
_pkcs11h_mutexRelease (¤t_session->mutexSession);
}
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexCache);
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexSession);
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal);
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_removeProvider return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
CK_RV
pkcs11h_forkFixup () {
#if defined(WIN32)
return CKR_OK;
#else
#if defined(ENABLE_PKCS11H_THREADING)
return CKR_OK;
#else
return _pkcs11h_forkFixup ();
#endif
#endif
}
CK_RV
pkcs11h_plugAndPlay () {
#if defined(WIN32)
int mypid = 0;
#else
pid_t mypid = getpid ();
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_forkFixup entry pid=%d",
mypid
);
if (s_pkcs11h_data != NULL && s_pkcs11h_data->fInitialized) {
pkcs11h_provider_t current;
#if defined(ENABLE_PKCS11H_SLOTEVENT)
PKCS11H_BOOL fSlotEventActive = FALSE;
#endif
#if defined(ENABLE_PKCS11H_THREADING)
_pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal);
#endif
for (
current = s_pkcs11h_data->providers;
current != NULL;
current = current->next
) {
if (current->fEnabled) {
current->f->C_Finalize (NULL);
}
}
#if defined(ENABLE_PKCS11H_SLOTEVENT)
if (s_pkcs11h_data->fSlotEventInitialized) {
fSlotEventActive = TRUE;
_pkcs11h_slotevent_terminate ();
}
#endif
for (
current = s_pkcs11h_data->providers;
current != NULL;
current = current->next
) {
if (current->fEnabled) {
current->f->C_Initialize (NULL);
}
}
#if defined(ENABLE_PKCS11H_SLOTEVENT)
if (fSlotEventActive) {
_pkcs11h_slotevent_init ();
}
#endif
#if defined(ENABLE_PKCS11H_THREADING)
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal);
#endif
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_forkFixup return"
);
return CKR_OK;
}
CK_RV
pkcs11h_freeTokenId (
IN pkcs11h_token_id_t token_id
) {
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_freeTokenId entry certificate_id=%p",
(void *)token_id
);
_pkcs11h_free ((void *)&token_id);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_freeTokenId return"
);
return CKR_OK;
}
CK_RV
pkcs11h_duplicateTokenId (
OUT pkcs11h_token_id_t * const to,
IN const pkcs11h_token_id_t from
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (to!=NULL);
PKCS11H_ASSERT (from!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_duplicateTokenId entry to=%p form=%p",
(void *)to,
(void *)from
);
*to = NULL;
if (rv == CKR_OK) {
rv = _pkcs11h_dupmem (
(void*)to,
NULL,
from,
sizeof (struct pkcs11h_token_id_s)
);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_duplicateTokenId return rv=%ld-'%s', *to=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*to
);
return rv;
}
PKCS11H_BOOL
pkcs11h_sameTokenId (
IN const pkcs11h_token_id_t a,
IN const pkcs11h_token_id_t b
) {
PKCS11H_ASSERT (a!=NULL);
PKCS11H_ASSERT (b!=NULL);
return (
!strcmp (a->manufacturerID, b->manufacturerID) &&
!strcmp (a->model, b->model) &&
!strcmp (a->serialNumber, b->serialNumber)
);
}
/*======================================================================*
* MEMORY INTERFACE
*======================================================================*/
static
CK_RV
_pkcs11h_malloc (
OUT const void ** const p,
IN const size_t s
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (p!=NULL);
PKCS11H_ASSERT (s!=0);
*p = NULL;
if (s > 0) {
if (
(*p = (void *)malloc (s)) == NULL
) {
rv = CKR_HOST_MEMORY;
}
else {
memset ((void *)*p, 0, s);
}
}
return rv;
}
static
CK_RV
_pkcs11h_free (
IN const void ** const p
) {
PKCS11H_ASSERT (p!=NULL);
free ((void *)*p);
*p = NULL;
return CKR_OK;
}
static
CK_RV
_pkcs11h_dupmem (
OUT const void ** const dest,
OUT size_t * const p_dest_size,
IN const void * const src,
IN const size_t mem_size
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (dest!=NULL);
/*PKCS11H_ASSERT (dest_size!=NULL); NOT NEEDED*/
PKCS11H_ASSERT (!(mem_size!=0&&src==NULL));
*dest = NULL;
if (p_dest_size != NULL) {
*p_dest_size = 0;
}
if (src != NULL) {
if (
rv == CKR_OK &&
(rv = _pkcs11h_malloc (dest, mem_size)) == CKR_OK
) {
if (p_dest_size != NULL) {
*p_dest_size = mem_size;
}
memmove ((void*)*dest, src, mem_size);
}
}
return rv;
}
#if defined(ENABLE_PKCS11H_THREADING)
/*======================================================================*
* THREADING INTERFACE
*======================================================================*/
static
void
_pkcs11h_sleep (
IN const unsigned milli
) {
#if defined(WIN32)
Sleep (milli);
#else
usleep (milli*1000);
#endif
}
static
CK_RV
_pkcs11h_mutexInit (
OUT pkcs11h_mutex_t * const mutex
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
if (
rv == CKR_OK &&
(*mutex = CreateMutex (NULL, FALSE, NULL)) == NULL
) {
rv = CKR_FUNCTION_FAILED;
}
#else
{
__pkcs11h_mutex_entry_t entry = NULL;
PKCS11H_BOOL fMutexLocked = FALSE;
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex)) == CKR_OK
) {
fMutexLocked = TRUE;
}
if (rv == CKR_OK) {
rv = _pkcs11h_malloc (
(void *)&entry,
sizeof (struct __pkcs11h_mutex_entry_s)
);
}
if (
rv == CKR_OK &&
pthread_mutex_init (mutex, NULL)
) {
rv = CKR_FUNCTION_FAILED;
}
if (rv == CKR_OK) {
entry->p_mutex = mutex;
entry->next = __s_pkcs11h_mutex_list.head;
__s_pkcs11h_mutex_list.head = entry;
entry = NULL;
}
if (entry != NULL) {
_pkcs11h_free ((void *)&entry);
}
if (fMutexLocked) {
_pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex);
fMutexLocked = FALSE;
}
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_mutexLock (
IN OUT pkcs11h_mutex_t *const mutex
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
if (
rv == CKR_OK &&
WaitForSingleObject (*mutex, INFINITE) == WAIT_FAILED
) {
rv = CKR_FUNCTION_FAILED;
}
#else
if (
rv == CKR_OK &&
pthread_mutex_lock (mutex)
) {
rv = CKR_FUNCTION_FAILED;
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_mutexRelease (
IN OUT pkcs11h_mutex_t *const mutex
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
if (
rv == CKR_OK &&
!ReleaseMutex (*mutex)
) {
rv = CKR_FUNCTION_FAILED;
}
#else
if (
rv == CKR_OK &&
pthread_mutex_unlock (mutex)
) {
rv = CKR_FUNCTION_FAILED;
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_mutexFree (
IN OUT pkcs11h_mutex_t *const mutex
) {
#if defined(WIN32)
if (*mutex != NULL) {
CloseHandle (*mutex);
*mutex = NULL;
}
#else
{
__pkcs11h_mutex_entry_t last = NULL;
__pkcs11h_mutex_entry_t entry = NULL;
PKCS11H_BOOL fMutexLocked = FALSE;
if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) {
fMutexLocked = TRUE;
}
entry = __s_pkcs11h_mutex_list.head;
while (
entry != NULL &&
entry->p_mutex != mutex
) {
last = entry;
entry = entry->next;
}
if (entry != NULL) {
if (last == NULL) {
__s_pkcs11h_mutex_list.head = entry->next;
}
else {
last->next = entry->next;
}
_pkcs11h_free ((void *)&entry);
}
pthread_mutex_destroy (mutex);
if (fMutexLocked) {
_pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex);
fMutexLocked = FALSE;
}
}
#endif
return CKR_OK;
}
#if !defined(WIN32)
/*
* This function is required in order
* to lock all mutexes before fork is called,
* and to avoid dedlocks.
* The loop is required because there is no
* way to lock all mutex in one system call...
*/
static
void
__pkcs1h_mutexLockAll () {
__pkcs11h_mutex_entry_t entry = NULL;
PKCS11H_BOOL fMutexLocked = FALSE;
PKCS11H_BOOL fAllLocked = FALSE;
if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) {
fMutexLocked = TRUE;
}
for (
entry = __s_pkcs11h_mutex_list.head;
entry != NULL;
entry = entry->next
) {
entry->fLocked = FALSE;
}
while (!fAllLocked) {
PKCS11H_BOOL fOK = TRUE;
for (
entry = __s_pkcs11h_mutex_list.head;
entry != NULL && fOK;
entry = entry->next
) {
if (!pthread_mutex_trylock (entry->p_mutex)) {
entry->fLocked = TRUE;
}
else {
fOK = FALSE;
}
}
if (!fOK) {
for (
entry = __s_pkcs11h_mutex_list.head;
entry != NULL;
entry = entry->next
) {
if (entry->fLocked == TRUE) {
pthread_mutex_unlock (entry->p_mutex);
entry->fLocked = FALSE;
}
}
_pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex);
_pkcs11h_sleep (1000);
_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex);
}
else {
fAllLocked = TRUE;
}
}
if (fMutexLocked) {
_pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex);
fMutexLocked = FALSE;
}
}
static
void
__pkcs1h_mutexReleaseAll () {
__pkcs11h_mutex_entry_t entry = NULL;
PKCS11H_BOOL fMutexLocked = FALSE;
if (_pkcs11h_mutexLock (&__s_pkcs11h_mutex_list.mutex) == CKR_OK) {
fMutexLocked = TRUE;
}
for (
entry = __s_pkcs11h_mutex_list.head;
entry != NULL;
entry = entry->next
) {
pthread_mutex_unlock (entry->p_mutex);
entry->fLocked = FALSE;
}
if (fMutexLocked) {
_pkcs11h_mutexRelease (&__s_pkcs11h_mutex_list.mutex);
fMutexLocked = FALSE;
}
}
#endif
CK_RV
_pkcs11h_condSignal (
IN OUT pkcs11h_cond_t *const cond
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
if (
rv == CKR_OK &&
!SetEvent (*cond)
) {
rv = CKR_FUNCTION_FAILED;
}
#else
if (
rv == CKR_OK &&
(
pthread_mutex_lock (&cond->mut) ||
pthread_cond_signal (&cond->cond) ||
pthread_mutex_unlock (&cond->mut)
)
) {
rv = CKR_FUNCTION_FAILED;
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_condInit (
OUT pkcs11h_cond_t * const cond
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
if (
rv == CKR_OK &&
(*cond = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL
) {
rv = CKR_FUNCTION_FAILED;
}
#else
if (
rv == CKR_OK &&
(
pthread_mutex_init (&cond->mut, NULL) ||
pthread_cond_init (&cond->cond, NULL) ||
pthread_mutex_lock (&cond->mut)
)
) {
rv = CKR_FUNCTION_FAILED;
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_condWait (
IN OUT pkcs11h_cond_t *const cond,
IN const unsigned milli
) {
CK_RV rv = CKR_OK;
#if defined(WIN32)
DWORD dwMilli;
if (milli == PKCS11H_COND_INFINITE) {
dwMilli = INFINITE;
}
else {
dwMilli = milli;
}
if (
rv == CKR_OK &&
WaitForSingleObject (*cond, dwMilli) == WAIT_FAILED
) {
rv = CKR_FUNCTION_FAILED;
}
#else
if (milli == PKCS11H_COND_INFINITE) {
if (
rv == CKR_OK &&
pthread_cond_wait (&cond->cond, &cond->mut)
) {
rv = CKR_FUNCTION_FAILED;
}
}
else {
struct timeval now;
struct timespec timeout;
if (
rv == CKR_OK &&
gettimeofday (&now, NULL)
) {
rv = CKR_FUNCTION_FAILED;
}
if (rv == CKR_OK) {
timeout.tv_sec = now.tv_sec + milli/1000;
timeout.tv_nsec = now.tv_usec*1000 + milli%1000;
}
if (
rv == CKR_OK &&
pthread_cond_timedwait (&cond->cond, &cond->mut, &timeout)
) {
rv = CKR_FUNCTION_FAILED;
}
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_condFree (
IN OUT pkcs11h_cond_t *const cond
) {
#if defined(WIN32)
CloseHandle (*cond);
*cond = NULL;
#else
pthread_mutex_unlock (&cond->mut);
#endif
return CKR_OK;
}
#if defined(WIN32)
static
unsigned
__stdcall
__pkcs11h_thread_start (void *p) {
__pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
unsigned ret;
ret = (unsigned)_data->start (_data->data);
_pkcs11h_free ((void *)&_data);
return ret;
}
#else
static
void *
__pkcs11h_thread_start (void *p) {
__pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
void *ret;
int i;
/*
* Ignore any signal in
* this thread
*/
for (i=1;i<16;i++) {
signal (i, SIG_IGN);
}
ret = _data->start (_data->data);
_pkcs11h_free ((void *)&_data);
return ret;
}
#endif
static
CK_RV
_pkcs11h_threadStart (
OUT pkcs11h_thread_t * const thread,
IN pkcs11h_thread_start_t const start,
IN void * data
) {
__pkcs11h_thread_data_t *_data = NULL;
CK_RV rv = CKR_OK;
if (rv == CKR_OK) {
rv = _pkcs11h_malloc (
(void *)&_data,
sizeof (__pkcs11h_thread_data_t)
);
}
if (rv == CKR_OK) {
_data->start = start;
_data->data = data;
}
#if defined(WIN32)
{
unsigned tmp;
if (
rv == CKR_OK &&
(*thread = (HANDLE)_beginthreadex (
NULL,
0,
__pkcs11h_thread_start,
_data,
0,
&tmp
)) == NULL
) {
rv = CKR_FUNCTION_FAILED;
}
}
#else
if (
rv == CKR_OK &&
pthread_create (thread, NULL, __pkcs11h_thread_start, _data)
) {
rv = CKR_FUNCTION_FAILED;
}
#endif
return rv;
}
static
CK_RV
_pkcs11h_threadJoin (
IN pkcs11h_thread_t * const thread
) {
#if defined(WIN32)
WaitForSingleObject (*thread, INFINITE);
CloseHandle (*thread);
*thread = NULL;
#else
pthread_join (*thread, NULL);
*thread = 0l;
#endif
return CKR_OK;
}
#endif /* ENABLE_PKCS11H_THREADING */
/*======================================================================*
* COMMON INTERNAL INTERFACE
*======================================================================*/
static
void
_pkcs11h_fixupFixedString (
OUT char * const szTarget, /* MUST BE >= nLength+1 */
IN const char * const szSource,
IN const size_t nLength /* FIXED STRING LENGTH */
) {
char *p;
PKCS11H_ASSERT (szSource!=NULL);
PKCS11H_ASSERT (szTarget!=NULL);
p = szTarget+nLength;
memmove (szTarget, szSource, nLength);
*p = '\0';
p--;
while (p >= szTarget && *p == ' ') {
*p = '\0';
p--;
}
}
static
void
_pkcs11h_log (
IN const unsigned flags,
IN const char * const szFormat,
IN ...
) {
va_list args;
PKCS11H_ASSERT (szFormat!=NULL);
va_start (args, szFormat);
if (
s_pkcs11h_data != NULL &&
s_pkcs11h_data->fInitialized
) {
if (PKCS11H_MSG_LEVEL_TEST (flags)) {
if (s_pkcs11h_data->hooks.log == NULL) {
_pkcs11h_hooks_default_log (
NULL,
flags,
szFormat,
args
);
}
else {
s_pkcs11h_data->hooks.log (
s_pkcs11h_data->hooks.log_data,
flags,
szFormat,
args
);
}
}
}
va_end (args);
}
static
CK_RV
_pkcs11h_getSlotList (
IN const pkcs11h_provider_t provider,
IN const CK_BBOOL tokenPresent,
OUT CK_SLOT_ID_PTR * const pSlotList,
OUT CK_ULONG_PTR pulCount
) {
CK_SLOT_ID_PTR _slots = NULL;
CK_ULONG _slotnum = 0;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (provider!=NULL);
PKCS11H_ASSERT (pSlotList!=NULL);
PKCS11H_ASSERT (pulCount!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getSlotList entry provider=%p, tokenPresent=%d, pSlotList=%p, pulCount=%p",
(void *)provider,
tokenPresent,
(void *)pSlotList,
(void *)pulCount
);
*pSlotList = NULL;
*pulCount = 0;
if (rv == CKR_OK) {
rv = provider->f->C_GetSlotList (
tokenPresent,
NULL_PTR,
&_slotnum
);
}
if (rv == CKR_OK && _slotnum > 0) {
rv = _pkcs11h_malloc ((void *)&_slots, _slotnum * sizeof (CK_SLOT_ID));
}
if (rv == CKR_OK && _slotnum > 0) {
rv = provider->f->C_GetSlotList (
tokenPresent,
_slots,
&_slotnum
);
}
if (rv == CKR_OK) {
*pSlotList = _slots;
_slots = NULL;
*pulCount = _slotnum;
}
if (_slots != NULL) {
_pkcs11h_free ((void *)&_slots);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getSlotList return rv=%ld-'%s' *pulCount=%ld",
rv,
pkcs11h_getMessage (rv),
*pulCount
);
return rv;
}
static
CK_RV
_pkcs11h_getObjectAttributes (
IN const pkcs11h_session_t session,
IN const CK_OBJECT_HANDLE object,
IN OUT const CK_ATTRIBUTE_PTR attrs,
IN const unsigned count
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (attrs!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getObjectAttributes entry session=%p, object=%ld, attrs=%p, count=%d",
(void *)session,
object,
(void *)attrs,
count
);
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (
rv == CKR_OK &&
(rv = session->provider->f->C_GetAttributeValue (
session->hSession,
object,
attrs,
count
)) == CKR_OK
) {
unsigned i;
for (i=0;rv == CKR_OK && i<count;i++) {
if (attrs[i].ulValueLen == (CK_ULONG)-1) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
}
else {
rv = _pkcs11h_malloc (
(void *)&attrs[i].pValue,
attrs[i].ulValueLen
);
}
}
}
if (rv == CKR_OK) {
rv = session->provider->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;i<count;i++) {
if (attrs[i].pValue != NULL) {
_pkcs11h_free ((void *)&attrs[i].pValue);
attrs[i].pValue = NULL;
}
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_freeObjectAttributes return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
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
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
PKCS11H_BOOL fShouldFindObjectFinal = FALSE;
CK_OBJECT_HANDLE *objects = NULL;
CK_ULONG objects_size = 0;
CK_OBJECT_HANDLE objects_buffer[100];
CK_ULONG objects_found;
CK_OBJECT_HANDLE oLast = PKCS11H_INVALID_OBJECT_HANDLE;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (session!=NULL);
PKCS11H_ASSERT (!(filter==NULL && filter_attrs!=0) || filter!=NULL);
PKCS11H_ASSERT (p_objects!=NULL);
PKCS11H_ASSERT (p_objects_found!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_findObjects entry session=%p, filter=%p, filter_attrs=%ld, p_objects=%p, p_objects_found=%p",
(void *)session,
(void *)filter,
filter_attrs,
(void *)p_objects,
(void *)p_objects_found
);
*p_objects = NULL;
*p_objects_found = 0;
#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_FindObjectsInit (
session->hSession,
(CK_ATTRIBUTE *)filter,
filter_attrs
)) == CKR_OK
) {
fShouldFindObjectFinal = TRUE;
}
while (
rv == CKR_OK &&
(rv = session->provider->f->C_FindObjects (
session->hSession,
objects_buffer,
sizeof (objects_buffer) / sizeof (CK_OBJECT_HANDLE),
&objects_found
)) == CKR_OK &&
objects_found > 0
) {
CK_OBJECT_HANDLE *temp = NULL;
/*
* Begin workaround
*
* Workaround iKey bug
* It returns the same objects over and over
*/
if (oLast == objects_buffer[0]) {
PKCS11H_LOG (
PKCS11H_LOG_WARN,
"PKCS#11: Bad PKCS#11 C_FindObjects implementation detected, workaround applied"
);
break;
}
oLast = objects_buffer[0];
/* End workaround */
if (
(rv = _pkcs11h_malloc (
(void *)&temp,
(objects_size+objects_found) * sizeof (CK_OBJECT_HANDLE)
)) == CKR_OK
) {
if (objects != NULL) {
memmove (
temp,
objects,
objects_size * sizeof (CK_OBJECT_HANDLE)
);
}
memmove (
temp + objects_size,
objects_buffer,
objects_found * sizeof (CK_OBJECT_HANDLE)
);
}
if (rv == CKR_OK) {
_pkcs11h_free ((void *)&objects);
objects = temp;
objects_size += objects_found;
temp = NULL;
}
if (temp != NULL) {
_pkcs11h_free ((void *)&temp);
temp = NULL;
}
}
if (fShouldFindObjectFinal) {
session->provider->f->C_FindObjectsFinal (
session->hSession
);
fShouldFindObjectFinal = FALSE;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
*p_objects = objects;
*p_objects_found = objects_size;
objects = NULL;
objects_size = 0;
}
if (objects != NULL) {
_pkcs11h_free ((void *)&objects);
objects = NULL;
objects_size = 0;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_findObjects return rv=%ld-'%s', *p_objects_found=%ld",
rv,
pkcs11h_getMessage (rv),
*p_objects_found
);
return rv;
}
static
CK_RV
_pkcs11h_getTokenId (
IN const CK_TOKEN_INFO_PTR info,
OUT pkcs11h_token_id_t * const p_token_id
) {
pkcs11h_token_id_t token_id;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (info!=NULL);
PKCS11H_ASSERT (p_token_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getTokenId entry p_token_id=%p",
(void *)p_token_id
);
*p_token_id = NULL;
if (
rv == CKR_OK &&
(rv = _pkcs11h_newTokenId (&token_id)) == CKR_OK
) {
_pkcs11h_fixupFixedString (
token_id->label,
(char *)info->label,
sizeof (info->label)
);
_pkcs11h_fixupFixedString (
token_id->manufacturerID,
(char *)info->manufacturerID,
sizeof (info->manufacturerID)
);
_pkcs11h_fixupFixedString (
token_id->model,
(char *)info->model,
sizeof (info->model)
);
_pkcs11h_fixupFixedString (
token_id->serialNumber,
(char *)info->serialNumber,
sizeof (info->serialNumber)
);
}
if (rv == CKR_OK) {
*p_token_id = token_id;
token_id = NULL;
}
if (token_id != NULL) {
_pkcs11h_free ((void *)&token_id);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getTokenId return rv=%ld-'%s', *p_token_id=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_token_id
);
return rv;
}
static
CK_RV
_pkcs11h_newTokenId (
OUT pkcs11h_token_id_t * const p_token_id
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (p_token_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_newTokenId entry p_token_id=%p",
(void *)p_token_id
);
*p_token_id = NULL;
if (rv == CKR_OK) {
rv = _pkcs11h_malloc ((void *)p_token_id, sizeof (struct pkcs11h_token_id_s));
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_newTokenId return rv=%ld-'%s', *p_token_id=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_token_id
);
return rv;
}
static
CK_RV
_pkcs11h_getSessionByTokenId (
IN const pkcs11h_token_id_t token_id,
OUT pkcs11h_session_t * const p_session
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
pkcs11h_session_t session = NULL;
PKCS11H_BOOL fNewSession = FALSE;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_ASSERT (p_session!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getSessionByTokenId entry token_id=%p, p_session=%p",
(void *)token_id,
(void *)p_session
);
*p_session = NULL;
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&s_pkcs11h_data->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
pkcs11h_session_t current_session;
for (
current_session = s_pkcs11h_data->sessions;
current_session != NULL && session == NULL;
current_session = current_session->next
) {
if (
pkcs11h_sameTokenId (
current_session->token_id,
token_id
)
) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Using cached session"
);
session = current_session;
session->nReferenceCount++;
}
}
}
if (
rv == CKR_OK &&
session == NULL
) {
fNewSession = TRUE;
}
if (fNewSession) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Creating a new session"
);
if (
rv == CKR_OK &&
(rv = _pkcs11h_malloc ((void *)&session, sizeof (struct pkcs11h_session_s))) == CKR_OK
) {
session->nReferenceCount = 1;
session->hSession = PKCS11H_INVALID_SESSION_HANDLE;
session->nPINCachePeriod = s_pkcs11h_data->nPINCachePeriod;
}
if (rv == CKR_OK) {
rv = pkcs11h_duplicateTokenId (
&session->token_id,
token_id
);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (rv == CKR_OK) {
rv = _pkcs11h_mutexInit (&session->mutexSession);
}
#endif
if (rv == CKR_OK) {
session->fValid = TRUE;
session->next = s_pkcs11h_data->sessions;
s_pkcs11h_data->sessions = session;
}
else {
#if defined(ENABLE_PKCS11H_THREADING)
_pkcs11h_mutexFree (&session->mutexSession);
#endif
_pkcs11h_free ((void *)&session);
}
}
if (rv == CKR_OK) {
*p_session = session;
session = NULL;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexSession);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getSessionByTokenId return rv=%ld-'%s', *p_session=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_session
);
return rv;
}
static
CK_RV
_pkcs11h_releaseSession (
IN const pkcs11h_session_t session
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (session!=NULL);
PKCS11H_ASSERT (session->nReferenceCount>=0);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_releaseSession session=%p",
(void *)session
);
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
/*
* Never logout for now
*/
if (rv == CKR_OK) {
if (session->nReferenceCount > 0) {
session->nReferenceCount--;
}
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_releaseSession return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_resetSession (
IN const pkcs11h_session_t session,
IN const unsigned maskPrompt,
OUT CK_SLOT_ID * const p_slot
) {
/*
* This function MUST NOT touch session
*/
PKCS11H_BOOL fFound = FALSE;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (session!=NULL);
PKCS11H_ASSERT (p_slot!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_resetSession entry session=%p, maskPrompt=%08x, p_slot=%p",
(void *)session,
maskPrompt,
(void *)p_slot
);
*p_slot = PKCS11H_INVALID_SLOT_ID;
while (
rv == CKR_OK &&
!fFound
) {
pkcs11h_provider_t current_provider = NULL;
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
for (
current_provider = s_pkcs11h_data->providers;
(
rv == CKR_OK &&
current_provider != NULL &&
!fFound
);
current_provider = current_provider->next
) {
CK_SLOT_ID_PTR slots = NULL;
CK_ULONG slotnum;
CK_SLOT_ID slot_index;
/*
* Skip disabled providers
* Skip all other providers,
* if one was set in the past
*/
if (session->provider != NULL) {
if (!session->provider->fEnabled) {
continue;
}
if (session->provider != current_provider) {
continue;
}
}
if (rv == CKR_OK) {
rv = _pkcs11h_getSlotList (
current_provider,
CK_TRUE,
&slots,
&slotnum
);
}
for (
slot_index=0;
(
slot_index < slotnum &&
rv == CKR_OK &&
!fFound
);
slot_index++
) {
pkcs11h_token_id_t token_id = NULL;
CK_TOKEN_INFO info;
if (rv == CKR_OK) {
rv = current_provider->f->C_GetTokenInfo (
slots[slot_index],
&info
);
}
if (
rv == CKR_OK &&
(rv = _pkcs11h_getTokenId (
&info,
&token_id
)) == CKR_OK &&
pkcs11h_sameTokenId (
session->token_id,
token_id
)
) {
fFound = TRUE;
*p_slot = slots[slot_index];
if (session->provider == NULL) {
session->provider = current_provider;
_pkcs11h_fixupFixedString (
token_id->label,
(char *)info.label,
sizeof (info.label)
);
session->fProtectedAuthenticationSupported = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0;
}
}
if (rv != CKR_OK) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
current_provider->manufacturerID,
slots[slot_index],
rv,
pkcs11h_getMessage (rv)
);
/*
* Ignore error
*/
rv = CKR_OK;
}
if (token_id != NULL) {
pkcs11h_freeTokenId (token_id);
}
}
if (rv != CKR_OK) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
current_provider->manufacturerID,
rv,
pkcs11h_getMessage (rv)
);
/*
* Ignore error
*/
rv = CKR_OK;
}
if (slots != NULL) {
_pkcs11h_free ((void *)&slots);
slots = NULL;
}
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (
rv == CKR_OK &&
!fFound
) {
if ((maskPrompt & PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT) != 0) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Calling token_prompt hook for '%s'",
session->token_id->label
);
if (
!s_pkcs11h_data->hooks.token_prompt (
s_pkcs11h_data->hooks.token_prompt_data,
session->token_id
)
) {
rv = CKR_CANCEL;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: token_prompt returned %ld",
rv
);
}
else {
rv = CKR_TOKEN_NOT_PRESENT;
}
}
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_resetSession return rv=%ld-'%s', *p_slot=%ld",
rv,
pkcs11h_getMessage (rv),
*p_slot
);
return rv;
}
static
CK_RV
_pkcs11h_getObjectById (
IN const pkcs11h_session_t session,
IN const CK_OBJECT_CLASS class,
IN const CK_BYTE_PTR id,
IN const size_t id_size,
OUT CK_OBJECT_HANDLE * const p_handle
) {
CK_ATTRIBUTE filter[] = {
{CKA_CLASS, (void *)&class, sizeof (class)},
{CKA_ID, (void *)id, id_size}
};
CK_OBJECT_HANDLE *objects = NULL;
CK_ULONG objects_found = 0;
CK_RV rv = CKR_OK;
/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
PKCS11H_ASSERT (id!=NULL);
PKCS11H_ASSERT (p_handle!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getObjectById entry session=%p, class=%ld, id=%p, id_size=%u, p_handle=%p",
(void *)session,
class,
id,
id_size,
(void *)p_handle
);
*p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (session);
}
if (rv == CKR_OK) {
rv = _pkcs11h_findObjects (
session,
filter,
sizeof (filter) / sizeof (CK_ATTRIBUTE),
&objects,
&objects_found
);
}
if (
rv == CKR_OK &&
objects_found == 0
) {
rv = CKR_FUNCTION_REJECTED;
}
if (rv == CKR_OK) {
*p_handle = objects[0];
}
if (objects != NULL) {
_pkcs11h_free ((void *)&objects);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getObjectById return rv=%ld-'%s', *p_handle=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_handle
);
return rv;
}
static
CK_RV
_pkcs11h_validateSession (
IN const pkcs11h_session_t session
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_RV rv = CKR_OK;
/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_validateSession entry session=%p",
(void *)session
);
if (
rv == CKR_OK &&
session == NULL
) {
rv = CKR_SESSION_HANDLE_INVALID;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (
rv == CKR_OK &&
(
session->provider == NULL ||
!session->provider->fEnabled ||
session->hSession == PKCS11H_INVALID_SESSION_HANDLE
)
) {
rv = CKR_SESSION_HANDLE_INVALID;
}
if (
rv == CKR_OK &&
session->timePINExpire != (time_t)0 &&
session->timePINExpire < PKCS11H_TIME (NULL)
) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Forcing logout due to pin timeout"
);
_pkcs11h_logout (session);
rv = CKR_SESSION_HANDLE_INVALID;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_validateSession return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_login (
IN const pkcs11h_session_t session,
IN const PKCS11H_BOOL fPublicOnly,
IN const PKCS11H_BOOL fReadOnly,
IN const unsigned maskPrompt
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (session!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_login entry session=%p, fPublicOnly=%d, fReadOnly=%d, maskPrompt=%08x",
(void *)session,
fPublicOnly ? 1 : 0,
fReadOnly ? 1 : 0,
maskPrompt
);
if (rv == CKR_OK) {
rv = _pkcs11h_logout (session);
}
if (rv == CKR_OK) {
rv = _pkcs11h_resetSession (session, maskPrompt, &slot);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
rv = session->provider->f->C_OpenSession (
slot,
(
CKF_SERIAL_SESSION |
(fReadOnly ? 0 : CKF_RW_SESSION)
),
NULL_PTR,
NULL_PTR,
&session->hSession
);
}
if (
rv == CKR_OK &&
(
!fPublicOnly ||
session->provider->fCertIsPrivate
)
) {
PKCS11H_BOOL fSuccessLogin = FALSE;
int nRetryCount = 0;
if ((maskPrompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT) == 0) {
rv = CKR_USER_NOT_LOGGED_IN;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Calling pin_prompt hook denied because of prompt mask"
);
}
while (
rv == CKR_OK &&
!fSuccessLogin &&
nRetryCount++ < s_pkcs11h_data->nMaxLoginRetries
) {
CK_UTF8CHAR_PTR utfPIN = NULL;
CK_ULONG lPINLength = 0;
char szPIN[1024];
if (
rv == CKR_OK &&
!(
s_pkcs11h_data->fProtectedAuthentication &&
session->provider->fProtectedAuthentication &&
session->fProtectedAuthenticationSupported
)
) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Calling pin_prompt hook for '%s'",
session->token_id->label
);
if (
!s_pkcs11h_data->hooks.pin_prompt (
s_pkcs11h_data->hooks.pin_prompt_data,
session->token_id,
szPIN,
sizeof (szPIN)
)
) {
rv = CKR_CANCEL;
}
else {
utfPIN = (CK_UTF8CHAR_PTR)szPIN;
lPINLength = strlen (szPIN);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: pin_prompt hook return rv=%ld",
rv
);
}
if (session->nPINCachePeriod == PKCS11H_PIN_CACHE_INFINITE) {
session->timePINExpire = 0;
}
else {
session->timePINExpire = (
PKCS11H_TIME (NULL) +
(time_t)session->nPINCachePeriod
);
}
if (
rv == CKR_OK &&
(rv = session->provider->f->C_Login (
session->hSession,
CKU_USER,
utfPIN,
lPINLength
)) != CKR_OK
) {
if (rv == CKR_USER_ALREADY_LOGGED_IN) {
rv = CKR_OK;
}
}
/*
* Clean PIN buffer
*/
memset (szPIN, 0, sizeof (szPIN));
if (rv == CKR_OK) {
fSuccessLogin = TRUE;
}
else if (
rv == CKR_PIN_INCORRECT ||
rv == CKR_PIN_INVALID
) {
/*
* Ignore these errors
* so retry can be performed
*/
rv = CKR_OK;
}
}
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_login return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_logout (
IN const pkcs11h_session_t session
) {
/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_logout entry session=%p",
(void *)session
);
if (
session != NULL &&
session->hSession != PKCS11H_INVALID_SESSION_HANDLE
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_RV rv = CKR_OK;
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
if (session->provider != NULL) {
session->provider->f->C_Logout (session->hSession);
session->provider->f->C_CloseSession (session->hSession);
}
session->hSession = PKCS11H_INVALID_SESSION_HANDLE;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_logout return"
);
return CKR_OK;
}
static
void
_pkcs11h_hooks_default_log (
IN const void * pData,
IN const unsigned flags,
IN const char * const szFormat,
IN va_list args
) {
(void)pData;
(void)flags;
(void)szFormat;
(void)args;
}
static
PKCS11H_BOOL
_pkcs11h_hooks_default_token_prompt (
IN const void * pData,
IN const pkcs11h_token_id_t token
) {
PKCS11H_ASSERT (token!=NULL);
(void)pData;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_hooks_default_token_prompt pData=%p, szLabel='%s'",
pData,
token->label
);
return FALSE;
}
static
PKCS11H_BOOL
_pkcs11h_hooks_default_pin_prompt (
IN const void * pData,
IN const pkcs11h_token_id_t token,
OUT char * const szPIN,
IN const size_t nMaxPIN
) {
PKCS11H_ASSERT (token!=NULL);
(void)pData;
(void)szPIN;
(void)nMaxPIN;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_hooks_default_pin_prompt pData=%p, szLabel='%s'",
pData,
token->label
);
return FALSE;
}
#if !defined(WIN32)
#if defined(ENABLE_PKCS11H_THREADING)
static
void
__pkcs11h_atfork_prepare () {
__pkcs1h_mutexLockAll ();
}
static
void
__pkcs11h_atfork_parent () {
__pkcs1h_mutexReleaseAll ();
}
static
void
__pkcs11h_atfork_child () {
__pkcs1h_mutexReleaseAll ();
_pkcs11h_forkFixup ();
}
#endif /* ENABLE_PKCS11H_THREADING */
static
CK_RV
_pkcs11h_forkFixup () {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
pid_t mypid = getpid ();
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_forkFixup entry pid=%d",
mypid
);
if (s_pkcs11h_data != NULL && s_pkcs11h_data->fInitialized) {
pkcs11h_provider_t current;
#if defined(ENABLE_PKCS11H_THREADING)
if (_pkcs11h_mutexLock (&s_pkcs11h_data->mutexGlobal) == CKR_OK) {
fMutexLocked = TRUE;
}
#endif
for (
current = s_pkcs11h_data->providers;
current != NULL;
current = current->next
) {
if (current->fEnabled) {
current->f->C_Initialize (NULL);
}
#if defined(ENABLE_PKCS11H_SLOTEVENT)
/*
* After fork we have no threads...
* So just initialized.
*/
if (s_pkcs11h_data->fSlotEventInitialized) {
s_pkcs11h_data->fSlotEventInitialized = FALSE;
_pkcs11h_slotevent_init ();
}
#endif
}
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&s_pkcs11h_data->mutexGlobal);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_forkFixup return"
);
return CKR_OK;
}
#endif /* !WIN32 */
#if defined(ENABLE_PKCS11H_TOKEN)
/*======================================================================*
* TOKEN INTERFACE
*======================================================================*/
CK_RV
pkcs11h_token_ensureAccess (
IN const pkcs11h_token_id_t token_id,
IN const unsigned maskPrompt
) {
pkcs11h_session_t session = NULL;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_token_ensureAccess entry token_id=%p, maskPrompt=%08x",
(void *)token_id,
maskPrompt
);
if (rv == CKR_OK) {
rv = _pkcs11h_getSessionByTokenId (
token_id,
&session
);
}
if (rv == CKR_OK) {
CK_SLOT_ID slot;
rv = _pkcs11h_resetSession (
session,
maskPrompt,
&slot
);
}
if (session != NULL) {
_pkcs11h_releaseSession (session);
session = NULL;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_token_ensureAccess return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
#endif /* ENABLE_PKCS11H_TOKEN */
#if defined(ENABLE_PKCS11H_DATA)
/*======================================================================*
* DATA INTERFACE
*======================================================================*/
static
CK_RV
_pkcs11h_data_getObject (
IN const pkcs11h_session_t session,
IN const char * const szApplication,
IN const char * const szLabel,
OUT CK_OBJECT_HANDLE * const p_handle
) {
CK_OBJECT_CLASS class = CKO_DATA;
CK_ATTRIBUTE filter[] = {
{CKA_CLASS, (void *)&class, sizeof (class)},
{CKA_APPLICATION, (void *)szApplication, szApplication == NULL ? 0 : strlen (szApplication)},
{CKA_LABEL, (void *)szLabel, szLabel == NULL ? 0 : strlen (szLabel)}
};
CK_OBJECT_HANDLE *objects = NULL;
CK_ULONG objects_found = 0;
CK_RV rv = CKR_OK;
/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
PKCS11H_ASSERT (szApplication!=NULL);
PKCS11H_ASSERT (szLabel!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_data_getObject entry session=%p, szApplication='%s', szLabel='%s', p_handle=%p",
(void *)session,
szApplication,
szLabel,
(void *)p_handle
);
*p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (session);
}
if (rv == CKR_OK) {
rv = _pkcs11h_findObjects (
session,
filter,
sizeof (filter) / sizeof (CK_ATTRIBUTE),
&objects,
&objects_found
);
}
if (
rv == CKR_OK &&
objects_found == 0
) {
rv = CKR_FUNCTION_REJECTED;
}
if (rv == CKR_OK) {
*p_handle = objects[0];
}
if (objects != NULL) {
_pkcs11h_free ((void *)&objects);
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_data_getObject return rv=%ld-'%s', *p_handle=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_handle
);
return rv;
}
CK_RV
pkcs11h_data_get (
IN const pkcs11h_token_id_t token_id,
IN const PKCS11H_BOOL fPublic,
IN const char * const szApplication,
IN const char * const szLabel,
OUT char * const blob,
IN OUT size_t * const p_blob_size
) {
CK_ATTRIBUTE attrs[] = {
{CKA_VALUE, NULL, 0}
};
CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
CK_RV rv = CKR_OK;
pkcs11h_session_t session = NULL;
size_t blob_size_max;
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_BOOL fLoginRetry = FALSE;
PKCS11H_BOOL fMutexLocked = FALSE;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_ASSERT (szApplication!=NULL);
PKCS11H_ASSERT (szLabel!=NULL);
/*PKCS11H_ASSERT (blob!=NULL); NOT NEEDED*/
PKCS11H_ASSERT (p_blob_size!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_get entry token_id=%p, szApplication='%s', szLabel='%s', blob=%p, p_blob_size=%p",
(void *)token_id,
szApplication,
szLabel,
blob,
(void *)p_blob_size
);
blob_size_max = *p_blob_size;
*p_blob_size = 0;
if (rv == CKR_OK) {
rv = _pkcs11h_getSessionByTokenId (
token_id,
&session
);
}
while (rv == CKR_OK && !fOpSuccess) {
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (session);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
rv = _pkcs11h_data_getObject (
session,
szApplication,
szLabel,
&handle
);
}
if (rv == CKR_OK) {
rv = _pkcs11h_getObjectAttributes (
session,
handle,
attrs,
sizeof (attrs)/sizeof (CK_ATTRIBUTE)
);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Read data object failed rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
fLoginRetry = TRUE;
rv = _pkcs11h_login (
session,
fPublic,
TRUE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
}
}
}
if (rv == CKR_OK) {
*p_blob_size = attrs[0].ulValueLen;
}
if (rv == CKR_OK) {
if (blob != NULL) {
if (*p_blob_size > blob_size_max) {
rv = CKR_BUFFER_TOO_SMALL;
}
else {
memmove (blob, attrs[0].pValue, *p_blob_size);
}
}
}
_pkcs11h_freeObjectAttributes (
attrs,
sizeof (attrs)/sizeof (CK_ATTRIBUTE)
);
if (session != NULL) {
_pkcs11h_releaseSession (session);
session = NULL;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_get return rv=%ld-'%s', *p_blob_size=%d",
rv,
pkcs11h_getMessage (rv),
*p_blob_size
);
return rv;
}
CK_RV
pkcs11h_data_put (
IN const pkcs11h_token_id_t token_id,
IN const PKCS11H_BOOL fPublic,
IN const char * const szApplication,
IN const char * const szLabel,
OUT char * const blob,
IN const size_t blob_size
) {
CK_OBJECT_CLASS class = CKO_DATA;
CK_BBOOL ck_true = CK_TRUE;
CK_BBOOL ck_false = CK_FALSE;
CK_ATTRIBUTE attrs[] = {
{CKA_CLASS, &class, sizeof (class)},
{CKA_TOKEN, &ck_true, sizeof (ck_true)},
{CKA_PRIVATE, fPublic ? &ck_false : &ck_true, sizeof (CK_BBOOL)},
{CKA_APPLICATION, (void *)szApplication, strlen (szApplication)},
{CKA_LABEL, (void *)szLabel, strlen (szLabel)},
{CKA_VALUE, blob, blob_size}
};
CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
CK_RV rv = CKR_OK;
pkcs11h_session_t session = NULL;
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_BOOL fLoginRetry = FALSE;
PKCS11H_BOOL fMutexLocked = FALSE;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_ASSERT (szApplication!=NULL);
PKCS11H_ASSERT (szLabel!=NULL);
PKCS11H_ASSERT (blob!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_put entry token_id=%p, szApplication='%s', szLabel='%s', blob=%p, blob_size=%d",
(void *)token_id,
szApplication,
szLabel,
blob,
blob_size
);
if (rv == CKR_OK) {
rv = _pkcs11h_getSessionByTokenId (
token_id,
&session
);
}
while (rv == CKR_OK && !fOpSuccess) {
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (session);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
rv = session->provider->f->C_CreateObject (
session->hSession,
attrs,
sizeof (attrs)/sizeof (CK_ATTRIBUTE),
&handle
);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Write data object failed rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
fLoginRetry = TRUE;
rv = _pkcs11h_login (
session,
fPublic,
FALSE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
}
}
}
if (session != NULL) {
_pkcs11h_releaseSession (session);
session = NULL;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_put return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
CK_RV
pkcs11h_data_del (
IN const pkcs11h_token_id_t token_id,
IN const PKCS11H_BOOL fPublic,
IN const char * const szApplication,
IN const char * const szLabel
) {
CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
CK_RV rv = CKR_OK;
pkcs11h_session_t session = NULL;
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_BOOL fLoginRetry = FALSE;
PKCS11H_BOOL fMutexLocked = FALSE;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (token_id!=NULL);
PKCS11H_ASSERT (szApplication!=NULL);
PKCS11H_ASSERT (szLabel!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_del entry token_id=%p, szApplication='%s', szLabel='%s'",
(void *)token_id,
szApplication,
szLabel
);
if (rv == CKR_OK) {
rv = _pkcs11h_getSessionByTokenId (
token_id,
&session
);
}
while (rv == CKR_OK && !fOpSuccess) {
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (session);
}
if (rv == CKR_OK) {
rv = _pkcs11h_data_getObject (
session,
szApplication,
szLabel,
&handle
);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
rv = session->provider->f->C_DestroyObject (
session->hSession,
handle
);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Remove data object failed rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
fLoginRetry = TRUE;
rv = _pkcs11h_login (
session,
fPublic,
FALSE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
}
}
}
if (session != NULL) {
_pkcs11h_releaseSession (session);
session = NULL;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_data_del return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
#endif /* ENABLE_PKCS11H_DATA */
#if defined(ENABLE_PKCS11H_CERTIFICATE)
/*======================================================================*
* CERTIFICATE INTERFACE
*======================================================================*/
static
void
_pkcs11h_isBetterCertificate_getExpiration (
IN const unsigned char * const pCertificate,
IN const size_t nCertificateSize,
OUT char * const szNotBefore,
IN const int nNotBeforeSize
) {
/*
* This function compare the notBefore
* and select the most recent certificate
* it does not deal with timezones...
* When openssl will have ASN1_TIME compare function
* it should be used.
*/
X509 *x509 = NULL;
PKCS11H_ASSERT (pCertificate!=NULL);
PKCS11H_ASSERT (szNotBefore!=NULL);
PKCS11H_ASSERT (nNotBeforeSize>0);
szNotBefore[0] = '\0';
x509 = X509_new ();
if (x509 != NULL) {
pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)pCertificate;
if (
d2i_X509 (&x509, &d2i, nCertificateSize)
) {
ASN1_TIME *notBefore = X509_get_notBefore (x509);
ASN1_TIME *notAfter = X509_get_notAfter (x509);
if (
notBefore != NULL &&
X509_cmp_current_time (notBefore) <= 0 &&
X509_cmp_current_time (notAfter) >= 0 &&
notBefore->length < nNotBeforeSize - 1
) {
memmove (szNotBefore, notBefore->data, notBefore->length);
szNotBefore[notBefore->length] = '\0';
}
}
}
if (x509 != NULL) {
X509_free (x509);
x509 = NULL;
}
}
static
PKCS11H_BOOL
_pkcs11h_isBetterCertificate (
IN const unsigned char * const pCurrent,
IN const size_t nCurrentSize,
IN const unsigned char * const pNew,
IN const size_t nNewSize
) {
/*
* This function compare the notBefore
* and select the most recent certificate
* it does not deal with timezones...
* When openssl will have ASN1_TIME compare function
* it should be used.
*/
PKCS11H_BOOL fBetter = FALSE;
/*PKCS11H_ASSERT (pCurrent!=NULL); NOT NEEDED */
PKCS11H_ASSERT (pNew!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_isBetterCertificate entry pCurrent=%p, nCurrentSize=%u, pNew=%p, nNewSize=%u",
pCurrent,
nCurrentSize,
pNew,
nNewSize
);
/*
* First certificae
* always select
*/
if (nCurrentSize == 0 || pCurrent == NULL) {
fBetter = TRUE;
}
else {
char szNotBeforeCurrent[1024], szNotBeforeNew[1024];
_pkcs11h_isBetterCertificate_getExpiration (
pCurrent,
nCurrentSize,
szNotBeforeCurrent,
sizeof (szNotBeforeCurrent)
);
_pkcs11h_isBetterCertificate_getExpiration (
pNew,
nNewSize,
szNotBeforeNew,
sizeof (szNotBeforeNew)
);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_isBetterCertificate szNotBeforeCurrent='%s', szNotBeforeNew='%s'",
szNotBeforeCurrent,
szNotBeforeNew
);
fBetter = strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_isBetterCertificate return fBetter=%d",
fBetter ? 1 : 0
);
return fBetter;
}
static
CK_RV
_pkcs11h_newCertificateId (
OUT pkcs11h_certificate_id_t * const p_certificate_id
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (p_certificate_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_newCertificateId entry p_certificate_id=%p",
(void *)p_certificate_id
);
*p_certificate_id = NULL;
if (rv == CKR_OK) {
rv = _pkcs11h_malloc ((void *)p_certificate_id, sizeof (struct pkcs11h_certificate_id_s));
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_newCertificateId return rv=%ld-'%s', *p_certificate_id=%p",
rv,
pkcs11h_getMessage (rv),
(void *)*p_certificate_id
);
return rv;
}
static
CK_RV
_pkcs11h_loadCertificate (
IN const pkcs11h_certificate_t certificate
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
CK_ATTRIBUTE cert_filter[] = {
{CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
{CKA_ID, NULL, 0}
};
CK_OBJECT_HANDLE *objects = NULL;
CK_ULONG objects_found = 0;
CK_RV rv = CKR_OK;
CK_ULONG i;
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_ASSERT (certificate->id!=NULL);
/* Must be after assert */
cert_filter[1].pValue = certificate->id->attrCKA_ID;
cert_filter[1].ulValueLen = certificate->id->attrCKA_ID_size;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_loadCertificate entry certificate=%p",
(void *)certificate
);
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (certificate->session);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK) {
rv = _pkcs11h_findObjects (
certificate->session,
cert_filter,
sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
&objects,
&objects_found
);
}
for (i=0;rv == CKR_OK && i < objects_found;i++) {
CK_ATTRIBUTE attrs[] = {
{CKA_VALUE, NULL, 0}
};
if (
rv == CKR_OK &&
(rv = _pkcs11h_getObjectAttributes (
certificate->session,
objects[i],
attrs,
sizeof (attrs) / sizeof (CK_ATTRIBUTE)
)) == CKR_OK
) {
if (
_pkcs11h_isBetterCertificate (
certificate->id->certificate_blob,
certificate->id->certificate_blob_size,
attrs[0].pValue,
attrs[0].ulValueLen
)
) {
if (certificate->id->certificate_blob != NULL) {
_pkcs11h_free ((void *)&certificate->id->certificate_blob);
}
rv = _pkcs11h_dupmem (
(void*)&certificate->id->certificate_blob,
&certificate->id->certificate_blob_size,
attrs[0].pValue,
attrs[0].ulValueLen
);
}
}
if (rv != CKR_OK) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
certificate->session->provider->manufacturerID,
objects[i],
rv,
pkcs11h_getMessage (rv)
);
/*
* Ignore error
*/
rv = CKR_OK;
}
_pkcs11h_freeObjectAttributes (
attrs,
sizeof (attrs) / sizeof (CK_ATTRIBUTE)
);
}
if (
rv == CKR_OK &&
certificate->id->certificate_blob == NULL
) {
rv = CKR_ATTRIBUTE_VALUE_INVALID;
}
if (objects != NULL) {
_pkcs11h_free ((void *)&objects);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&certificate->mutexCertificate);
fMutexLocked = FALSE;
}
#endif
/*
* No need to free allocated objects
* on error, since the certificate_id
* should be free by caller.
*/
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_loadCertificate return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_updateCertificateIdDescription (
IN OUT pkcs11h_certificate_id_t certificate_id
) {
static const char * szSeparator = " on ";
static const char * szUnknown = "UNKNOWN";
X509 *x509 = NULL;
pkcs11_openssl_d2i_t d2i1;
PKCS11H_ASSERT (certificate_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_updateCertificateIdDescription entry certificate_id=%p",
(void *)certificate_id
);
x509 = X509_new ();
d2i1 = (pkcs11_openssl_d2i_t)certificate_id->certificate_blob;
if (d2i_X509 (&x509, &d2i1, certificate_id->certificate_blob_size)) {
X509_NAME_oneline (
X509_get_subject_name (x509),
certificate_id->displayName,
sizeof (certificate_id->displayName)
);
}
else {
strncpy (
certificate_id->displayName,
szUnknown,
sizeof (certificate_id->displayName)-1
);
}
if (x509 != NULL) {
X509_free (x509);
x509 = NULL;
}
/*
* Try to avoid using snprintf,
* may be unavailable
*/
strncat (
certificate_id->displayName,
szSeparator,
sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
);
strncat (
certificate_id->displayName,
certificate_id->token_id->label,
sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
);
certificate_id->displayName[sizeof (certificate_id->displayName) - 1] = '\0';
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_updateCertificateIdDescription return displayName=%s",
certificate_id->displayName
);
return CKR_OK;
}
static
CK_RV
_pkcs11h_ensureCertificateBlob (
IN const pkcs11h_certificate_t certificate
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_BOOL fLoginRetry = FALSE;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_ensureCertificateBlob entry certificate=%p",
(void *)certificate
);
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (certificate->id->certificate_blob == NULL) {
fOpSuccess = FALSE;
fLoginRetry = FALSE;
while (rv == CKR_OK && !fOpSuccess) {
if (rv == CKR_OK) {
rv = _pkcs11h_loadCertificate (certificate);
}
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
fLoginRetry = TRUE;
rv = _pkcs11h_resetCertificateSession (
certificate,
TRUE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
}
}
}
}
if (
rv == CKR_OK &&
certificate->id->certificate_blob == NULL
) {
rv = CKR_FUNCTION_REJECTED;
}
if (rv == CKR_OK) {
_pkcs11h_updateCertificateIdDescription (certificate->id);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&certificate->mutexCertificate);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_ensureCertificateBlob return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_getCertificateKeyAttributes (
IN const pkcs11h_certificate_t certificate
) {
CK_RV rv = CKR_OK;
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_BOOL fLoginRetry = FALSE;
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getCertificateKeyAttributes entry certificate=%p",
(void *)certificate
);
certificate->maskSignMode = 0;
while (rv == CKR_OK && !fOpSuccess) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
CK_ATTRIBUTE key_attrs[] = {
{CKA_SIGN, NULL, 0},
{CKA_SIGN_RECOVER, NULL, 0}
};
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
/*
* Don't try invalid object
*/
if (
rv == CKR_OK &&
certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE
) {
rv = CKR_OBJECT_HANDLE_INVALID;
}
if (rv == CKR_OK) {
if (certificate->session->provider->maskSignMode != 0) {
certificate->maskSignMode = certificate->session->provider->maskSignMode;
fOpSuccess = TRUE;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Key attributes enforced by provider (%08x)",
certificate->maskSignMode
);
}
}
if (rv == CKR_OK && !fOpSuccess) {
rv = _pkcs11h_getObjectAttributes (
certificate->session,
certificate->hKey,
key_attrs,
sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
);
}
if (rv == CKR_OK && !fOpSuccess) {
CK_BBOOL *key_attrs_sign = (CK_BBOOL *)key_attrs[0].pValue;
CK_BBOOL *key_attrs_sign_recover = (CK_BBOOL *)key_attrs[1].pValue;
if (key_attrs_sign != NULL && *key_attrs_sign != CK_FALSE) {
certificate->maskSignMode |= PKCS11H_SIGNMODE_MASK_SIGN;
}
if (key_attrs_sign_recover != NULL && *key_attrs_sign_recover != CK_FALSE) {
certificate->maskSignMode |= PKCS11H_SIGNMODE_MASK_RECOVER;
}
if (certificate->maskSignMode == 0) {
rv = CKR_KEY_TYPE_INCONSISTENT;
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Key attributes loaded (%08x)",
certificate->maskSignMode
);
}
_pkcs11h_freeObjectAttributes (
key_attrs,
sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
);
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&certificate->mutexCertificate);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Get private key attributes failed: %ld:'%s'",
rv,
pkcs11h_getMessage (rv)
);
rv = _pkcs11h_resetCertificateSession (
certificate,
FALSE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
fLoginRetry = TRUE;
}
}
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_getCertificateKeyAttributes return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_validateCertificateSession (
IN const pkcs11h_certificate_t certificate
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_validateCertificateSession entry certificate=%p",
(void *)certificate
);
if (rv == CKR_OK) {
rv = _pkcs11h_validateSession (certificate->session);
}
if (rv == CKR_OK) {
if (certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE) {
rv = CKR_OBJECT_HANDLE_INVALID;
}
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_validateCertificateSession return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
CK_RV
_pkcs11h_resetCertificateSession (
IN const pkcs11h_certificate_t certificate,
IN const PKCS11H_BOOL fPublicOnly,
IN const unsigned maskPrompt
) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
PKCS11H_BOOL fKeyValid = FALSE;
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_resetCertificateSession entry certificate=%p, fPublicOnly=%d, maskPrompt=%08x",
(void *)certificate,
fPublicOnly ? 1 : 0,
maskPrompt
);
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&certificate->mutexCertificate)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (
!fKeyValid &&
rv == CKR_OK &&
certificate->session == NULL &&
(rv = _pkcs11h_getSessionByTokenId (certificate->id->token_id, &certificate->session)) == CKR_OK
) {
if (certificate->nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) {
if (certificate->session->nPINCachePeriod != PKCS11H_PIN_CACHE_INFINITE) {
if (certificate->session->nPINCachePeriod > certificate->nPINCachePeriod) {
certificate->session->timePINExpire = (
certificate->session->timePINExpire -
(time_t)certificate->session->nPINCachePeriod +
(time_t)certificate->nPINCachePeriod
);
certificate->session->nPINCachePeriod = certificate->nPINCachePeriod;
}
}
else {
certificate->session->timePINExpire = (
PKCS11H_TIME (NULL) +
(time_t)certificate->nPINCachePeriod
);
certificate->session->nPINCachePeriod = certificate->nPINCachePeriod;
}
}
}
/*
* First, if session seems to be valid
* and key handle is invalid (hard-set),
* try to fetch key handle,
* maybe the token is already logged in
*/
if (rv == CKR_OK) {
if (
certificate->session->hSession != PKCS11H_INVALID_SESSION_HANDLE &&
certificate->hKey == PKCS11H_INVALID_OBJECT_HANDLE &&
!fPublicOnly
) {
if (
(rv = _pkcs11h_getObjectById (
certificate->session,
CKO_PRIVATE_KEY,
certificate->id->attrCKA_ID,
certificate->id->attrCKA_ID_size,
&certificate->hKey
)) == CKR_OK
) {
fKeyValid = TRUE;
}
else {
/*
* Ignore error
*/
rv = CKR_OK;
certificate->hKey = PKCS11H_INVALID_OBJECT_HANDLE;
}
}
}
if (
!fKeyValid &&
rv == CKR_OK &&
(rv = _pkcs11h_login (
certificate->session,
fPublicOnly,
TRUE,
maskPrompt
)) == CKR_OK
) {
rv = _pkcs11h_updateCertificateIdDescription (certificate->id);
}
if (
!fKeyValid &&
rv == CKR_OK &&
!fPublicOnly &&
(rv = _pkcs11h_getObjectById (
certificate->session,
CKO_PRIVATE_KEY,
certificate->id->attrCKA_ID,
certificate->id->attrCKA_ID_size,
&certificate->hKey
)) == CKR_OK
) {
fKeyValid = TRUE;
}
if (
rv == CKR_OK &&
!fPublicOnly &&
!fKeyValid
) {
rv = CKR_FUNCTION_REJECTED;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&certificate->mutexCertificate);
fMutexLocked = FALSE;
}
#endif
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_resetCertificateSession return rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
return rv;
}
static
CK_RV
_pkcs11h_certificate_private_op (
IN const pkcs11h_certificate_t certificate,
IN const enum _pkcs11h_private_op_e op,
IN const CK_MECHANISM_TYPE mech_type,
IN const unsigned char * const source,
IN const size_t source_size,
OUT unsigned char * const target,
IN OUT size_t * const p_target_size
) {
CK_MECHANISM mech = {
mech_type, NULL, 0
};
CK_RV rv = CKR_OK;
PKCS11H_BOOL fLoginRetry = FALSE;
PKCS11H_BOOL fOpSuccess = FALSE;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (certificate!=NULL);
PKCS11H_ASSERT (source!=NULL);
/*PKCS11H_ASSERT (target); NOT NEEDED*/
PKCS11H_ASSERT (p_target_size!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_certificate_private_op entry certificate=%p, op=%d, mech_type=%ld, source=%p, source_size=%u, target=%p, p_target_size=%p",
(void *)certificate,
op,
mech_type,
source,
source_size,
target,
(void *)p_target_size
);
if (target == NULL) {
*p_target_size = 0;
}
while (rv == CKR_OK && !fOpSuccess) {
#if defined(ENABLE_PKCS11H_THREADING)
PKCS11H_BOOL fMutexLocked = FALSE;
#endif
if (rv == CKR_OK && !certificate->fOperationActive) {
rv = _pkcs11h_validateCertificateSession (certificate);
}
#if defined(ENABLE_PKCS11H_THREADING)
if (
rv == CKR_OK &&
(rv = _pkcs11h_mutexLock (&certificate->session->mutexSession)) == CKR_OK
) {
fMutexLocked = TRUE;
}
#endif
if (rv == CKR_OK && !certificate->fOperationActive) {
switch (op) {
case _pkcs11h_private_op_sign:
rv = certificate->session->provider->f->C_SignInit (
certificate->session->hSession,
&mech,
certificate->hKey
);
break;
case _pkcs11h_private_op_sign_recover:
rv = certificate->session->provider->f->C_SignRecoverInit (
certificate->session->hSession,
&mech,
certificate->hKey
);
break;
case _pkcs11h_private_op_decrypt:
rv = certificate->session->provider->f->C_DecryptInit (
certificate->session->hSession,
&mech,
certificate->hKey
);
break;
default:
rv = CKR_ARGUMENTS_BAD;
break;
}
}
if (rv == CKR_OK) {
CK_ULONG size = *p_target_size;
switch (op) {
case _pkcs11h_private_op_sign:
rv = certificate->session->provider->f->C_Sign (
certificate->session->hSession,
(CK_BYTE_PTR)source,
source_size,
(CK_BYTE_PTR)target,
&size
);
break;
case _pkcs11h_private_op_sign_recover:
rv = certificate->session->provider->f->C_SignRecover (
certificate->session->hSession,
(CK_BYTE_PTR)source,
source_size,
(CK_BYTE_PTR)target,
&size
);
break;
case _pkcs11h_private_op_decrypt:
rv = certificate->session->provider->f->C_Decrypt (
certificate->session->hSession,
(CK_BYTE_PTR)source,
source_size,
(CK_BYTE_PTR)target,
&size
);
break;
default:
rv = CKR_ARGUMENTS_BAD;
break;
}
*p_target_size = size;
}
if (
target == NULL &&
(
rv == CKR_BUFFER_TOO_SMALL ||
rv == CKR_OK
)
) {
certificate->fOperationActive = TRUE;
rv = CKR_OK;
}
else {
certificate->fOperationActive = FALSE;
}
#if defined(ENABLE_PKCS11H_THREADING)
if (fMutexLocked) {
_pkcs11h_mutexRelease (&certificate->session->mutexSession);
fMutexLocked = FALSE;
}
#endif
if (rv == CKR_OK) {
fOpSuccess = TRUE;
}
else {
if (!fLoginRetry) {
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG1,
"PKCS#11: Private key operation failed rv=%ld-'%s'",
rv,
pkcs11h_getMessage (rv)
);
fLoginRetry = TRUE;
rv = _pkcs11h_resetCertificateSession (
certificate,
FALSE,
(
PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT |
PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT
)
);
}
}
}
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_certificate_private_op return rv=%ld-'%s', *p_target_size=%d",
rv,
pkcs11h_getMessage (rv),
*p_target_size
);
return rv;
}
CK_RV
pkcs11h_freeCertificateId (
IN pkcs11h_certificate_id_t certificate_id
) {
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (certificate_id!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_freeCertificateId entry certificate_id=%p",
(void *)certificate_id
);
if (certificate_id->attrCKA_ID != NULL) {
_pkcs11h_free ((void *)&certificate_id->attrCKA_ID);
}
if (certificate_id->certificate_blob != NULL) {
_pkcs11h_free ((void *)&certificate_id->certificate_blob);
}
if (certificate_id->token_id != NULL) {
pkcs11h_freeTokenId (certificate_id->token_id);
certificate_id->token_id = NULL;
}
_pkcs11h_free ((void *)&certificate_id);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_freeCertificateId return"
);
return CKR_OK;
}
CK_RV
pkcs11h_duplicateCertificateId (
OUT pkcs11h_certificate_id_t * const to,
IN const pkcs11h_certificate_id_t from
) {
CK_RV rv = CKR_OK;
PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
PKCS11H_ASSERT (s_pkcs11h_data->fInitialized);
PKCS11H_ASSERT (to!=NULL);
PKCS11H_ASSERT (from!=NULL);
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: pkcs11h_duplicateCertificateId entry to=%p form=%p",
(void *)to,
(void *)from
);
*to = NULL;
if (rv == CKR_OK) {
rv = _pkcs11h_dupmem (
(void*)to,
NULL,
from,
sizeof (struct pkcs11h_certificate_id_s)
);
}
if (rv == CKR_OK) {
rv = _pkcs11h_dupmem (
(void*)&(*to)->token_id,
NULL,
from->token_id,
sizeof (struct pkcs11h_token_id_s)
);
}
if (rv == CKR_OK) {
rv = _pkcs11h_dupmem (
(void*)&(*to)->attrCKA_ID,
&(*to)->attrCKA_ID_size,
from->attrCKA_ID,
from->attrCKA_ID_size
);
}
if (rv == CKR_OK) {
rv = _pkcs11h_dupmem (
(void*)&(*to)->certificate_blob,
&(*to)->certificate_blob_size,
from->certificate_blob,
from->certificate_blob_size
);
}
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 (!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) {
continue;
}
if (rv == CKR_OK) {
rv = _pkcs11h_getSlotList (
current_provider,
CK_TRUE,
&slots,
&slotnum
);
}
for (
slot_index=0;
(
slot_index < slotnum &&
rv == CKR_OK &&
!fFound
);
slot_index++
) {
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) {
continue;
}
if (rv == CKR_OK) {
rv = _pkcs11h_getSlotList (
current_provider,
CK_TRUE,
&slots,
&slotnum
);
}
for (
slot_index=0;
(
slot_index < slotnum &&
rv == CKR_OK &&
!fFound
);
slot_index++
) {
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;
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
)
) {
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 (*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 (
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) {
continue;
}
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) {
continue;
}
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;i<s;i++) {
r += p[i];
}
return r;
}
static
void *
_pkcs11h_slotevent_provider (
IN void *p
) {
pkcs11h_provider_t provider = (pkcs11h_provider_t)p;
CK_SLOT_ID slot;
CK_RV rv = CKR_OK;
PKCS11H_DEBUG (
PKCS11H_LOG_DEBUG2,
"PKCS#11: _pkcs11h_slotevent_provider provider='%s' entry",
provider->manufacturerID
);
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;i<slotnum;i++) {
CK_TOKEN_INFO info;
if (provider->f->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,
OUT char * const szPIN,
IN const size_t nMaxPIN
) {
strncpy (szPIN, (char *)pData, nMaxPIN);
return TRUE;
}
void
_pkcs11h_standalone_dump_objects_hex (
IN const unsigned char * const p,
IN const size_t p_size,
OUT char * const sz,
IN const size_t max,
IN const char * const szLinePrefix
) {
size_t j;
sz[0] = '\0';
for (j=0;j<p_size;j+=16) {
char szLine[3*16+1];
size_t k;
szLine[0] = '\0';
for (k=0;k<16 && j+k<p_size;k++) {
sprintf (szLine+strlen (szLine), "%02x ", p[j+k]);
}
strncat (
sz,
szLinePrefix,
max-1-strlen (sz)
);
strncat (
sz,
szLine,
max-1-strlen (sz)
);
strncat (
sz,
"\n",
max-1-strlen (sz)
);
}
sz[max-1] = '\0';
}
void
pkcs11h_standalone_dump_objects (
IN const pkcs11h_output_print_t my_output,
IN const void *pData,
IN const char * const provider,
IN const char * const slot,
IN const char * const pin
) {
CK_SLOT_ID s;
CK_RV rv = CKR_OK;
pkcs11h_provider_t pkcs11h_provider = NULL;
pkcs11h_token_id_t token_id = NULL;
pkcs11h_session_t session = NULL;
PKCS11H_ASSERT (my_output!=NULL);
/*PKCS11H_ASSERT (pData) NOT NEEDED */
PKCS11H_ASSERT (provider!=NULL);
PKCS11H_ASSERT (slot!=NULL);
PKCS11H_ASSERT (pin!=NULL);
s = atoi (slot);
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_setPINPromptHook (_pkcs11h_standalone_dump_objects_pin_prompt, (void *)pin)) != CKR_OK
) {
my_output (pData, "PKCS#11: Cannot set hooks %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_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_recover, sizeof (sign_recover)},
{CKA_SIGN_RECOVER, &sign, sizeof (sign)}
};
CK_ATTRIBUTE attrs_key_common[] = {
{CKA_ID, NULL, 0},
{CKA_LABEL, NULL, 0}
};
unsigned char *attrs_id = NULL;
int attrs_id_size = 0;
char *attrs_label = NULL;
char szHexId[1024];
pkcs11h_provider->f->C_GetAttributeValue (
session->hSession,
objects[i],
attrs_key,
sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
);
if (
_pkcs11h_getObjectAttributes (
session,
objects[i],
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
) == CKR_OK &&
_pkcs11h_malloc (
(void *)&attrs_label,
attrs_key_common[1].ulValueLen+1
) == CKR_OK
) {
attrs_id = (unsigned char *)attrs_key_common[0].pValue;
attrs_id_size = attrs_key_common[0].ulValueLen;
memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
_pkcs11h_standalone_dump_objects_hex (
attrs_id,
attrs_id_size,
szHexId,
sizeof (szHexId),
"\t\t"
);
}
my_output (
pData,
(
"Object\n"
"\tType:\t\t\tPrivate Key\n"
"\tCKA_ID:\n"
"%s"
"\tCKA_LABEL:\t\t%s\n"
"\tCKA_SIGN:\t\t%s\n"
"\tCKA_SIGN_RECOVER:\t%s\n"
),
szHexId,
attrs_label,
sign ? "TRUE" : "FALSE",
sign_recover ? "TRUE" : "FALSE"
);
_pkcs11h_free ((void *)&attrs_label);
_pkcs11h_freeObjectAttributes (
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
);
}
else if (attrs_class == CKO_PUBLIC_KEY) {
CK_ATTRIBUTE attrs_key_common[] = {
{CKA_ID, NULL, 0},
{CKA_LABEL, NULL, 0}
};
unsigned char *attrs_id = NULL;
int attrs_id_size = 0;
char *attrs_label = NULL;
char szHexId[1024];
if (
_pkcs11h_getObjectAttributes (
session,
objects[i],
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
) == CKR_OK &&
_pkcs11h_malloc (
(void *)&attrs_label,
attrs_key_common[1].ulValueLen+1
) == CKR_OK
) {
attrs_id = (unsigned char *)attrs_key_common[0].pValue;
attrs_id_size = attrs_key_common[0].ulValueLen;
memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
_pkcs11h_standalone_dump_objects_hex (
attrs_id,
attrs_id_size,
szHexId,
sizeof (szHexId),
"\t\t"
);
}
my_output (
pData,
(
"Object\n"
"\tType:\t\t\tPublic Key\n"
"\tCKA_ID:\n"
"%s"
"\tCKA_LABEL:\t\t%s\n"
),
szHexId,
attrs_label
);
_pkcs11h_free ((void *)&attrs_label);
_pkcs11h_freeObjectAttributes (
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
);
}
else if (attrs_class == CKO_DATA) {
CK_ATTRIBUTE attrs_key_common[] = {
{CKA_APPLICATION, NULL, 0},
{CKA_LABEL, NULL, 0}
};
char *attrs_application = NULL;
char *attrs_label = NULL;
if (
_pkcs11h_getObjectAttributes (
session,
objects[i],
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
) == CKR_OK &&
_pkcs11h_malloc (
(void *)&attrs_application,
attrs_key_common[0].ulValueLen+1
) == CKR_OK &&
_pkcs11h_malloc (
(void *)&attrs_label,
attrs_key_common[1].ulValueLen+1
) == CKR_OK
) {
memset (attrs_application, 0, attrs_key_common[0].ulValueLen+1);
memmove (attrs_application, attrs_key_common[0].pValue, attrs_key_common[0].ulValueLen);
memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
}
my_output (
pData,
(
"Object\n"
"\tType:\t\t\tData\n"
"\tCKA_APPLICATION\t\t%s\n"
"\tCKA_LABEL:\t\t%s\n"
),
attrs_application,
attrs_label
);
_pkcs11h_free ((void *)&attrs_application);
_pkcs11h_free ((void *)&attrs_label);
_pkcs11h_freeObjectAttributes (
attrs_key_common,
sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
);
}
else {
my_output (
pData,
(
"Object\n"
"\tType:\t\t\tUnsupported\n"
)
);
}
}
_pkcs11h_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 */