/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# include <cryptoki.hxx>
# include <sstream>
# include <mrw/checkcxx11.hxx>
# include <memory>
# ifndef WIN32
# include <dlfcn.h>
# define CK_PTR *
typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR ;
typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR ;
typedef CK_RV ( * CK_C_GetFunctionList )
( CK_FUNCTION_LIST_PTR_PTR ppFunctionList ) ;
# else
# include <windows.h>
# undef ERROR
# endif
namespace cryptoki {
bool Library : : Init : : functionList ( const std : : string & library ) {
CRYPTOLOG ( " try to load: " < < library ) ;
# ifndef WIN32
_lib = dlopen ( library . c_str ( ) , RTLD_NOW ) ;
# else
_lib = LoadLibrary ( library . c_str ( ) ) ;
# endif
if ( ! _lib ) throw exception ( " open of library failed: " + library ) ;
CRYPTOLOG ( " loaded: " < < library ) ;
# ifndef WIN32
/// @bug in dlsym: returns void* but should return void(*)()
CK_C_GetFunctionList fnl
( reinterpret_cast < CK_C_GetFunctionList >
( reinterpret_cast < long long >
( dlsym ( _lib , " C_GetFunctionList " ) ) ) ) ;
# else
CK_C_GetFunctionList fnl
( ( CK_C_GetFunctionList ) GetProcAddress ( _lib , " C_GetFunctionList " ) ) ;
# endif
if ( ! fnl )
throw exception ( " required library symbol C_GetFunctionList not found in "
+ library ) ;
CRYPTOLOG ( " Got C_GetFunctionList, now call it " ) ;
//! calls @c C_GetFunctionList
return check ( fnl ( & _fn ) , CRYPTOKI_FN_LOG ( " C_GetFunctionList " ) ) ;
}
bool Library : : Init : : check ( CK_RV result , const std : : string & context ) {
_res = result ;
if ( _exc & & ! * this ) {
if ( context . size ( ) ) {
if ( _res = = CKR_PIN_INCORRECT )
throw wrong_pin ( context + " : " + error ( ) ) ;
else
throw access_error ( context + " : " + error ( ) ) ;
} else {
if ( _res = = CKR_PIN_INCORRECT )
throw wrong_pin ( error ( ) ) ;
else
throw access_error ( error ( ) ) ;
}
}
return _res = = CKR_OK ;
}
std : : string Library : : 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 ( ) ;
}
}
}
Library : : Init : : Init ( const std : : string & library , bool exc ) try :
_exc ( exc ) , _res ( CKR_OK ) , _fn ( 0 ) {
CRYPTOLOG ( " library: " < < library ) ;
//! calls @c functionList
if ( ! functionList ( library ) ) return ;
CRYPTOLOG ( " now initialize " < < library ) ;
assert ( _fn ) ;
//! calls @c C_Initialize
check ( _fn - > C_Initialize ( 0 ) , //! @todo add optional argument
CRYPTOKI_FN_LOG ( " C_Initialize " ) ) ;
} catch ( . . . ) {
throw access_error ( CRYPTOKI_FN_LOG ( " C_Initialize " )
+ " : Error in initialization of library " + library ) ;
}
Library : : Init : : ~ Init ( ) {
CRYPTOLOG ( " log " ) ;
try {
//! calls @c C_Finalize
check ( _fn - > C_Finalize ( 0 ) , CRYPTOKI_FN_LOG ( " C_Finalize " ) ) ;
# ifndef WIN32
if ( _lib ) dlclose ( _lib ) ;
_lib = 0 ;
# else
FreeLibrary ( _lib ) ;
_lib = 0 ;
# endif
_fn = 0 ;
} catch ( . . . ) {
if ( ! std : : uncaught_exception ( ) ) throw ;
}
}
Library : : Init : : operator bool ( ) {
return _res = = CKR_OK ;
}
std : : string Library : : Init : : error ( ) {
return error ( _res ) ;
}
/*! @todo Not implemented:
@ code
bool Library : : Init : : getinfo ( ) {
//! calls @c C_GetInfo
return check ( _init . _fn - > C_GetInfo ( CK_INFO_PTR ) ,
CRYPTOKI_FN_LOG ( " C_GetInfo " ) ) ;
}
@ endcode */
SlotList Library : : slotList ( bool tokenPresent , std : : string name ) {
CRYPTOLOG ( " log " ) ;
CRYPTOLOG ( " looking for card name: " ) < < name < < ( tokenPresent ? " with token " : " " ) ;
SlotList res ;
CK_ULONG count ( 0 ) ;
//! calls @c C_GetSlotList
_init - > check ( _init - > _fn - > C_GetSlotList ( tokenPresent ? TRUE : FALSE , 0 , & count ) ,
CRYPTOKI_FN_LOG ( " C_GetSlotList " ) ) ;
CRYPTOLOG ( " found " ) < < count < < " readers, result: " < < ( * this ? " success " : " error " ) ;
if ( ! count | | ! * this ) return res ;
CK_SLOT_ID * slots = 0 ;
try {
CK_RV r ( 0 ) ;
do {
delete [ ] slots ;
slots = new CK_SLOT_ID [ count ] ;
r = _init - > _fn - > C_GetSlotList ( tokenPresent ? TRUE : FALSE , slots , & count ) ;
} while ( r = = CKR_BUFFER_TOO_SMALL ) ;
_init - > check ( r , CRYPTOKI_FN_LOG ( " C_GetSlotList " ) ) ;
if ( ! * this ) return res ;
for ( CK_ULONG i ( 0 ) ; i < count ; + + i ) {
Slot s ( * this , slots [ i ] ) ;
CRYPTOLOG ( " found slot " ) < < s . slotinfo ( ) . slotDescription ;
if ( ! name . size ( ) | | name = = s . slotinfo ( ) . slotDescription ) {
CRYPTOLOG ( " -> slot matches " ) ;
res . push_back ( s ) ;
}
}
} catch ( . . . ) {
delete [ ] slots ;
throw ;
}
delete [ ] slots ;
return res ;
}
//============================================================================
ObjectList Session : : find ( const AttributeList & attrs ) {
CRYPTOLOG ( " log " ) ;
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 . _library - > 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 . _library - > C_FindObjects
( _session , & obj , 1 , & objs ) ,
CRYPTOKI_FN_LOG ( " C_FindObjects " ) ) & & objs ;
res . push_back ( Object ( * this , obj ) ) ) ;
}
//! calls @c C_FindObjectsFinal
check ( _slot . _library - > C_FindObjectsFinal ( _session ) ,
CRYPTOKI_FN_LOG ( " C_FindObjectsFinal " ) ) ;
delete [ ] a ;
return res ;
} catch ( . . . ) {
delete [ ] a ;
throw ;
}
}
//----------------------------------------------------------------------------
ObjectList Session : : find ( const Attribute & a ) {
CRYPTOLOG ( " log " ) ;
AttributeList al ;
al . push_back ( a ) ;
return find ( al ) ;
}
//----------------------------------------------------------------------------
ObjectList Session : : find ( const Attribute & a1 , const Attribute & a2 ) {
CRYPTOLOG ( " log " ) ;
AttributeList al ;
al . push_back ( a1 ) ;
al . push_back ( a2 ) ;
return find ( al ) ;
}
//----------------------------------------------------------------------------
Object Session : : create ( const std : : string & label , const openssl : : X509 & cert ) {
CRYPTOLOG ( " log " ) ;
AttributeList attrs ;
attrs . push_back ( Attribute ( CKA_CLASS )
. from < CK_OBJECT_CLASS > ( CKO_CERTIFICATE ) ) ;
attrs . push_back ( Attribute ( CKA_TOKEN ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_PRIVATE ) . from < CK_BBOOL > ( FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_MODIFIABLE ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_LABEL , label ) ) ;
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_ID , cert . id ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_ISSUER , cert . issuerDER ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_SERIAL_NUMBER , cert . serial ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_VALUE , cert . valueDER ( ) ) ) ;
CRYPTOLOG ( " create: serial = " < < crypto : : hex ( cert . serial ( ) ) ) ;
return create ( attrs ) ;
}
Object Session : : create ( const std : : string & label ,
const openssl : : PrivateKey & key ,
const openssl : : X509 & cert ) {
CRYPTOLOG ( " log " ) ;
int usage ( cert . keyUsageFlags ( ) ) ;
AttributeList attrs ;
attrs . push_back ( Attribute ( CKA_CLASS )
. from < CK_OBJECT_CLASS > ( CKO_PRIVATE_KEY ) ) ;
attrs . push_back ( Attribute ( CKA_TOKEN ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_PRIVATE ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_MODIFIABLE ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_LABEL , label ) ) ;
attrs . push_back ( Attribute ( CKA_KEY_TYPE ) . from < CK_KEY_TYPE > ( CKK_RSA ) ) ;
attrs . push_back ( Attribute ( CKA_ID , cert . id ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_DERIVE ) . from < CK_BBOOL > ( FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_SUBJECT , cert . subjectDER ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_SENSITIVE ) . from < CK_BBOOL > ( TRUE ) ) ;
attrs . push_back ( Attribute ( CKA_SECONDARY_AUTH ) . from < CK_BBOOL > ( FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_DECRYPT ) // Required by Doujak/Inverardi
. from < CK_BBOOL > ( usage & ( X509v3_KU_DATA_ENCIPHERMENT
| ( usage & X509v3_KU_KEY_ENCIPHERMENT ) )
? TRUE : FALSE ) ) ; // instead of CKA_UNWRAP
attrs . push_back ( Attribute ( CKA_SIGN )
. from < CK_BBOOL > ( usage & ( X509v3_KU_DIGITAL_SIGNATURE
| X509v3_KU_NON_REPUDIATION )
? TRUE : FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_SIGN_RECOVER ) // same as CKA_SIGN
. from < CK_BBOOL > ( usage & ( X509v3_KU_DIGITAL_SIGNATURE
| X509v3_KU_NON_REPUDIATION )
? TRUE : FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_EXTRACTABLE ) . from < CK_BBOOL > ( FALSE ) ) ;
attrs . push_back ( Attribute ( CKA_MODULUS , key . modulus ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_PUBLIC_EXPONENT , key . publicExponent ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_PRIVATE_EXPONENT , key . privateExponent ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_PRIME_1 , key . prime1 ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_PRIME_2 , key . prime2 ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_EXPONENT_1 , key . exponent1 ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_EXPONENT_2 , key . exponent2 ( ) ) ) ;
attrs . push_back ( Attribute ( CKA_COEFFICIENT , key . coefficient ( ) ) ) ;
return create ( attrs ) ;
}
//----------------------------------------------------------------------------
Object Session : : create ( const AttributeList & attrs ) {
CRYPTOLOG ( " log " ) ;
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 ] ;
}
for ( AttributeList : : size_type i ( 0 ) ; i < attrs . size ( ) ; + + i ) {
std : : string value ( ( char * ) a [ i ] . pValue , a [ i ] . ulValueLen ) ;
Attribute xxx ( a [ i ] . type , value ) ;
CRYPTOLOG ( " Attribute: " < < xxx . name ( ) < < " = " < < xxx . readableValue ( ) ) ;
} ;
CK_OBJECT_HANDLE object ;
//! calls @c C_CreateObject
check ( _slot . _library - > C_CreateObject
( _session , a , attrs . size ( ) , & object ) ,
CRYPTOKI_FN_LOG ( " C_CreateObject " ) ) ;
delete [ ] a ;
return Object ( * this , object ) ;
} catch ( . . . ) {
delete [ ] a ;
throw ;
}
}
}