diff options
Diffstat (limited to 'openssl/agent/pkcs11/pkcs11.cxx')
-rw-r--r-- | openssl/agent/pkcs11/pkcs11.cxx | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/openssl/agent/pkcs11/pkcs11.cxx b/openssl/agent/pkcs11/pkcs11.cxx new file mode 100644 index 0000000..1cd541d --- /dev/null +++ b/openssl/agent/pkcs11/pkcs11.cxx @@ -0,0 +1,214 @@ +// file : openssl/agent/pkcs11/pkcs11.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <openssl/agent/pkcs11/pkcs11.hxx> + +#include <dlfcn.h> + +#include <libbutl/utility.mxx> // 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<void, module_deleter> module; + static unique_ptr<CK_FUNCTION_LIST, functions_deleter> functions; + + CK_FUNCTION_LIST* + api (const path& p, bool ignore_nonexistent) + { + if (functions != nullptr) + return functions.get (); + + // Load the PKCS#11 module. + // + unique_ptr<void, module_deleter> 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<decltype(f)> ( + 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); + } + } + } +} |