// file : openssl/agent/pkcs11/pkcs11.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2018 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include #include #include // function_cast() namespace openssl { namespace agent { namespace pkcs11 { using namespace butl; // Deleters. // struct module_deleter { void operator() (void* p) const {if (p != nullptr) dlclose (p);} }; struct functions_deleter { void operator() (CK_FUNCTION_LIST* p) const { if (p != nullptr) p->C_Finalize (nullptr); } }; // API. // static unique_ptr module; static unique_ptr functions; CK_FUNCTION_LIST* api (const path& p, bool ignore_nonexistent) { if (functions != nullptr) return functions.get (); // Load the PKCS#11 module. // unique_ptr mod ( dlopen (p.string ().c_str (), RTLD_NOW)); if (mod == nullptr) { // Note that we cannot distinguish the module absence from other // failure reasons (not readable, has a wrong format, etc) and will // reduce all possible reasons to the 'not found' case. // if (ignore_nonexistent) return nullptr; char* e (dlerror ()); assert (e != nullptr); throw runtime_error (e); } // Initialize the API. // CK_FUNCTION_LIST* fs; { CK_RV (*f) (CK_FUNCTION_LIST**) = function_cast ( dlsym (mod.get (), "C_GetFunctionList")); if (f == nullptr) throw runtime_error ("unable to find PKCS#11 entry point"); CK_RV r (f (&fs)); if (r != CKR_OK) throw_api_error (r, "unable to get PKCS#11 functions"); } // We don't suppose the Cryptoki to be called from multiple threads // and so passing NULL to the initialization function. // CK_RV r (fs->C_Initialize (nullptr /* pInitArgs */)); if (r != CKR_OK) throw_api_error (r, "unable to initialize PKCS#11 API"); functions.reset (fs); module = move (mod); return functions.get (); } CK_FUNCTION_LIST* api () { assert (functions != nullptr); return functions.get (); } struct error_reason { CK_RV error; const char* reason; }; static const error_reason error_reasons[] = { {CKR_CANCEL, "cancel"}, {CKR_HOST_MEMORY, "host memory error"}, {CKR_SLOT_ID_INVALID, "invalid slot id"}, {CKR_GENERAL_ERROR, "general error"}, {CKR_FUNCTION_FAILED, "function failed"}, {CKR_ARGUMENTS_BAD, "invalid arguments"}, {CKR_NO_EVENT, "no event"}, {CKR_NEED_TO_CREATE_THREADS, "need to create threads"}, {CKR_CANT_LOCK, "cannot lock"}, {CKR_ATTRIBUTE_READ_ONLY, "attribute read only"}, {CKR_ATTRIBUTE_SENSITIVE, "attribute sensitive"}, {CKR_ATTRIBUTE_TYPE_INVALID, "attribute type invalid"}, {CKR_ATTRIBUTE_VALUE_INVALID, "attribute value invalid"}, {CKR_DATA_INVALID, "data invalid"}, {CKR_DATA_LEN_RANGE, "data len range"}, {CKR_DEVICE_ERROR, "device error"}, {CKR_DEVICE_MEMORY, "device memory"}, {CKR_DEVICE_REMOVED, "device removed"}, {CKR_ENCRYPTED_DATA_INVALID, "encrypted data invalid"}, {CKR_ENCRYPTED_DATA_LEN_RANGE, "encrypted data len range"}, {CKR_FUNCTION_CANCELED, "function canceled"}, {CKR_FUNCTION_NOT_PARALLEL, "function not parallel"}, {CKR_FUNCTION_NOT_SUPPORTED, "function not supported"}, {CKR_KEY_HANDLE_INVALID, "key handle invalid"}, {CKR_KEY_SIZE_RANGE, "key size range"}, {CKR_KEY_TYPE_INCONSISTENT, "key type inconsistent"}, {CKR_KEY_NOT_NEEDED, "key not needed"}, {CKR_KEY_CHANGED, "key changed"}, {CKR_KEY_NEEDED, "key needed"}, {CKR_KEY_INDIGESTIBLE, "key indigestible"}, {CKR_KEY_FUNCTION_NOT_PERMITTED, "key function not permitted"}, {CKR_KEY_NOT_WRAPPABLE, "key not wrappable"}, {CKR_KEY_UNEXTRACTABLE, "key unextractable"}, {CKR_MECHANISM_INVALID, "mechanism invalid"}, {CKR_MECHANISM_PARAM_INVALID, "mechanism param invalid"}, {CKR_OBJECT_HANDLE_INVALID, "object handle invalid"}, {CKR_OPERATION_ACTIVE, "operation active"}, {CKR_OPERATION_NOT_INITIALIZED, "operation not initialized"}, {CKR_PIN_INCORRECT, "PIN incorrect"}, {CKR_PIN_INVALID, "PIN invalid"}, {CKR_PIN_LEN_RANGE, "invalid PIN length"}, {CKR_PIN_EXPIRED, "PIN expired"}, {CKR_PIN_LOCKED, "PIN locked"}, {CKR_SESSION_CLOSED, "session closed"}, {CKR_SESSION_COUNT, "session count"}, {CKR_SESSION_HANDLE_INVALID, "session handle invalid"}, {CKR_SESSION_PARALLEL_NOT_SUPPORTED, "session parallel not supported"}, {CKR_SESSION_READ_ONLY, "session read only"}, {CKR_SESSION_EXISTS, "session exists"}, {CKR_SESSION_READ_ONLY_EXISTS, "read-only session exists"}, {CKR_SESSION_READ_WRITE_SO_EXISTS, "read/write SO session exists"}, {CKR_SIGNATURE_INVALID, "signature invalid"}, {CKR_SIGNATURE_LEN_RANGE, "signature len range"}, {CKR_TEMPLATE_INCOMPLETE, "incomplete template"}, {CKR_TEMPLATE_INCONSISTENT, "inconsistent template"}, {CKR_TOKEN_NOT_PRESENT, "no PKCS#11 token present"}, {CKR_TOKEN_NOT_RECOGNIZED, "PKCS#11 token not recognized"}, {CKR_TOKEN_WRITE_PROTECTED, "token write protected"}, {CKR_UNWRAPPING_KEY_HANDLE_INVALID, "unwrapping key handle invalid"}, {CKR_UNWRAPPING_KEY_SIZE_RANGE, "unwrapping key size range"}, {CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, "unwrapping key type inconsistent"}, {CKR_USER_ALREADY_LOGGED_IN, "user already logged in"}, {CKR_USER_NOT_LOGGED_IN, "user not logged in"}, {CKR_USER_PIN_NOT_INITIALIZED, "user PIN not initialized"}, {CKR_USER_TYPE_INVALID, "user type invalid"}, {CKR_USER_ANOTHER_ALREADY_LOGGED_IN, "user another is already logged in"}, {CKR_USER_TOO_MANY_TYPES, "uxsser too many types"}, {CKR_WRAPPED_KEY_INVALID, "wrapped key invalid"}, {CKR_WRAPPED_KEY_LEN_RANGE, "wrapped key len range"}, {CKR_WRAPPING_KEY_HANDLE_INVALID, "wrapping key handle invalid"}, {CKR_WRAPPING_KEY_SIZE_RANGE, "wrapping key size range"}, {CKR_WRAPPING_KEY_TYPE_INCONSISTENT, "wrapping key type inconsistent"}, {CKR_RANDOM_SEED_NOT_SUPPORTED, "random seed not supported"}, {CKR_RANDOM_NO_RNG, "random no rng"}, {CKR_DOMAIN_PARAMS_INVALID, "domain params invalid"}, {CKR_BUFFER_TOO_SMALL, "buffer too small"}, {CKR_SAVED_STATE_INVALID, "saved state invalid"}, {CKR_INFORMATION_SENSITIVE, "information sensitive"}, {CKR_STATE_UNSAVEABLE, "state unsaveable"}, {CKR_CRYPTOKI_NOT_INITIALIZED, "cryptoki not initialized"}, {CKR_CRYPTOKI_ALREADY_INITIALIZED, "cryptoki already initialized"}, {CKR_MUTEX_BAD, "mutex bad"}, {CKR_MUTEX_NOT_LOCKED, "mutex not locked"}, {CKR_VENDOR_DEFINED, "vendor defined"}, {CKR_OK, nullptr} }; [[noreturn]] void throw_api_error (CK_RV error, string what) { what += ": "; const error_reason* e (error_reasons); for (; e->error != error && e->reason != nullptr; ++e) ; if (e->reason != nullptr) what += e->reason; else what += "unknown error " + to_string (error); throw runtime_error (what); } } } }