/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# include <cryptoki.hxx>
# include <sstream>
# include <memory>
# include <dlfcn.h>
# include <iostream>
# define CRYPTOKI_LOG(X) std::clog<<"... "<<X<<" in "<<__PRETTY_FUNCTION__<<std::endl;
namespace cryptoki {
# ifndef CRYPTOKI_FN_LOG
# if __GNUC__ >= 2
# define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \
+ std : : string ( __PRETTY_FUNCTION__ ) )
# else
# define CRYPTOKI_FN_LOG(X) X " failed"
# endif
# endif
bool Init : : functionList ( const std : : string & library ) {
void * lib ( dlopen ( library . c_str ( ) , RTLD_NOW ) ) ;
if ( ! lib ) throw exception ( " open of library failed: " + library ) ;
CK_RV ( * fn ) ( CK_FUNCTION_LIST * * )
( ( CK_RV ( * ) ( CK_FUNCTION_LIST * * ) ) dlsym ( lib , " C_GetFunctionList " ) ) ;
if ( ! fn )
throw exception ( " required library symbol C_GetFunctionList not found in "
+ library ) ;
//! calls @c C_GetFunctionList
return check ( fn ( & _fn ) , CRYPTOKI_FN_LOG ( " C_GetFunctionList " ) ) ;
}
bool Init : : check ( CK_RV result , const std : : string & context ) {
_res = result ;
if ( _exc & & ! * this )
if ( context . size ( ) )
throw access_error ( context + " : " + error ( ) ) ;
else
throw access_error ( error ( ) ) ;
return _res = = CKR_OK ;
}
std : : string Init : : error ( CK_RV res ) {
switch ( res ) {
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_VENDOR_DEFINED : return " CKR_VENDOR_DEFINED " ;
default : {
std : : stringstream ss ;
ss < < " unknown error code ( " < < res < < ' ) ' ;
return ss . str ( ) ;
}
}
}
Init : : Init ( const std : : string & library , bool exc ) :
_exc ( exc ) , _res ( CKR_OK ) , _fn ( 0 ) {
//! calls @c functionList
if ( ! functionList ( library ) ) return ;
//! calls @c C_Initialize
check ( _fn - > C_Initialize ( 0 ) , //! @todo add optional argument
CRYPTOKI_FN_LOG ( " C_Initialize " ) ) ;
}
Init : : operator bool ( ) {
return _res = = CKR_OK ;
}
std : : string Init : : error ( ) {
return error ( _res ) ;
}
/*! @todo Not implemented:
@ code
bool Init : : getinfo ( ) {
//! calls @c C_GetInfo
return check ( _init . _fn - > C_GetInfo ( CK_INFO_PTR ) ,
CRYPTOKI_FN_LOG ( " C_GetInfo " ) ) ;
}
@ endcode */
SlotList Init : : slotList ( bool tokenPresent ) {
SlotList res ;
CK_ULONG count ( 0 ) ;
//! calls @c C_GetSlotList
check ( _fn - > C_GetSlotList ( tokenPresent ? TRUE : FALSE , 0 , & count ) ,
CRYPTOKI_FN_LOG ( " C_GetSlotList " ) ) ;
if ( ! count | | ! * this ) return res ;
CK_SLOT_ID * slots = 0 ;
try {
do {
delete [ ] slots ;
slots = new CK_SLOT_ID [ count ] ;
_res = _fn - > C_GetSlotList ( tokenPresent ? TRUE : FALSE , slots , & count ) ;
} while ( _res = = CKR_BUFFER_TOO_SMALL ) ;
check ( _res , CRYPTOKI_FN_LOG ( " C_GetSlotList " ) ) ;
if ( ! * this ) return res ;
for ( CK_ULONG i ( 0 ) ; i < count ; + + i ) res . push_back ( Slot ( * this , slots [ i ] ) ) ;
} catch ( . . . ) {
delete [ ] slots ;
throw ;
}
delete [ ] slots ;
return res ;
}
//============================================================================
ObjectList Session : : find ( const AttributeList & attrs ) {
ObjectList res ;
CK_ATTRIBUTE * a ( 0 ) ;
try {
if ( attrs . size ( ) ) {
a = new CK_ATTRIBUTE [ attrs . size ( ) ] ;
for ( AttributeList : : size_type i ( 0 ) ; i < attrs . size ( ) ; + + i )
a [ i ] = attrs [ i ] ;
}
//! calls @c C_FindObjectsInit
if ( check ( _slot . _init - > _fn - > C_FindObjectsInit
( _session , a , attrs . size ( ) ) ,
CRYPTOKI_FN_LOG ( " C_FindObjectsInit " ) ) ) {
CK_OBJECT_HANDLE obj ;
//! calls @c C_FindObjects
for ( CK_ULONG objs ( 0 ) ;
check ( _slot . _init - > _fn - > C_FindObjects
( _session , & obj , 1 , & objs ) ,
CRYPTOKI_FN_LOG ( " C_FindObjects " ) ) & & objs ;
res . push_back ( Object ( * this , obj ) ) ) ;
}
//! calls @c C_FindObjectsFinal
check ( _slot . _init - > _fn - > C_FindObjectsFinal ( _session ) ,
CRYPTOKI_FN_LOG ( " C_FindObjectsFinal " ) ) ;
delete [ ] a ;
return res ;
} catch ( . . . ) {
delete [ ] a ;
throw ;
}
}
//----------------------------------------------------------------------------
Object Session : : create ( const openssl : : X509 & cert ) {
AttributeList attrs ;
attrs . push_back ( Attribute ( CKA_CLASS )
. from < CK_OBJECT_CLASS > ( CKO_CERTIFICATE ) ) ;
attrs . push_back ( Attribute ( CKA_CERTIFICATE_TYPE )
. from < CK_CERTIFICATE_TYPE > ( CKC_X_509 ) ) ;
attrs . push_back ( Attribute ( CKA_SUBJECT , cert . subjectDER ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_VALUE , cert . valueDER ( ) ) ) ;
return create ( attrs ) ;
}
Object Session : : create ( const openssl : : PrivateKey & key ) {
AttributeList attrs ;
return create ( attrs ) ;
}
Object Session : : create ( const openssl : : PKCS12 & p12 ) {
AttributeList attrs ;
return create ( attrs ) ;
}
//----------------------------------------------------------------------------
Object Session : : create ( const AttributeList & attrs ) {
CK_ATTRIBUTE * a ( 0 ) ;
try {
if ( attrs . size ( ) ) {
a = new CK_ATTRIBUTE [ attrs . size ( ) ] ;
for ( AttributeList : : size_type i ( 0 ) ; i < attrs . size ( ) ; + + i )
a [ i ] = attrs [ i ] ;
}
CK_OBJECT_HANDLE object ;
//! calls @c C_CreateObject
check ( _slot . _init - > _fn - > C_CreateObject
( _session , a , attrs . size ( ) , & object ) ,
CRYPTOKI_FN_LOG ( " C_CreateObject " ) ) ;
delete [ ] a ;
return Object ( * this , object ) ;
} catch ( . . . ) {
delete [ ] a ;
throw ;
}
}
}