aboutsummaryrefslogtreecommitdiff
path: root/openssl/agent/pkcs11/pkcs11.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/agent/pkcs11/pkcs11.cxx')
-rw-r--r--openssl/agent/pkcs11/pkcs11.cxx214
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);
+ }
+ }
+ }
+}