aboutsummaryrefslogtreecommitdiff
path: root/openssl/agent/pkcs11
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/agent/pkcs11')
-rw-r--r--openssl/agent/pkcs11/agent.cxx621
-rw-r--r--openssl/agent/pkcs11/options.cli79
-rw-r--r--openssl/agent/pkcs11/pkcs11.cxx214
-rw-r--r--openssl/agent/pkcs11/pkcs11.h1436
-rw-r--r--openssl/agent/pkcs11/pkcs11.hxx63
-rw-r--r--openssl/agent/pkcs11/private-key.cxx492
-rw-r--r--openssl/agent/pkcs11/private-key.hxx95
-rw-r--r--openssl/agent/pkcs11/private-key.test.cxx72
-rw-r--r--openssl/agent/pkcs11/private-key.test.testscript22
-rw-r--r--openssl/agent/pkcs11/url.cxx303
-rw-r--r--openssl/agent/pkcs11/url.hxx246
-rw-r--r--openssl/agent/pkcs11/url.test.cxx46
-rw-r--r--openssl/agent/pkcs11/url.test.testscript34
13 files changed, 3723 insertions, 0 deletions
diff --git a/openssl/agent/pkcs11/agent.cxx b/openssl/agent/pkcs11/agent.cxx
new file mode 100644
index 0000000..12b273c
--- /dev/null
+++ b/openssl/agent/pkcs11/agent.cxx
@@ -0,0 +1,621 @@
+// file : openssl/agent/pkcs11/agent.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <sys/un.h> // sockaddr_un
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <signal.h> // kill(), sigaction(), sigemptyset(), SIG*
+#include <unistd.h> // fork(), getpid(), dup2(), setsid()
+#include <termios.h> // tcgetattr(), tcsetattr()
+
+#include <csignal> // sig_atomic_t
+#include <cstring> // strlen(), strcpy(), memset(), memcmp()
+#include <iostream>
+
+#include <iostream> // cout
+
+#include <libbutl/pager.mxx>
+
+#include <openssl/protocol.hxx>
+#include <openssl/diagnostics.hxx>
+
+#include <openssl/agent/pkcs11/url.hxx>
+#include <openssl/agent/pkcs11/options.hxx>
+#include <openssl/agent/pkcs11/private-key.hxx>
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ using namespace std;
+ using namespace butl;
+
+ static void
+ pin_prompt (const string& prompt, char*, size_t);
+
+ // The agent daemon top-level function.
+ //
+ static int
+ daemon (const options&,
+ identity&&,
+ access&&,
+ auto_fd&& sock,
+ char* pin) noexcept;
+
+ static int
+ main (int argc, char* argv[])
+ try
+ {
+ cli::argv_scanner scan (argc, argv);
+
+ // Parse options.
+ //
+ options ops;
+ ops.parse (scan);
+
+ // Version.
+ //
+ if (ops.version ())
+ {
+ cout << "openssl-agent-pkcs11 " << OPENSSL_AGENT_VERSION_ID << endl
+ << "libbutl " << LIBBUTL_VERSION_ID << endl
+ << "Copyright (c) 2014-2018 Code Synthesis Ltd" << endl
+ << "This is free software released under the MIT license."
+ << endl;
+
+ return 0;
+ }
+
+ // Help.
+ //
+ if (ops.help ())
+ {
+ pager p ("openssl-agent-pkcs11 help", false);
+ print_openssl_agent_pkcs11_usage (p.stream ());
+
+ // If the pager failed, assume it has issued some diagnostics.
+ //
+ return p.wait () ? 0 : 1;
+ }
+
+ // Parse arguments.
+ //
+ identity key_identity;
+ access key_access;
+
+ try
+ {
+ string u (scan.more () ? scan.next () : "");
+ if (u.empty ())
+ fail << "private key URL argument expected";
+
+ url key_url (u);
+
+ key_identity = identity (key_url);
+ key_access = access (key_url);
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid PKCS#11 URL: " << e;
+ }
+
+ try
+ {
+ // Prompt the user for a token PIN unless it is already specified as
+ // an access attribute in the URL.
+ //
+ char pin[65]; // NULL character-terminated PIN.
+
+ if (!key_access.pin_value)
+ pin_prompt ("Enter PIN for PKCS#11", pin, sizeof (pin));
+
+ // Open the agent communication socket and fail if the path is
+ // already taken. We could probably deal with the faulty case
+ // ourselves but let's not complicate things for now.
+ //
+ auto_fd sock (socket (AF_UNIX, SOCK_STREAM, 0));
+
+ if (sock.get () == -1)
+ throw_system_error (errno);
+
+ path sock_path (path::temp_path ("openssl-agent-pkcs11"));
+
+ struct sockaddr_un addr;
+ memset (&addr, 0, sizeof (addr));
+ addr.sun_family = AF_UNIX;
+
+ if (sock_path.string ().size () >= sizeof (addr.sun_path))
+ throw_generic_error (ENAMETOOLONG);
+
+ strcpy (addr.sun_path, sock_path.string ().c_str ());
+
+ // Creates the socket filesystem entry.
+ //
+ if (bind (sock.get (),
+ reinterpret_cast<sockaddr*> (&addr),
+ sizeof (addr)) == -1)
+ throw_system_error (errno);
+
+ auto_rmfile rm (sock_path);
+
+ if (listen (sock.get (), 20 /* backlog */) == -1)
+ throw_system_error (errno);
+
+ // Fork off the agent daemon.
+ //
+ pid_t pid (fork ());
+
+ if (pid == -1)
+ throw_system_error (errno);
+
+ // Run the agent daemon in the child process.
+ //
+ if (pid == 0)
+ return daemon (ops,
+ move (key_identity),
+ move (key_access),
+ move (sock),
+ !key_access.pin_value ? pin : nullptr);
+
+ // Erase the no longer needed PIN.
+ //
+ mem_clear (pin, sizeof (pin));
+
+ // The child now is in charge for the socket filesystem entry.
+ //
+ rm.cancel ();
+
+ sock.close ();
+
+ // Send the init request to the agent to make sure that it is alive
+ // and has successfully initialized the key. Issue the received from
+ // the agent diagnostics and exit with non-zero status if the
+ // initialization failed. Note that the daemon will also exit right
+ // after the response in this case.
+ //
+ {
+ sock = connect (sock_path);
+
+ ifdstream is (fddup (sock.get ()));
+ ofdstream os (move (sock));
+
+ os << request ("init");
+ os.close ();
+
+ response r;
+ is >> r;
+
+ if (r.status != 0)
+ {
+ text << r.error;
+ return r.status;
+ }
+ }
+
+ // Let's mimic the 'ssh-agent -s' command output.
+ //
+ cout << "OPENSSL_AGENT_PKCS11_SOCK=" << sock_path << "; "
+ << "export OPENSSL_AGENT_PKCS11_SOCK;\n"
+ << "OPENSSL_AGENT_PKCS11_PID=" << pid << "; "
+ << "export OPENSSL_AGENT_PKCS11_PID;\n"
+ << "echo Agent pid " << pid << endl;
+
+ return 0;
+ }
+ catch (const io_error&)
+ {
+ fail << "unable to communicate with daemon";
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to start daemon: " << e;
+ }
+
+ return 0;
+ }
+ catch (const failed&)
+ {
+ return 1; // Diagnostics has already been issued.
+ }
+ catch (const cli::exception& e)
+ {
+ error << e;
+ return 1;
+ }
+
+ // Prompt for the PIN.
+ //
+ // We would be happy to use getpass() functions but it is mentioned as
+ // obsolete in the man page and is likely to be removed from the glibc
+ // future versions. Thus, we will provide our own implementation of the
+ // function that is inspired by the openssh implementation.
+ //
+ // Note: _NSIG is Linux-specic.
+ //
+ static volatile sig_atomic_t received_signals[_NSIG];
+
+ extern "C" void
+ handle_signal (int sig)
+ {
+ received_signals[sig] = 1;
+ }
+
+ static void
+ pin_prompt (const string& prompt, char* buf, size_t max_len)
+ {
+ // Note that openssh tries to open /dev/tty for read/write access but
+ // falls back to stdin/stdout on failure. Let's skip the fallback for
+ // simplicity.
+ //
+ try
+ {
+ auto_fd ifd (fdopen ("/dev/tty", fdopen_mode::in));
+ ofdstream os (fdopen ("/dev/tty", fdopen_mode::out));
+
+ // Disable the echo.
+ //
+ termios term_attrs;
+ if (tcgetattr (os.fd (), &term_attrs) == -1)
+ throw_system_error (errno);
+
+ termios na (term_attrs);
+ na.c_lflag &= ~ECHO;
+
+ if (tcsetattr (os.fd (), TCSAFLUSH, &na) == -1)
+ throw_system_error (errno);
+
+ // Catch signals that would otherwise cause the user to end up with
+ // echo turned off in the shell.
+ //
+ for (size_t i (0); i < _NSIG; ++i)
+ received_signals[i] = 0;
+
+ using sigaction_type = struct sigaction;
+
+ sigaction_type sa;
+ memset (&sa, 0, sizeof (sa));
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = handle_signal;
+
+ // Save the current signal handlers while setting up the new ones.
+ //
+ vector<pair<int, sigaction_type>> sig_handlers;
+
+ const vector<int> sigs ({
+ SIGALRM,
+ SIGHUP,
+ SIGINT,
+ SIGPIPE,
+ SIGQUIT,
+ SIGTERM,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU});
+
+ for (int s: sigs)
+ {
+ sig_handlers.push_back (make_pair (s, sigaction_type ()));
+
+ if (sigaction (s, &sa, &sig_handlers.back ().second) == -1)
+ throw_system_error (errno);
+ }
+
+ // Restore the echo state and signal handlers and resend the
+ // received signals.
+ //
+ auto restore = [&os, &term_attrs, &sig_handlers] ()
+ {
+ if (tcsetattr (os.fd (), TCSAFLUSH, &term_attrs) == -1)
+ throw_system_error (errno);
+
+ for (const pair<int, sigaction_type>& sa: sig_handlers)
+ {
+ if (sigaction (sa.first, &sa.second, nullptr) == -1)
+ throw_system_error (errno);
+ }
+
+ pid_t pid (getpid ());
+ for (int i (0); i < _NSIG; i++)
+ {
+ if (received_signals[i] != 0 && kill (pid, i) == -1)
+ throw_system_error (errno);
+ }
+ };
+
+ auto rst (make_exception_guard ([&restore] ()
+ {
+ try
+ {
+ restore ();
+ }
+ catch (const system_error&)
+ {
+ // Not much we can do here.
+ //
+ }
+ }));
+
+ // Print prompt.
+ //
+ os << prompt << ": " << flush;
+
+ // Read the PIN.
+ //
+ // Reserve space for the terminating NULL character.
+ //
+ size_t n (max_len - 1);
+ size_t i (0);
+ for (; i < n; ++i)
+ {
+ ssize_t r (read (ifd.get (), buf + i, 1));
+ if (r == -1)
+ throw_system_error (errno);
+
+ if (r == 0 || buf[i] == '\n')
+ break;
+ }
+
+ restore ();
+
+ os << endl;
+ os.close ();
+
+ if (i == n)
+ fail << "PIN is too long";
+
+ buf[i] = '\0';
+ }
+ catch (const system_error& e)
+ {
+ fail << "failed to read PIN: " << e;
+ }
+ }
+
+ // Terminate the daemon.
+ //
+ static volatile sig_atomic_t exit_requested (0); // Can be used as bool.
+
+ extern "C" void
+ handle_term (int /* sig */)
+ {
+ exit_requested = 1;
+
+ // Now accept() will wakeup, set errno to EINTR, and return with -1.
+ //
+ }
+
+ // Run the daemon.
+ //
+ static int
+ daemon (const options& ops,
+ identity&& ki,
+ access&& ka,
+ auto_fd&& sc,
+ char* pin) noexcept
+ try
+ {
+ // Demonize ourselves.
+ //
+ {
+ if (setsid () == -1)
+ throw_system_error (errno);
+
+ path ("/").current_directory ();
+
+ auto_fd nd (fdnull ());
+
+ auto redir = [&nd] (int sd)
+ {
+ if (dup2 (nd.get (), sd) == -1)
+ throw_system_error (errno);
+ };
+
+ redir (0);
+ redir (1);
+ redir (2);
+ }
+
+ auto_fd sock (move (sc));
+ identity key_identity (move (ki));
+ access key_access (move (ka));
+
+ struct sigaction sa;
+ memset (&sa, 0, sizeof (sa));
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = handle_term;
+
+ if (sigaction (SIGTERM, &sa, nullptr) == -1)
+ throw_system_error (errno);
+
+ // It would be natural to create the key at the time of receiving the
+ // init request. However, we need to erase the PIN as soon as
+ // possible. Thus, we will create it now. In case of failure we will
+ // save the error to use for the upcoming init request response.
+ //
+ private_key key;
+
+ // If present, indicates that we still expect the init request. Will
+ // set it to nullopt after init request processing.
+ //
+ optional<string> init_error;
+
+ try
+ {
+ optional<simulate_outcome> s;
+ if (ops.simulate_specified ())
+ s = ops.simulate ();
+
+ key = private_key (key_identity, key_access, pin, s);
+ init_error = "";
+ }
+ catch (const invalid_argument& e)
+ {
+ init_error = string ("error: ") + e.what ();
+ }
+ catch (const runtime_error& e)
+ {
+ init_error = string ("error: ") + e.what ();
+ }
+
+ // Erase the no longer needed PIN.
+ //
+ if (pin != nullptr)
+ mem_clear (pin, strlen (pin));
+
+ // Run the request processing loop.
+ //
+ while (true)
+ {
+ // Accept the client connection.
+ //
+ auto_fd fd (
+ accept (sock.get (), nullptr /* addr */, nullptr /* addrlen */));
+
+ if (exit_requested)
+ break;
+
+ if (fd.get () == -1)
+ {
+ if (errno == EINTR || errno == ECONNABORTED || errno == EPROTO)
+ continue;
+
+ throw_system_error (errno);
+ }
+
+ // If we fail to duplicate the file descriptor, then we are probably
+ // out of resources. Anyway we can't do much about it and will bail
+ // out.
+ //
+ ifdstream is (fddup (fd.get ()));
+
+ try
+ {
+ ofdstream os (move (fd));
+
+ // Respond to the client until he sends valid requests.
+ //
+ while (is.peek () != ifdstream::traits_type::eof ())
+ {
+ request rq;
+ is >> rq;
+
+ // The init request must be the first and only one.
+ //
+ if (rq.cmd == "init")
+ {
+ if (!init_error)
+ {
+ os << response ("error: already initialized");
+ break;
+ }
+
+ if (!init_error->empty ())
+ {
+ os << response (*init_error);
+ os.close ();
+
+ throw runtime_error (*init_error);
+ }
+
+ init_error = nullopt; // We don't expect init anymore.
+ os << response (); // Success.
+ continue;
+ }
+
+ if (init_error)
+ {
+ os << response ("error: not initialized");
+ break;
+ }
+
+ // Process the sign request.
+ //
+ if (rq.cmd == "sign")
+ {
+ // Parse and validate the request arguments (key URL and
+ // simulate outcome).
+ //
+ if (rq.args.size () != 2)
+ {
+ os << response ("error: invalid args");
+ break;
+ }
+
+ identity k;
+
+ try
+ {
+ k = identity (url (rq.args[0]));
+ }
+ catch (const invalid_argument& e)
+ {
+ os << response (
+ string ("error: invalid private key URL: ") + e.what ());
+
+ break;
+ }
+
+ optional<simulate_outcome> sim;
+
+ if (!rq.args[1].empty ())
+ try
+ {
+ sim = to_simulate_outcome (rq.args[1]);
+ }
+ catch (const invalid_argument& e)
+ {
+ os << response (string ("error: ") + e.what ());
+ break;
+ }
+
+ if (k != key_identity)
+ {
+ os << response ("error: private key doesn't match");
+ break;
+ }
+
+ try
+ {
+ os << response (key.sign (rq.input, sim));
+ }
+ catch (const runtime_error& e)
+ {
+ os << response (string ("error: ") + e.what ());
+ break;
+ }
+ }
+ }
+
+ // Close the client connection.
+ //
+ is.close ();
+ os.close ();
+ }
+ catch (const io_error&)
+ {
+ // The client is presumably dead.
+ //
+ }
+ }
+
+ return 0;
+ }
+ catch (const std::exception&)
+ {
+ // There is no way we can complain.
+ //
+ return 1;
+ }
+ }
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ return openssl::agent::pkcs11::main (argc, argv);
+}
diff --git a/openssl/agent/pkcs11/options.cli b/openssl/agent/pkcs11/options.cli
new file mode 100644
index 0000000..9c31b53
--- /dev/null
+++ b/openssl/agent/pkcs11/options.cli
@@ -0,0 +1,79 @@
+// file : openssl/agent/pkcs11/options.cli
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+include <openssl/options.cli>;
+
+"\section=1"
+"\name=openssl-agent-pkcs11"
+"\summary=OpenSSL PKCS#11 key agent"
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ {
+ "<options> <url>",
+
+ "
+ \h|SYNOPSIS|
+
+ \c{\b{openssl-agent-pkcs11 --help}\n
+ \b{openssl-agent-pkcs11 --version}\n
+ \b{openssl-agent-pkcs11} [<options>] <url>}
+
+ \h|DESCRIPTION|
+
+ The \cb{PKCS#11} key agent prompts for a PIN for the specified token
+ and forks off the daemon, which unlocks the key, opens a UNIX domain
+ socket, and waits for cryptographic operation requests from the
+ OpenSSL client \l{openssl-client(1)}. The agent also prints to
+ \cb{stdout} a shell script fragment that sets the environment
+ variables necessary for locating the agent. See the ENVIRONMENT
+ section for details.
+
+ The daemon can be run in the simulation mode without actually logging
+ into the \cb{PKCS#11} token. If the \cb{--simulate} option is
+ specified with the \cb{success} outcome, the daemon pretends to unlock
+ the requested key and responds with a dummy signature to the
+ subsequent data signing requests. The \cb{failure} outcome causes the
+ daemon to exit with non-zero status, as if it failed to find the key.
+ This mode is mostly useful for testing.
+ "
+ }
+
+ class options
+ {
+ "\h|OPTIONS|"
+
+ bool --help {"Print usage information and exit."}
+ bool --version {"Print version and exit."}
+
+ simulate_outcome --simulate
+ {
+ "<outcome>",
+ "Run the daemon in the simulation mode."
+ }
+ };
+
+ "
+ \h|ENVIRONMENT|
+
+ The printed shell script fragment sets the
+ \cb{OPENSSL_AGENT_PKCS11_SOCK} and \cb{OPENSSL_AGENT_PKCS11_PID}
+ environment variables. The former refers to the Unix-domain socket that
+ should be used by \cb{openssl-client(1)} for communicating with the
+ daemon. The latter contains the daemon process id that can be used to
+ terminate the daemon by sending it the \cb{SIGTERM} signal.
+ "
+
+ "
+ \h|EXIT STATUS|
+
+ Non-zero exit status is returned in case of an error.
+ "
+ }
+ }
+}
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);
+ }
+ }
+ }
+}
diff --git a/openssl/agent/pkcs11/pkcs11.h b/openssl/agent/pkcs11/pkcs11.h
new file mode 100644
index 0000000..8219b96
--- /dev/null
+++ b/openssl/agent/pkcs11/pkcs11.h
@@ -0,0 +1,1436 @@
+/* pkcs11.h
+ Copyright 2006, 2007 g10 Code GmbH
+ Copyright 2006 Andreas Jellinghaus
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. */
+
+/* Please submit changes back to the Scute project at
+ http://www.scute.org/ (or send them to marcus@g10code.com), so that
+ they can be picked up by other projects from there as well. */
+
+/* This file is a modified implementation of the PKCS #11 standard by
+ RSA Security Inc. It is mostly a drop-in replacement, with the
+ following change:
+
+ This header file does not require any macro definitions by the user
+ (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros
+ for you (if useful, some are missing, let me know if you need
+ more).
+
+ There is an additional API available that does comply better to the
+ GNU coding standard. It can be switched on by defining
+ CRYPTOKI_GNU before including this header file. For this, the
+ following changes are made to the specification:
+
+ All structure types are changed to a "struct ck_foo" where CK_FOO
+ is the type name in PKCS #11.
+
+ All non-structure types are changed to ck_foo_t where CK_FOO is the
+ lowercase version of the type name in PKCS #11. The basic types
+ (CK_ULONG et al.) are removed without substitute.
+
+ All members of structures are modified in the following way: Type
+ indication prefixes are removed, and underscore characters are
+ inserted before words. Then the result is lowercased.
+
+ Note that function names are still in the original case, as they
+ need for ABI compatibility.
+
+ CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use
+ <stdbool.h>.
+
+ If CRYPTOKI_COMPAT is defined before including this header file,
+ then none of the API changes above take place, and the API is the
+ one defined by the PKCS #11 standard. */
+
+#ifndef PKCS11_H
+#define PKCS11_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* The version of cryptoki we implement. The revision is changed with
+ each modification of this file. If you do not use the "official"
+ version of this file, please consider deleting the revision macro
+ (you may use a macro with a different name to keep track of your
+ versions). */
+#define CRYPTOKI_VERSION_MAJOR 2
+#define CRYPTOKI_VERSION_MINOR 20
+#define CRYPTOKI_VERSION_REVISION 6
+
+
+/* Compatibility interface is default, unless CRYPTOKI_GNU is
+ given. */
+#ifndef CRYPTOKI_GNU
+#ifndef CRYPTOKI_COMPAT
+#define CRYPTOKI_COMPAT 1
+#endif
+#endif
+
+/* System dependencies. */
+
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+
+/* There is a matching pop below. */
+#pragma pack(push, cryptoki, 1)
+
+#ifdef CRYPTOKI_EXPORTS
+#define CK_SPEC __declspec(dllexport)
+#else
+#define CK_SPEC __declspec(dllimport)
+#endif
+
+#else
+
+#define CK_SPEC
+
+#endif
+
+#ifdef CRYPTOKI_COMPAT
+ /* If we are in compatibility mode, switch all exposed names to the
+ PKCS #11 variant. There are corresponding #undefs below. */
+
+#define ck_flags_t CK_FLAGS
+#define ck_version _CK_VERSION
+
+#define ck_info _CK_INFO
+#define cryptoki_version cryptokiVersion
+#define manufacturer_id manufacturerID
+#define library_description libraryDescription
+#define library_version libraryVersion
+
+#define ck_notification_t CK_NOTIFICATION
+#define ck_slot_id_t CK_SLOT_ID
+
+#define ck_slot_info _CK_SLOT_INFO
+#define slot_description slotDescription
+#define hardware_version hardwareVersion
+#define firmware_version firmwareVersion
+
+#define ck_token_info _CK_TOKEN_INFO
+#define serial_number serialNumber
+#define max_session_count ulMaxSessionCount
+#define session_count ulSessionCount
+#define max_rw_session_count ulMaxRwSessionCount
+#define rw_session_count ulRwSessionCount
+#define max_pin_len ulMaxPinLen
+#define min_pin_len ulMinPinLen
+#define total_public_memory ulTotalPublicMemory
+#define free_public_memory ulFreePublicMemory
+#define total_private_memory ulTotalPrivateMemory
+#define free_private_memory ulFreePrivateMemory
+#define utc_time utcTime
+
+#define ck_session_handle_t CK_SESSION_HANDLE
+#define ck_user_type_t CK_USER_TYPE
+#define ck_state_t CK_STATE
+
+#define ck_session_info _CK_SESSION_INFO
+#define slot_id slotID
+#define device_error ulDeviceError
+
+#define ck_object_handle_t CK_OBJECT_HANDLE
+#define ck_object_class_t CK_OBJECT_CLASS
+#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE
+#define ck_key_type_t CK_KEY_TYPE
+#define ck_certificate_type_t CK_CERTIFICATE_TYPE
+#define ck_attribute_type_t CK_ATTRIBUTE_TYPE
+
+#define ck_attribute _CK_ATTRIBUTE
+#define value pValue
+#define value_len ulValueLen
+
+#define ck_date _CK_DATE
+
+#define ck_mechanism_type_t CK_MECHANISM_TYPE
+
+#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE
+
+#define ck_mechanism _CK_MECHANISM
+#define parameter pParameter
+#define parameter_len ulParameterLen
+
+#define ck_mechanism_info _CK_MECHANISM_INFO
+#define min_key_size ulMinKeySize
+#define max_key_size ulMaxKeySize
+
+#define ck_rv_t CK_RV
+#define ck_notify_t CK_NOTIFY
+
+#define ck_function_list _CK_FUNCTION_LIST
+
+#define ck_createmutex_t CK_CREATEMUTEX
+#define ck_destroymutex_t CK_DESTROYMUTEX
+#define ck_lockmutex_t CK_LOCKMUTEX
+#define ck_unlockmutex_t CK_UNLOCKMUTEX
+
+#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS
+#define create_mutex CreateMutex
+#define destroy_mutex DestroyMutex
+#define lock_mutex LockMutex
+#define unlock_mutex UnlockMutex
+#define reserved pReserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+typedef unsigned long ck_flags_t;
+
+struct ck_version
+{
+ unsigned char major;
+ unsigned char minor;
+};
+
+
+struct ck_info
+{
+ struct ck_version cryptoki_version;
+ unsigned char manufacturer_id[32];
+ ck_flags_t flags;
+ unsigned char library_description[32];
+ struct ck_version library_version;
+};
+
+
+typedef unsigned long ck_notification_t;
+
+#define CKN_SURRENDER (0UL)
+
+
+typedef unsigned long ck_slot_id_t;
+
+
+struct ck_slot_info
+{
+ unsigned char slot_description[64];
+ unsigned char manufacturer_id[32];
+ ck_flags_t flags;
+ struct ck_version hardware_version;
+ struct ck_version firmware_version;
+};
+
+
+#define CKF_TOKEN_PRESENT (1UL << 0)
+#define CKF_REMOVABLE_DEVICE (1UL << 1)
+#define CKF_HW_SLOT (1UL << 2)
+#define CKF_ARRAY_ATTRIBUTE (1UL << 30)
+
+
+struct ck_token_info
+{
+ unsigned char label[32];
+ unsigned char manufacturer_id[32];
+ unsigned char model[16];
+ unsigned char serial_number[16];
+ ck_flags_t flags;
+ unsigned long max_session_count;
+ unsigned long session_count;
+ unsigned long max_rw_session_count;
+ unsigned long rw_session_count;
+ unsigned long max_pin_len;
+ unsigned long min_pin_len;
+ unsigned long total_public_memory;
+ unsigned long free_public_memory;
+ unsigned long total_private_memory;
+ unsigned long free_private_memory;
+ struct ck_version hardware_version;
+ struct ck_version firmware_version;
+ unsigned char utc_time[16];
+};
+
+
+#define CKF_RNG (1UL << 0)
+#define CKF_WRITE_PROTECTED (1UL << 1)
+#define CKF_LOGIN_REQUIRED (1UL << 2)
+#define CKF_USER_PIN_INITIALIZED (1UL << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED (1UL << 5)
+#define CKF_CLOCK_ON_TOKEN (1UL << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH (1UL << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS (1UL << 9)
+#define CKF_TOKEN_INITIALIZED (1UL << 10)
+#define CKF_SECONDARY_AUTHENTICATION (1UL << 11)
+#define CKF_USER_PIN_COUNT_LOW (1UL << 16)
+#define CKF_USER_PIN_FINAL_TRY (1UL << 17)
+#define CKF_USER_PIN_LOCKED (1UL << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED (1UL << 19)
+#define CKF_SO_PIN_COUNT_LOW (1UL << 20)
+#define CKF_SO_PIN_FINAL_TRY (1UL << 21)
+#define CKF_SO_PIN_LOCKED (1UL << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED (1UL << 23)
+
+#define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1)
+#define CK_EFFECTIVELY_INFINITE (0UL)
+
+
+typedef unsigned long ck_session_handle_t;
+
+#define CK_INVALID_HANDLE (0UL)
+
+
+typedef unsigned long ck_user_type_t;
+
+#define CKU_SO (0UL)
+#define CKU_USER (1UL)
+#define CKU_CONTEXT_SPECIFIC (2UL)
+
+
+typedef unsigned long ck_state_t;
+
+#define CKS_RO_PUBLIC_SESSION (0UL)
+#define CKS_RO_USER_FUNCTIONS (1UL)
+#define CKS_RW_PUBLIC_SESSION (2UL)
+#define CKS_RW_USER_FUNCTIONS (3UL)
+#define CKS_RW_SO_FUNCTIONS (4UL)
+
+
+struct ck_session_info
+{
+ ck_slot_id_t slot_id;
+ ck_state_t state;
+ ck_flags_t flags;
+ unsigned long device_error;
+};
+
+#define CKF_RW_SESSION (1UL << 1)
+#define CKF_SERIAL_SESSION (1UL << 2)
+
+
+typedef unsigned long ck_object_handle_t;
+
+
+typedef unsigned long ck_object_class_t;
+
+#define CKO_DATA (0UL)
+#define CKO_CERTIFICATE (1UL)
+#define CKO_PUBLIC_KEY (2UL)
+#define CKO_PRIVATE_KEY (3UL)
+#define CKO_SECRET_KEY (4UL)
+#define CKO_HW_FEATURE (5UL)
+#define CKO_DOMAIN_PARAMETERS (6UL)
+#define CKO_MECHANISM (7UL)
+#define CKO_VENDOR_DEFINED (1UL << 31)
+
+
+typedef unsigned long ck_hw_feature_type_t;
+
+#define CKH_MONOTONIC_COUNTER (1UL)
+#define CKH_CLOCK (2UL)
+#define CKH_USER_INTERFACE (3UL)
+#define CKH_VENDOR_DEFINED (1UL << 31)
+
+
+typedef unsigned long ck_key_type_t;
+
+#define CKK_RSA (0UL)
+#define CKK_DSA (1UL)
+#define CKK_DH (2UL)
+#define CKK_ECDSA (3UL)
+#define CKK_EC (3UL)
+#define CKK_X9_42_DH (4UL)
+#define CKK_KEA (5UL)
+#define CKK_GENERIC_SECRET (0x10UL)
+#define CKK_RC2 (0x11UL)
+#define CKK_RC4 (0x12UL)
+#define CKK_DES (0x13UL)
+#define CKK_DES2 (0x14UL)
+#define CKK_DES3 (0x15UL)
+#define CKK_CAST (0x16UL)
+#define CKK_CAST3 (0x17UL)
+#define CKK_CAST128 (0x18UL)
+#define CKK_RC5 (0x19UL)
+#define CKK_IDEA (0x1aUL)
+#define CKK_SKIPJACK (0x1bUL)
+#define CKK_BATON (0x1cUL)
+#define CKK_JUNIPER (0x1dUL)
+#define CKK_CDMF (0x1eUL)
+#define CKK_AES (0x1fUL)
+#define CKK_BLOWFISH (0x20UL)
+#define CKK_TWOFISH (0x21UL)
+#define CKK_GOSTR3410 (0x30UL)
+#define CKK_GOSTR3411 (0x31UL)
+#define CKK_GOST28147 (0x32UL)
+#define CKK_VENDOR_DEFINED (1UL << 31)
+
+
+typedef unsigned long ck_certificate_type_t;
+
+#define CKC_X_509 (0UL)
+#define CKC_X_509_ATTR_CERT (1UL)
+#define CKC_WTLS (2UL)
+#define CKC_VENDOR_DEFINED (1UL << 31)
+
+
+typedef unsigned long ck_attribute_type_t;
+
+#define CKA_CLASS (0UL)
+#define CKA_TOKEN (1UL)
+#define CKA_PRIVATE (2UL)
+#define CKA_LABEL (3UL)
+#define CKA_APPLICATION (0x10UL)
+#define CKA_VALUE (0x11UL)
+#define CKA_OBJECT_ID (0x12UL)
+#define CKA_CERTIFICATE_TYPE (0x80UL)
+#define CKA_ISSUER (0x81UL)
+#define CKA_SERIAL_NUMBER (0x82UL)
+#define CKA_AC_ISSUER (0x83UL)
+#define CKA_OWNER (0x84UL)
+#define CKA_ATTR_TYPES (0x85UL)
+#define CKA_TRUSTED (0x86UL)
+#define CKA_CERTIFICATE_CATEGORY (0x87UL)
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88UL)
+#define CKA_URL (0x89UL)
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8aUL)
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8bUL)
+#define CKA_CHECK_VALUE (0x90UL)
+#define CKA_KEY_TYPE (0x100UL)
+#define CKA_SUBJECT (0x101UL)
+#define CKA_ID (0x102UL)
+#define CKA_SENSITIVE (0x103UL)
+#define CKA_ENCRYPT (0x104UL)
+#define CKA_DECRYPT (0x105UL)
+#define CKA_WRAP (0x106UL)
+#define CKA_UNWRAP (0x107UL)
+#define CKA_SIGN (0x108UL)
+#define CKA_SIGN_RECOVER (0x109UL)
+#define CKA_VERIFY (0x10aUL)
+#define CKA_VERIFY_RECOVER (0x10bUL)
+#define CKA_DERIVE (0x10cUL)
+#define CKA_START_DATE (0x110UL)
+#define CKA_END_DATE (0x111UL)
+#define CKA_MODULUS (0x120UL)
+#define CKA_MODULUS_BITS (0x121UL)
+#define CKA_PUBLIC_EXPONENT (0x122UL)
+#define CKA_PRIVATE_EXPONENT (0x123UL)
+#define CKA_PRIME_1 (0x124UL)
+#define CKA_PRIME_2 (0x125UL)
+#define CKA_EXPONENT_1 (0x126UL)
+#define CKA_EXPONENT_2 (0x127UL)
+#define CKA_COEFFICIENT (0x128UL)
+#define CKA_PRIME (0x130UL)
+#define CKA_SUBPRIME (0x131UL)
+#define CKA_BASE (0x132UL)
+#define CKA_PRIME_BITS (0x133UL)
+#define CKA_SUB_PRIME_BITS (0x134UL)
+#define CKA_VALUE_BITS (0x160UL)
+#define CKA_VALUE_LEN (0x161UL)
+#define CKA_EXTRACTABLE (0x162UL)
+#define CKA_LOCAL (0x163UL)
+#define CKA_NEVER_EXTRACTABLE (0x164UL)
+#define CKA_ALWAYS_SENSITIVE (0x165UL)
+#define CKA_KEY_GEN_MECHANISM (0x166UL)
+#define CKA_MODIFIABLE (0x170UL)
+#define CKA_ECDSA_PARAMS (0x180UL)
+#define CKA_EC_PARAMS (0x180UL)
+#define CKA_EC_POINT (0x181UL)
+#define CKA_SECONDARY_AUTH (0x200UL)
+#define CKA_AUTH_PIN_FLAGS (0x201UL)
+#define CKA_ALWAYS_AUTHENTICATE (0x202UL)
+#define CKA_WRAP_WITH_TRUSTED (0x210UL)
+#define CKA_GOSTR3410_PARAMS (0x250UL)
+#define CKA_GOSTR3411_PARAMS (0x251UL)
+#define CKA_GOST28147_PARAMS (0x252UL)
+#define CKA_HW_FEATURE_TYPE (0x300UL)
+#define CKA_RESET_ON_INIT (0x301UL)
+#define CKA_HAS_RESET (0x302UL)
+#define CKA_PIXEL_X (0x400UL)
+#define CKA_PIXEL_Y (0x401UL)
+#define CKA_RESOLUTION (0x402UL)
+#define CKA_CHAR_ROWS (0x403UL)
+#define CKA_CHAR_COLUMNS (0x404UL)
+#define CKA_COLOR (0x405UL)
+#define CKA_BITS_PER_PIXEL (0x406UL)
+#define CKA_CHAR_SETS (0x480UL)
+#define CKA_ENCODING_METHODS (0x481UL)
+#define CKA_MIME_TYPES (0x482UL)
+#define CKA_MECHANISM_TYPE (0x500UL)
+#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501UL)
+#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502UL)
+#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503UL)
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211UL)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212UL)
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL)
+#define CKA_VENDOR_DEFINED (1UL << 31)
+
+
+struct ck_attribute
+{
+ ck_attribute_type_t type;
+ void *value;
+ unsigned long value_len;
+};
+
+
+struct ck_date
+{
+ unsigned char year[4];
+ unsigned char month[2];
+ unsigned char day[2];
+};
+
+
+typedef unsigned long ck_mechanism_type_t;
+
+#define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL)
+#define CKM_RSA_PKCS (1UL)
+#define CKM_RSA_9796 (2UL)
+#define CKM_RSA_X_509 (3UL)
+#define CKM_MD2_RSA_PKCS (4UL)
+#define CKM_MD5_RSA_PKCS (5UL)
+#define CKM_SHA1_RSA_PKCS (6UL)
+#define CKM_RIPEMD128_RSA_PKCS (7UL)
+#define CKM_RIPEMD160_RSA_PKCS (8UL)
+#define CKM_RSA_PKCS_OAEP (9UL)
+#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xaUL)
+#define CKM_RSA_X9_31 (0xbUL)
+#define CKM_SHA1_RSA_X9_31 (0xcUL)
+#define CKM_RSA_PKCS_PSS (0xdUL)
+#define CKM_SHA1_RSA_PKCS_PSS (0xeUL)
+#define CKM_DSA_KEY_PAIR_GEN (0x10UL)
+#define CKM_DSA (0x11UL)
+#define CKM_DSA_SHA1 (0x12UL)
+#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL)
+#define CKM_DH_PKCS_DERIVE (0x21UL)
+#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL)
+#define CKM_X9_42_DH_DERIVE (0x31UL)
+#define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL)
+#define CKM_X9_42_MQV_DERIVE (0x33UL)
+#define CKM_SHA256_RSA_PKCS (0x40UL)
+#define CKM_SHA384_RSA_PKCS (0x41UL)
+#define CKM_SHA512_RSA_PKCS (0x42UL)
+#define CKM_SHA256_RSA_PKCS_PSS (0x43UL)
+#define CKM_SHA384_RSA_PKCS_PSS (0x44UL)
+#define CKM_SHA512_RSA_PKCS_PSS (0x45UL)
+#define CKM_SHA224_RSA_PKCS (0x46UL)
+#define CKM_SHA224_RSA_PKCS_PSS (0x47UL)
+#define CKM_RC2_KEY_GEN (0x100UL)
+#define CKM_RC2_ECB (0x101UL)
+#define CKM_RC2_CBC (0x102UL)
+#define CKM_RC2_MAC (0x103UL)
+#define CKM_RC2_MAC_GENERAL (0x104UL)
+#define CKM_RC2_CBC_PAD (0x105UL)
+#define CKM_RC4_KEY_GEN (0x110UL)
+#define CKM_RC4 (0x111UL)
+#define CKM_DES_KEY_GEN (0x120UL)
+#define CKM_DES_ECB (0x121UL)
+#define CKM_DES_CBC (0x122UL)
+#define CKM_DES_MAC (0x123UL)
+#define CKM_DES_MAC_GENERAL (0x124UL)
+#define CKM_DES_CBC_PAD (0x125UL)
+#define CKM_DES2_KEY_GEN (0x130UL)
+#define CKM_DES3_KEY_GEN (0x131UL)
+#define CKM_DES3_ECB (0x132UL)
+#define CKM_DES3_CBC (0x133UL)
+#define CKM_DES3_MAC (0x134UL)
+#define CKM_DES3_MAC_GENERAL (0x135UL)
+#define CKM_DES3_CBC_PAD (0x136UL)
+#define CKM_CDMF_KEY_GEN (0x140UL)
+#define CKM_CDMF_ECB (0x141UL)
+#define CKM_CDMF_CBC (0x142UL)
+#define CKM_CDMF_MAC (0x143UL)
+#define CKM_CDMF_MAC_GENERAL (0x144UL)
+#define CKM_CDMF_CBC_PAD (0x145UL)
+#define CKM_MD2 (0x200UL)
+#define CKM_MD2_HMAC (0x201UL)
+#define CKM_MD2_HMAC_GENERAL (0x202UL)
+#define CKM_MD5 (0x210UL)
+#define CKM_MD5_HMAC (0x211UL)
+#define CKM_MD5_HMAC_GENERAL (0x212UL)
+#define CKM_SHA_1 (0x220UL)
+#define CKM_SHA_1_HMAC (0x221UL)
+#define CKM_SHA_1_HMAC_GENERAL (0x222UL)
+#define CKM_RIPEMD128 (0x230UL)
+#define CKM_RIPEMD128_HMAC (0x231UL)
+#define CKM_RIPEMD128_HMAC_GENERAL (0x232UL)
+#define CKM_RIPEMD160 (0x240UL)
+#define CKM_RIPEMD160_HMAC (0x241UL)
+#define CKM_RIPEMD160_HMAC_GENERAL (0x242UL)
+#define CKM_SHA256 (0x250UL)
+#define CKM_SHA256_HMAC (0x251UL)
+#define CKM_SHA256_HMAC_GENERAL (0x252UL)
+#define CKM_SHA224 (0x255UL)
+#define CKM_SHA224_HMAC (0x256UL)
+#define CKM_SHA224_HMAC_GENERAL (0x257UL)
+#define CKM_SHA384 (0x260UL)
+#define CKM_SHA384_HMAC (0x261UL)
+#define CKM_SHA384_HMAC_GENERAL (0x262UL)
+#define CKM_SHA512 (0x270UL)
+#define CKM_SHA512_HMAC (0x271UL)
+#define CKM_SHA512_HMAC_GENERAL (0x272UL)
+#define CKM_CAST_KEY_GEN (0x300UL)
+#define CKM_CAST_ECB (0x301UL)
+#define CKM_CAST_CBC (0x302UL)
+#define CKM_CAST_MAC (0x303UL)
+#define CKM_CAST_MAC_GENERAL (0x304UL)
+#define CKM_CAST_CBC_PAD (0x305UL)
+#define CKM_CAST3_KEY_GEN (0x310UL)
+#define CKM_CAST3_ECB (0x311UL)
+#define CKM_CAST3_CBC (0x312UL)
+#define CKM_CAST3_MAC (0x313UL)
+#define CKM_CAST3_MAC_GENERAL (0x314UL)
+#define CKM_CAST3_CBC_PAD (0x315UL)
+#define CKM_CAST5_KEY_GEN (0x320UL)
+#define CKM_CAST128_KEY_GEN (0x320UL)
+#define CKM_CAST5_ECB (0x321UL)
+#define CKM_CAST128_ECB (0x321UL)
+#define CKM_CAST5_CBC (0x322UL)
+#define CKM_CAST128_CBC (0x322UL)
+#define CKM_CAST5_MAC (0x323UL)
+#define CKM_CAST128_MAC (0x323UL)
+#define CKM_CAST5_MAC_GENERAL (0x324UL)
+#define CKM_CAST128_MAC_GENERAL (0x324UL)
+#define CKM_CAST5_CBC_PAD (0x325UL)
+#define CKM_CAST128_CBC_PAD (0x325UL)
+#define CKM_RC5_KEY_GEN (0x330UL)
+#define CKM_RC5_ECB (0x331UL)
+#define CKM_RC5_CBC (0x332UL)
+#define CKM_RC5_MAC (0x333UL)
+#define CKM_RC5_MAC_GENERAL (0x334UL)
+#define CKM_RC5_CBC_PAD (0x335UL)
+#define CKM_IDEA_KEY_GEN (0x340UL)
+#define CKM_IDEA_ECB (0x341UL)
+#define CKM_IDEA_CBC (0x342UL)
+#define CKM_IDEA_MAC (0x343UL)
+#define CKM_IDEA_MAC_GENERAL (0x344UL)
+#define CKM_IDEA_CBC_PAD (0x345UL)
+#define CKM_GENERIC_SECRET_KEY_GEN (0x350UL)
+#define CKM_CONCATENATE_BASE_AND_KEY (0x360UL)
+#define CKM_CONCATENATE_BASE_AND_DATA (0x362UL)
+#define CKM_CONCATENATE_DATA_AND_BASE (0x363UL)
+#define CKM_XOR_BASE_AND_DATA (0x364UL)
+#define CKM_EXTRACT_KEY_FROM_KEY (0x365UL)
+#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370UL)
+#define CKM_SSL3_MASTER_KEY_DERIVE (0x371UL)
+#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372UL)
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373UL)
+#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374UL)
+#define CKM_TLS_MASTER_KEY_DERIVE (0x375UL)
+#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376UL)
+#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377UL)
+#define CKM_SSL3_MD5_MAC (0x380UL)
+#define CKM_SSL3_SHA1_MAC (0x381UL)
+#define CKM_MD5_KEY_DERIVATION (0x390UL)
+#define CKM_MD2_KEY_DERIVATION (0x391UL)
+#define CKM_SHA1_KEY_DERIVATION (0x392UL)
+#define CKM_PBE_MD2_DES_CBC (0x3a0UL)
+#define CKM_PBE_MD5_DES_CBC (0x3a1UL)
+#define CKM_PBE_MD5_CAST_CBC (0x3a2UL)
+#define CKM_PBE_MD5_CAST3_CBC (0x3a3UL)
+#define CKM_PBE_MD5_CAST5_CBC (0x3a4UL)
+#define CKM_PBE_MD5_CAST128_CBC (0x3a4UL)
+#define CKM_PBE_SHA1_CAST5_CBC (0x3a5UL)
+#define CKM_PBE_SHA1_CAST128_CBC (0x3a5UL)
+#define CKM_PBE_SHA1_RC4_128 (0x3a6UL)
+#define CKM_PBE_SHA1_RC4_40 (0x3a7UL)
+#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8UL)
+#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9UL)
+#define CKM_PBE_SHA1_RC2_128_CBC (0x3aaUL)
+#define CKM_PBE_SHA1_RC2_40_CBC (0x3abUL)
+#define CKM_PKCS5_PBKD2 (0x3b0UL)
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0UL)
+#define CKM_KEY_WRAP_LYNKS (0x400UL)
+#define CKM_KEY_WRAP_SET_OAEP (0x401UL)
+#define CKM_SKIPJACK_KEY_GEN (0x1000UL)
+#define CKM_SKIPJACK_ECB64 (0x1001UL)
+#define CKM_SKIPJACK_CBC64 (0x1002UL)
+#define CKM_SKIPJACK_OFB64 (0x1003UL)
+#define CKM_SKIPJACK_CFB64 (0x1004UL)
+#define CKM_SKIPJACK_CFB32 (0x1005UL)
+#define CKM_SKIPJACK_CFB16 (0x1006UL)
+#define CKM_SKIPJACK_CFB8 (0x1007UL)
+#define CKM_SKIPJACK_WRAP (0x1008UL)
+#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009UL)
+#define CKM_SKIPJACK_RELAYX (0x100aUL)
+#define CKM_KEA_KEY_PAIR_GEN (0x1010UL)
+#define CKM_KEA_KEY_DERIVE (0x1011UL)
+#define CKM_FORTEZZA_TIMESTAMP (0x1020UL)
+#define CKM_BATON_KEY_GEN (0x1030UL)
+#define CKM_BATON_ECB128 (0x1031UL)
+#define CKM_BATON_ECB96 (0x1032UL)
+#define CKM_BATON_CBC128 (0x1033UL)
+#define CKM_BATON_COUNTER (0x1034UL)
+#define CKM_BATON_SHUFFLE (0x1035UL)
+#define CKM_BATON_WRAP (0x1036UL)
+#define CKM_ECDSA_KEY_PAIR_GEN (0x1040UL)
+#define CKM_EC_KEY_PAIR_GEN (0x1040UL)
+#define CKM_ECDSA (0x1041UL)
+#define CKM_ECDSA_SHA1 (0x1042UL)
+#define CKM_ECDSA_SHA224 (0x1043UL)
+#define CKM_ECDSA_SHA256 (0x1044UL)
+#define CKM_ECDSA_SHA384 (0x1045UL)
+#define CKM_ECDSA_SHA512 (0x1046UL)
+#define CKM_ECDH1_DERIVE (0x1050UL)
+#define CKM_ECDH1_COFACTOR_DERIVE (0x1051UL)
+#define CKM_ECMQV_DERIVE (0x1052UL)
+#define CKM_JUNIPER_KEY_GEN (0x1060UL)
+#define CKM_JUNIPER_ECB128 (0x1061UL)
+#define CKM_JUNIPER_CBC128 (0x1062UL)
+#define CKM_JUNIPER_COUNTER (0x1063UL)
+#define CKM_JUNIPER_SHUFFLE (0x1064UL)
+#define CKM_JUNIPER_WRAP (0x1065UL)
+#define CKM_FASTHASH (0x1070UL)
+#define CKM_AES_KEY_GEN (0x1080UL)
+#define CKM_AES_ECB (0x1081UL)
+#define CKM_AES_CBC (0x1082UL)
+#define CKM_AES_MAC (0x1083UL)
+#define CKM_AES_MAC_GENERAL (0x1084UL)
+#define CKM_AES_CBC_PAD (0x1085UL)
+#define CKM_AES_CTR (0x1086UL)
+#define CKM_AES_GCM (0x1087UL)
+#define CKM_AES_CCM (0x1088UL)
+#define CKM_AES_CTS (0x1089UL)
+#define CKM_BLOWFISH_KEY_GEN (0x1090UL)
+#define CKM_BLOWFISH_CBC (0x1091UL)
+#define CKM_TWOFISH_KEY_GEN (0x1092UL)
+#define CKM_TWOFISH_CBC (0x1093UL)
+#define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL)
+#define CKM_GOSTR3410 (0x1201UL)
+#define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL)
+#define CKM_GOSTR3410_KEY_WRAP (0x1203UL)
+#define CKM_GOSTR3410_DERIVE (0x1204UL)
+#define CKM_GOSTR3411 (0x1210UL)
+#define CKM_GOSTR3411_HMAC (0x1211UL)
+#define CKM_GOST28147_KEY_GEN (0x1220UL)
+#define CKM_GOST28147_ECB (0x1221UL)
+#define CKM_GOST28147 (0x1222UL)
+#define CKM_GOST28147_MAC (0x1223UL)
+#define CKM_GOST28147_KEY_WRAP (0x1224UL)
+
+#define CKM_DSA_PARAMETER_GEN (0x2000UL)
+#define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL)
+#define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL)
+#define CKM_VENDOR_DEFINED (1UL << 31)
+
+
+struct ck_mechanism
+{
+ ck_mechanism_type_t mechanism;
+ void *parameter;
+ unsigned long parameter_len;
+};
+
+
+struct ck_mechanism_info
+{
+ unsigned long min_key_size;
+ unsigned long max_key_size;
+ ck_flags_t flags;
+};
+
+#define CKF_HW (1UL << 0)
+#define CKF_ENCRYPT (1UL << 8)
+#define CKF_DECRYPT (1UL << 9)
+#define CKF_DIGEST (1UL << 10)
+#define CKF_SIGN (1UL << 11)
+#define CKF_SIGN_RECOVER (1UL << 12)
+#define CKF_VERIFY (1UL << 13)
+#define CKF_VERIFY_RECOVER (1UL << 14)
+#define CKF_GENERATE (1UL << 15)
+#define CKF_GENERATE_KEY_PAIR (1UL << 16)
+#define CKF_WRAP (1UL << 17)
+#define CKF_UNWRAP (1UL << 18)
+#define CKF_DERIVE (1UL << 19)
+#define CKF_EXTENSION (1UL << 31)
+
+#define CKF_EC_F_P (1UL << 20)
+#define CKF_EC_F_2M (1UL << 21)
+#define CKF_EC_ECPARAMETERS (1UL << 22)
+#define CKF_EC_NAMEDCURVE (1UL << 23)
+#define CKF_EC_UNCOMPRESS (1UL << 24)
+#define CKF_EC_COMPRESS (1UL << 25)
+
+/* Flags for C_WaitForSlotEvent. */
+#define CKF_DONT_BLOCK (1UL)
+
+/* Flags for Key derivation */
+#define CKD_NULL (1UL << 0)
+
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ unsigned long kdf;
+ unsigned long ulSharedDataLen;
+ unsigned char * pSharedData;
+ unsigned long ulPublicDataLen;
+ unsigned char * pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef unsigned long ck_rsa_pkcs_mgf_type_t;
+typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ void *pSourceData;
+ unsigned long ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ ck_mechanism_type_t hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ unsigned long sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+#define CKG_MGF1_SHA1 (0x00000001UL)
+#define CKG_MGF1_SHA224 (0x00000005UL)
+#define CKG_MGF1_SHA256 (0x00000002UL)
+#define CKG_MGF1_SHA384 (0x00000003UL)
+#define CKG_MGF1_SHA512 (0x00000004UL)
+
+#define CKZ_DATA_SPECIFIED (0x00000001UL)
+
+typedef unsigned long ck_rv_t;
+
+
+typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session,
+ ck_notification_t event, void *application);
+
+/* Forward reference. */
+struct ck_function_list;
+
+#define _CK_DECLARE_FUNCTION(name, args) \
+typedef ck_rv_t (*CK_ ## name) args; \
+ck_rv_t CK_SPEC name args
+
+_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args));
+_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved));
+_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info));
+_CK_DECLARE_FUNCTION (C_GetFunctionList,
+ (struct ck_function_list **function_list));
+
+_CK_DECLARE_FUNCTION (C_GetSlotList,
+ (unsigned char token_present, ck_slot_id_t *slot_list,
+ unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetSlotInfo,
+ (ck_slot_id_t slot_id, struct ck_slot_info *info));
+_CK_DECLARE_FUNCTION (C_GetTokenInfo,
+ (ck_slot_id_t slot_id, struct ck_token_info *info));
+_CK_DECLARE_FUNCTION (C_WaitForSlotEvent,
+ (ck_flags_t flags, ck_slot_id_t *slot, void *reserved));
+_CK_DECLARE_FUNCTION (C_GetMechanismList,
+ (ck_slot_id_t slot_id,
+ ck_mechanism_type_t *mechanism_list,
+ unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetMechanismInfo,
+ (ck_slot_id_t slot_id, ck_mechanism_type_t type,
+ struct ck_mechanism_info *info));
+_CK_DECLARE_FUNCTION (C_InitToken,
+ (ck_slot_id_t slot_id, unsigned char *pin,
+ unsigned long pin_len, unsigned char *label));
+_CK_DECLARE_FUNCTION (C_InitPIN,
+ (ck_session_handle_t session, unsigned char *pin,
+ unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_SetPIN,
+ (ck_session_handle_t session, unsigned char *old_pin,
+ unsigned long old_len, unsigned char *new_pin,
+ unsigned long new_len));
+
+_CK_DECLARE_FUNCTION (C_OpenSession,
+ (ck_slot_id_t slot_id, ck_flags_t flags,
+ void *application, ck_notify_t notify,
+ ck_session_handle_t *session));
+_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id));
+_CK_DECLARE_FUNCTION (C_GetSessionInfo,
+ (ck_session_handle_t session,
+ struct ck_session_info *info));
+_CK_DECLARE_FUNCTION (C_GetOperationState,
+ (ck_session_handle_t session,
+ unsigned char *operation_state,
+ unsigned long *operation_state_len));
+_CK_DECLARE_FUNCTION (C_SetOperationState,
+ (ck_session_handle_t session,
+ unsigned char *operation_state,
+ unsigned long operation_state_len,
+ ck_object_handle_t encryption_key,
+ ck_object_handle_t authentication_key));
+_CK_DECLARE_FUNCTION (C_Login,
+ (ck_session_handle_t session, ck_user_type_t user_type,
+ unsigned char *pin, unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_CreateObject,
+ (ck_session_handle_t session,
+ struct ck_attribute *templ,
+ unsigned long count, ck_object_handle_t *object));
+_CK_DECLARE_FUNCTION (C_CopyObject,
+ (ck_session_handle_t session, ck_object_handle_t object,
+ struct ck_attribute *templ, unsigned long count,
+ ck_object_handle_t *new_object));
+_CK_DECLARE_FUNCTION (C_DestroyObject,
+ (ck_session_handle_t session,
+ ck_object_handle_t object));
+_CK_DECLARE_FUNCTION (C_GetObjectSize,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ unsigned long *size));
+_CK_DECLARE_FUNCTION (C_GetAttributeValue,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_SetAttributeValue,
+ (ck_session_handle_t session,
+ ck_object_handle_t object,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjectsInit,
+ (ck_session_handle_t session,
+ struct ck_attribute *templ,
+ unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjects,
+ (ck_session_handle_t session,
+ ck_object_handle_t *object,
+ unsigned long max_object_count,
+ unsigned long *object_count));
+_CK_DECLARE_FUNCTION (C_FindObjectsFinal,
+ (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_EncryptInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Encrypt,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *encrypted_data,
+ unsigned long *encrypted_data_len));
+_CK_DECLARE_FUNCTION (C_EncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_EncryptFinal,
+ (ck_session_handle_t session,
+ unsigned char *last_encrypted_part,
+ unsigned long *last_encrypted_part_len));
+
+_CK_DECLARE_FUNCTION (C_DecryptInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Decrypt,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_data,
+ unsigned long encrypted_data_len,
+ unsigned char *data, unsigned long *data_len));
+_CK_DECLARE_FUNCTION (C_DecryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part, unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_DecryptFinal,
+ (ck_session_handle_t session,
+ unsigned char *last_part,
+ unsigned long *last_part_len));
+
+_CK_DECLARE_FUNCTION (C_DigestInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism));
+_CK_DECLARE_FUNCTION (C_Digest,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *digest,
+ unsigned long *digest_len));
+_CK_DECLARE_FUNCTION (C_DigestUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_DigestKey,
+ (ck_session_handle_t session, ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_DigestFinal,
+ (ck_session_handle_t session,
+ unsigned char *digest,
+ unsigned long *digest_len));
+
+_CK_DECLARE_FUNCTION (C_SignInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Sign,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_SignFinal,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignRecoverInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_SignRecover,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long *signature_len));
+
+_CK_DECLARE_FUNCTION (C_VerifyInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Verify,
+ (ck_session_handle_t session,
+ unsigned char *data, unsigned long data_len,
+ unsigned char *signature,
+ unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_VerifyFinal,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyRecoverInit,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_VerifyRecover,
+ (ck_session_handle_t session,
+ unsigned char *signature,
+ unsigned long signature_len,
+ unsigned char *data,
+ unsigned long *data_len));
+
+_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part,
+ unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_SignEncryptUpdate,
+ (ck_session_handle_t session,
+ unsigned char *part, unsigned long part_len,
+ unsigned char *encrypted_part,
+ unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate,
+ (ck_session_handle_t session,
+ unsigned char *encrypted_part,
+ unsigned long encrypted_part_len,
+ unsigned char *part,
+ unsigned long *part_len));
+
+_CK_DECLARE_FUNCTION (C_GenerateKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ struct ck_attribute *templ,
+ unsigned long count,
+ ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_GenerateKeyPair,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ struct ck_attribute *public_key_template,
+ unsigned long public_key_attribute_count,
+ struct ck_attribute *private_key_template,
+ unsigned long private_key_attribute_count,
+ ck_object_handle_t *public_key,
+ ck_object_handle_t *private_key));
+_CK_DECLARE_FUNCTION (C_WrapKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t wrapping_key,
+ ck_object_handle_t key,
+ unsigned char *wrapped_key,
+ unsigned long *wrapped_key_len));
+_CK_DECLARE_FUNCTION (C_UnwrapKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t unwrapping_key,
+ unsigned char *wrapped_key,
+ unsigned long wrapped_key_len,
+ struct ck_attribute *templ,
+ unsigned long attribute_count,
+ ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_DeriveKey,
+ (ck_session_handle_t session,
+ struct ck_mechanism *mechanism,
+ ck_object_handle_t base_key,
+ struct ck_attribute *templ,
+ unsigned long attribute_count,
+ ck_object_handle_t *key));
+
+_CK_DECLARE_FUNCTION (C_SeedRandom,
+ (ck_session_handle_t session, unsigned char *seed,
+ unsigned long seed_len));
+_CK_DECLARE_FUNCTION (C_GenerateRandom,
+ (ck_session_handle_t session,
+ unsigned char *random_data,
+ unsigned long random_len));
+
+_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session));
+
+
+struct ck_function_list
+{
+ struct ck_version version;
+ CK_C_Initialize C_Initialize;
+ CK_C_Finalize C_Finalize;
+ CK_C_GetInfo C_GetInfo;
+ CK_C_GetFunctionList C_GetFunctionList;
+ CK_C_GetSlotList C_GetSlotList;
+ CK_C_GetSlotInfo C_GetSlotInfo;
+ CK_C_GetTokenInfo C_GetTokenInfo;
+ CK_C_GetMechanismList C_GetMechanismList;
+ CK_C_GetMechanismInfo C_GetMechanismInfo;
+ CK_C_InitToken C_InitToken;
+ CK_C_InitPIN C_InitPIN;
+ CK_C_SetPIN C_SetPIN;
+ CK_C_OpenSession C_OpenSession;
+ CK_C_CloseSession C_CloseSession;
+ CK_C_CloseAllSessions C_CloseAllSessions;
+ CK_C_GetSessionInfo C_GetSessionInfo;
+ CK_C_GetOperationState C_GetOperationState;
+ CK_C_SetOperationState C_SetOperationState;
+ CK_C_Login C_Login;
+ CK_C_Logout C_Logout;
+ CK_C_CreateObject C_CreateObject;
+ CK_C_CopyObject C_CopyObject;
+ CK_C_DestroyObject C_DestroyObject;
+ CK_C_GetObjectSize C_GetObjectSize;
+ CK_C_GetAttributeValue C_GetAttributeValue;
+ CK_C_SetAttributeValue C_SetAttributeValue;
+ CK_C_FindObjectsInit C_FindObjectsInit;
+ CK_C_FindObjects C_FindObjects;
+ CK_C_FindObjectsFinal C_FindObjectsFinal;
+ CK_C_EncryptInit C_EncryptInit;
+ CK_C_Encrypt C_Encrypt;
+ CK_C_EncryptUpdate C_EncryptUpdate;
+ CK_C_EncryptFinal C_EncryptFinal;
+ CK_C_DecryptInit C_DecryptInit;
+ CK_C_Decrypt C_Decrypt;
+ CK_C_DecryptUpdate C_DecryptUpdate;
+ CK_C_DecryptFinal C_DecryptFinal;
+ CK_C_DigestInit C_DigestInit;
+ CK_C_Digest C_Digest;
+ CK_C_DigestUpdate C_DigestUpdate;
+ CK_C_DigestKey C_DigestKey;
+ CK_C_DigestFinal C_DigestFinal;
+ CK_C_SignInit C_SignInit;
+ CK_C_Sign C_Sign;
+ CK_C_SignUpdate C_SignUpdate;
+ CK_C_SignFinal C_SignFinal;
+ CK_C_SignRecoverInit C_SignRecoverInit;
+ CK_C_SignRecover C_SignRecover;
+ CK_C_VerifyInit C_VerifyInit;
+ CK_C_Verify C_Verify;
+ CK_C_VerifyUpdate C_VerifyUpdate;
+ CK_C_VerifyFinal C_VerifyFinal;
+ CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+ CK_C_VerifyRecover C_VerifyRecover;
+ CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+ CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+ CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+ CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+ CK_C_GenerateKey C_GenerateKey;
+ CK_C_GenerateKeyPair C_GenerateKeyPair;
+ CK_C_WrapKey C_WrapKey;
+ CK_C_UnwrapKey C_UnwrapKey;
+ CK_C_DeriveKey C_DeriveKey;
+ CK_C_SeedRandom C_SeedRandom;
+ CK_C_GenerateRandom C_GenerateRandom;
+ CK_C_GetFunctionStatus C_GetFunctionStatus;
+ CK_C_CancelFunction C_CancelFunction;
+ CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+};
+
+
+typedef ck_rv_t (*ck_createmutex_t) (void **mutex);
+typedef ck_rv_t (*ck_destroymutex_t) (void *mutex);
+typedef ck_rv_t (*ck_lockmutex_t) (void *mutex);
+typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex);
+
+
+struct ck_c_initialize_args
+{
+ ck_createmutex_t create_mutex;
+ ck_destroymutex_t destroy_mutex;
+ ck_lockmutex_t lock_mutex;
+ ck_unlockmutex_t unlock_mutex;
+ ck_flags_t flags;
+ void *reserved;
+};
+
+
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1UL << 0)
+#define CKF_OS_LOCKING_OK (1UL << 1)
+
+#define CKR_OK (0UL)
+#define CKR_CANCEL (1UL)
+#define CKR_HOST_MEMORY (2UL)
+#define CKR_SLOT_ID_INVALID (3UL)
+#define CKR_GENERAL_ERROR (5UL)
+#define CKR_FUNCTION_FAILED (6UL)
+#define CKR_ARGUMENTS_BAD (7UL)
+#define CKR_NO_EVENT (8UL)
+#define CKR_NEED_TO_CREATE_THREADS (9UL)
+#define CKR_CANT_LOCK (0xaUL)
+#define CKR_ATTRIBUTE_READ_ONLY (0x10UL)
+#define CKR_ATTRIBUTE_SENSITIVE (0x11UL)
+#define CKR_ATTRIBUTE_TYPE_INVALID (0x12UL)
+#define CKR_ATTRIBUTE_VALUE_INVALID (0x13UL)
+#define CKR_DATA_INVALID (0x20UL)
+#define CKR_DATA_LEN_RANGE (0x21UL)
+#define CKR_DEVICE_ERROR (0x30UL)
+#define CKR_DEVICE_MEMORY (0x31UL)
+#define CKR_DEVICE_REMOVED (0x32UL)
+#define CKR_ENCRYPTED_DATA_INVALID (0x40UL)
+#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41UL)
+#define CKR_FUNCTION_CANCELED (0x50UL)
+#define CKR_FUNCTION_NOT_PARALLEL (0x51UL)
+#define CKR_FUNCTION_NOT_SUPPORTED (0x54UL)
+#define CKR_KEY_HANDLE_INVALID (0x60UL)
+#define CKR_KEY_SIZE_RANGE (0x62UL)
+#define CKR_KEY_TYPE_INCONSISTENT (0x63UL)
+#define CKR_KEY_NOT_NEEDED (0x64UL)
+#define CKR_KEY_CHANGED (0x65UL)
+#define CKR_KEY_NEEDED (0x66UL)
+#define CKR_KEY_INDIGESTIBLE (0x67UL)
+#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68UL)
+#define CKR_KEY_NOT_WRAPPABLE (0x69UL)
+#define CKR_KEY_UNEXTRACTABLE (0x6aUL)
+#define CKR_MECHANISM_INVALID (0x70UL)
+#define CKR_MECHANISM_PARAM_INVALID (0x71UL)
+#define CKR_OBJECT_HANDLE_INVALID (0x82UL)
+#define CKR_OPERATION_ACTIVE (0x90UL)
+#define CKR_OPERATION_NOT_INITIALIZED (0x91UL)
+#define CKR_PIN_INCORRECT (0xa0UL)
+#define CKR_PIN_INVALID (0xa1UL)
+#define CKR_PIN_LEN_RANGE (0xa2UL)
+#define CKR_PIN_EXPIRED (0xa3UL)
+#define CKR_PIN_LOCKED (0xa4UL)
+#define CKR_SESSION_CLOSED (0xb0UL)
+#define CKR_SESSION_COUNT (0xb1UL)
+#define CKR_SESSION_HANDLE_INVALID (0xb3UL)
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4UL)
+#define CKR_SESSION_READ_ONLY (0xb5UL)
+#define CKR_SESSION_EXISTS (0xb6UL)
+#define CKR_SESSION_READ_ONLY_EXISTS (0xb7UL)
+#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8UL)
+#define CKR_SIGNATURE_INVALID (0xc0UL)
+#define CKR_SIGNATURE_LEN_RANGE (0xc1UL)
+#define CKR_TEMPLATE_INCOMPLETE (0xd0UL)
+#define CKR_TEMPLATE_INCONSISTENT (0xd1UL)
+#define CKR_TOKEN_NOT_PRESENT (0xe0UL)
+#define CKR_TOKEN_NOT_RECOGNIZED (0xe1UL)
+#define CKR_TOKEN_WRITE_PROTECTED (0xe2UL)
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0UL)
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1UL)
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2UL)
+#define CKR_USER_ALREADY_LOGGED_IN (0x100UL)
+#define CKR_USER_NOT_LOGGED_IN (0x101UL)
+#define CKR_USER_PIN_NOT_INITIALIZED (0x102UL)
+#define CKR_USER_TYPE_INVALID (0x103UL)
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104UL)
+#define CKR_USER_TOO_MANY_TYPES (0x105UL)
+#define CKR_WRAPPED_KEY_INVALID (0x110UL)
+#define CKR_WRAPPED_KEY_LEN_RANGE (0x112UL)
+#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113UL)
+#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114UL)
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115UL)
+#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120UL)
+#define CKR_RANDOM_NO_RNG (0x121UL)
+#define CKR_DOMAIN_PARAMS_INVALID (0x130UL)
+#define CKR_BUFFER_TOO_SMALL (0x150UL)
+#define CKR_SAVED_STATE_INVALID (0x160UL)
+#define CKR_INFORMATION_SENSITIVE (0x170UL)
+#define CKR_STATE_UNSAVEABLE (0x180UL)
+#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190UL)
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191UL)
+#define CKR_MUTEX_BAD (0x1a0UL)
+#define CKR_MUTEX_NOT_LOCKED (0x1a1UL)
+#define CKR_FUNCTION_REJECTED (0x200UL)
+#define CKR_VENDOR_DEFINED (1UL << 31)
+
+
+/* Compatibility layer. */
+
+#ifdef CRYPTOKI_COMPAT
+
+#undef CK_DEFINE_FUNCTION
+#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name
+
+/* For NULL. */
+#include <stddef.h>
+
+typedef unsigned char CK_BYTE;
+typedef unsigned char CK_CHAR;
+typedef unsigned char CK_UTF8CHAR;
+typedef unsigned char CK_BBOOL;
+typedef unsigned long int CK_ULONG;
+typedef long int CK_LONG;
+typedef CK_BYTE *CK_BYTE_PTR;
+typedef CK_CHAR *CK_CHAR_PTR;
+typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR;
+typedef CK_ULONG *CK_ULONG_PTR;
+typedef void *CK_VOID_PTR;
+typedef void **CK_VOID_PTR_PTR;
+#define CK_FALSE 0
+#define CK_TRUE 1
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#endif
+
+typedef struct ck_version CK_VERSION;
+typedef struct ck_version *CK_VERSION_PTR;
+
+typedef struct ck_info CK_INFO;
+typedef struct ck_info *CK_INFO_PTR;
+
+typedef ck_slot_id_t *CK_SLOT_ID_PTR;
+
+typedef struct ck_slot_info CK_SLOT_INFO;
+typedef struct ck_slot_info *CK_SLOT_INFO_PTR;
+
+typedef struct ck_token_info CK_TOKEN_INFO;
+typedef struct ck_token_info *CK_TOKEN_INFO_PTR;
+
+typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR;
+
+typedef struct ck_session_info CK_SESSION_INFO;
+typedef struct ck_session_info *CK_SESSION_INFO_PTR;
+
+typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR;
+
+typedef ck_object_class_t *CK_OBJECT_CLASS_PTR;
+
+typedef struct ck_attribute CK_ATTRIBUTE;
+typedef struct ck_attribute *CK_ATTRIBUTE_PTR;
+
+typedef struct ck_date CK_DATE;
+typedef struct ck_date *CK_DATE_PTR;
+
+typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
+
+typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR;
+
+typedef struct ck_mechanism CK_MECHANISM;
+typedef struct ck_mechanism *CK_MECHANISM_PTR;
+
+typedef struct ck_mechanism_info CK_MECHANISM_INFO;
+typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR;
+
+typedef struct ck_function_list CK_FUNCTION_LIST;
+typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
+typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
+
+typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS;
+typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
+
+#define NULL_PTR NULL
+
+/* Delete the helper macros defined at the top of the file. */
+#undef ck_flags_t
+#undef ck_version
+
+#undef ck_info
+#undef cryptoki_version
+#undef manufacturer_id
+#undef library_description
+#undef library_version
+
+#undef ck_notification_t
+#undef ck_slot_id_t
+
+#undef ck_slot_info
+#undef slot_description
+#undef hardware_version
+#undef firmware_version
+
+#undef ck_token_info
+#undef serial_number
+#undef max_session_count
+#undef session_count
+#undef max_rw_session_count
+#undef rw_session_count
+#undef max_pin_len
+#undef min_pin_len
+#undef total_public_memory
+#undef free_public_memory
+#undef total_private_memory
+#undef free_private_memory
+#undef utc_time
+
+#undef ck_session_handle_t
+#undef ck_user_type_t
+#undef ck_state_t
+
+#undef ck_session_info
+#undef slot_id
+#undef device_error
+
+#undef ck_object_handle_t
+#undef ck_object_class_t
+#undef ck_hw_feature_type_t
+#undef ck_key_type_t
+#undef ck_certificate_type_t
+#undef ck_attribute_type_t
+
+#undef ck_attribute
+#undef value
+#undef value_len
+
+#undef ck_date
+
+#undef ck_mechanism_type_t
+
+#undef ck_rsa_pkcs_mgf_type_t
+
+#undef ck_mechanism
+#undef parameter
+#undef parameter_len
+
+#undef ck_mechanism_info
+#undef min_key_size
+#undef max_key_size
+
+#undef ck_rv_t
+#undef ck_notify_t
+
+#undef ck_function_list
+
+#undef ck_createmutex_t
+#undef ck_destroymutex_t
+#undef ck_lockmutex_t
+#undef ck_unlockmutex_t
+
+#undef ck_c_initialize_args
+#undef create_mutex
+#undef destroy_mutex
+#undef lock_mutex
+#undef unlock_mutex
+#undef reserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+/* System dependencies. */
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+#pragma pack(pop, cryptoki)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* PKCS11_H */
diff --git a/openssl/agent/pkcs11/pkcs11.hxx b/openssl/agent/pkcs11/pkcs11.hxx
new file mode 100644
index 0000000..e1c90b1
--- /dev/null
+++ b/openssl/agent/pkcs11/pkcs11.hxx
@@ -0,0 +1,63 @@
+// file : openssl/agent/pkcs11/pkcs11.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef OPENSSL_AGENT_PKCS11_PKCS11_HXX
+#define OPENSSL_AGENT_PKCS11_PKCS11_HXX
+
+// PKCS#11 API (Cryptoki) definitions.
+//
+#include <openssl/agent/pkcs11/pkcs11.h>
+
+#include <openssl/types.hxx>
+#include <openssl/utility.hxx>
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ // For simplicity we will not handle multiple PKCS#11 modules
+ // simultaneously. The first one loaded will stay till the end of the
+ // process lifetime.
+ //
+
+ // Return the PKCS#11 API pointer. If requested, ignore non-existent
+ // module returning NULL.
+ //
+ // On the first call load the PKCS#11 module using the specified path
+ // and initialize the API. Return the same pointer on the subsequent
+ // calls regardless of the path. Throw runtime_error if anything goes
+ // wrong.
+ //
+ CK_FUNCTION_LIST*
+ api (const path&, bool ignore_nonexistent = false);
+
+ // Return a pointer to the previously initialized PKCS#11 API.
+ //
+ CK_FUNCTION_LIST*
+ api ();
+
+ // Throw runtime_error describing a PKCS#11 API error.
+ //
+ [[noreturn]] void
+ throw_api_error (CK_RV error, string what);
+
+ // Convert API string representation to a regular one.
+ //
+ // PKCS#11 API struct string members are fixed-sized unsigned character
+ // arrays right-padded with the space character. Return such a string
+ // with the trailing spaces stripped.
+ //
+ inline string
+ api_string (const unsigned char* s, size_t n)
+ {
+ for (; n != 0 && s[n - 1] == ' '; --n) ;
+ return string (reinterpret_cast<const char*> (s), n);
+ }
+ }
+ }
+}
+
+#endif // OPENSSL_AGENT_PKCS11_PKCS11_HXX
diff --git a/openssl/agent/pkcs11/private-key.cxx b/openssl/agent/pkcs11/private-key.cxx
new file mode 100644
index 0000000..e85d815
--- /dev/null
+++ b/openssl/agent/pkcs11/private-key.cxx
@@ -0,0 +1,492 @@
+// file : openssl/agent/pkcs11/private-key.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <openssl/agent/pkcs11/private-key.hxx>
+
+#include <cstring> // memset(), strlen()
+
+#include <openssl/agent/pkcs11/pkcs11.hxx>
+
+#define API_STRING(S) api_string (S, sizeof (S))
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ using namespace std;
+
+ static void
+ close_session (CK_SESSION_HANDLE* p)
+ {
+ if (p != nullptr)
+ api ()->C_CloseSession (*p);
+ }
+
+ private_key::
+ private_key (): session_ (nullptr, close_session)
+ {
+ }
+
+ private_key::
+ private_key (private_key&& k): private_key ()
+ {
+ *this = move (k);
+ }
+
+ private_key& private_key::
+ operator= (private_key&& k)
+ {
+ description = move (k.description);
+ session_ = move (k.session_);
+ handle_ = k.handle_;
+ simulate_ = move (k.simulate_);
+ return *this;
+ }
+
+ private_key::
+ private_key (const identity& idn,
+ const access& acc,
+ const char* pin,
+ optional<simulate_outcome> sim)
+ : private_key ()
+ {
+ simulate_ = move (sim); // Can't initialize because of delegate ctor.
+
+ // Verify the identity and access attributes.
+ //
+ if (idn.type && *idn.type != "private")
+ throw invalid_argument ("unexpected object type " + *idn.type);
+
+ if (pin == nullptr && acc.pin_value)
+ pin = acc.pin_value->c_str ();
+
+ if (pin == nullptr)
+ throw invalid_argument ("PIN is required");
+
+ auto no_key = [] ()
+ {
+ throw runtime_error ("no matching private key found");
+ };
+
+ auto simulate = [this, &no_key] ()
+ {
+ assert (simulate_ && session_ == nullptr);
+
+ switch (*simulate_)
+ {
+ case simulate_outcome::success:
+ {
+ description = "simulated private key";
+ return;
+ }
+ case simulate_outcome::failure:
+ {
+ no_key ();
+ }
+ }
+ };
+
+ // Get the Cryptoki functions pointer.
+ //
+ CK_FUNCTION_LIST* fs;
+ {
+ path p;
+
+ if (acc.module_path)
+ {
+ if (acc.module_name)
+ p = *acc.module_path / (*acc.module_name + ".so");
+ else if (file_exists (*acc.module_path))
+ p = *acc.module_path;
+ else
+ p = *acc.module_path / "opensc-pkcs11.so";
+ }
+ else if (acc.module_name)
+ p = *acc.module_name + ".so";
+ else
+ p = path ("opensc-pkcs11.so");
+
+ // Ignore non-existent PKCS#11 module in the simulated mode. Note
+ // that if the module exists we will simulate as far as possible,
+ // up to opening token sessions (but not logging into them).
+ //
+ fs = api (p, simulate_.has_value ());
+
+ if (fs == nullptr)
+ {
+ assert (simulate_);
+ simulate ();
+ return;
+ }
+ }
+
+ // Search for the private key.
+ //
+ // The overall plan is to match the PKCS#11 module, go though all the
+ // matching slots it provides, log into all the matching tokens these
+ // slots may contain and see if the tokens contain a matching RSA
+ // private keys. Fail if unable to log into the matching tokens or
+ // none or multiple private keys match. Otherwise keep both the
+ // matching token session and the key handle.
+ //
+ auto mult_keys = [] ()
+ {
+ throw runtime_error ("multiple private keys match");
+ };
+
+ auto match = [] (const auto& attr, const auto& value)
+ {
+ return !attr || *attr == value;
+ };
+
+ // Match the module.
+ //
+ CK_INFO pi;
+ CK_RV r (fs->C_GetInfo (&pi));
+
+ if (r != CKR_OK)
+ throw_api_error (r, "unable to obtain PKCS#11 module info");
+
+ if (!match (idn.library_manufacturer,
+ API_STRING (pi.manufacturerID)) ||
+
+ !match (idn.library_version,
+ library_version (pi.libraryVersion.major,
+ pi.libraryVersion.minor)) ||
+
+ !match (idn.library_description,
+ API_STRING (pi.libraryDescription)))
+ no_key ();
+
+ // Traverse through slots.
+ //
+ // In the PKCS#11 terminology a slot is something that may have token
+ // be inserted into it. Not to be confused with Yubikey's 9a, 9c, etc
+ // slots.
+ //
+ // Note that a set of slots is checked at the time when
+ // C_GetSlotList() is called to obtain slots count (pSlotList argument
+ // is NULL and the tokenPresent argument is false).
+ //
+ CK_ULONG nslots;
+ r = fs->C_GetSlotList (false /* tokenPresent */,
+ nullptr /* pSlotList */,
+ &nslots);
+
+ if (r != CKR_OK)
+ throw_api_error (r, "unable to obtain slots count");
+
+ vector<CK_SLOT_ID> slot_ids (nslots);
+ r = fs->C_GetSlotList (false /* tokenPresent */,
+ slot_ids.data (),
+ &nslots);
+
+ if (r != CKR_OK)
+ throw_api_error (r, "unable to obtain slot ids");
+
+ for (CK_SLOT_ID sid: slot_ids)
+ {
+ // Match the slot information.
+ //
+ if (!match (idn.slot_id, sid))
+ continue;
+
+ CK_SLOT_INFO si;
+ r = fs->C_GetSlotInfo (sid, &si);
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r, "unable to obtain slot " + to_string (sid) + " info");
+
+ if ((si.flags & CKF_TOKEN_PRESENT) == 0 ||
+ !match (idn.slot_manufacturer, API_STRING (si.manufacturerID)) ||
+ !match (idn.slot_description, API_STRING (si.slotDescription)))
+ continue;
+
+ auto slot_desc = [&sid, &si] ()
+ {
+ string d (API_STRING (si.slotDescription));
+ return "slot " + to_string (sid) + " (" +
+ (!d.empty () ? d : API_STRING (si.manufacturerID)) + ")";
+ };
+
+ // Match the token information.
+ //
+ CK_TOKEN_INFO ti;
+ r = fs->C_GetTokenInfo (sid, &ti);
+
+ if (r == CKR_TOKEN_NOT_PRESENT || r == CKR_TOKEN_NOT_RECOGNIZED)
+ continue;
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r, "unable to obtain token info for " + slot_desc ());
+
+ if ((ti.flags & CKF_TOKEN_INITIALIZED) == 0 ||
+ (ti.flags & CKF_USER_PIN_INITIALIZED) == 0 ||
+ (ti.flags & CKF_LOGIN_REQUIRED) == 0 ||
+ (ti.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0 || // Pinpad?
+
+ !match (idn.serial, API_STRING (ti.serialNumber)) ||
+ !match (idn.token, API_STRING (ti.label)) ||
+ !match (idn.model, API_STRING (ti.model)) ||
+ !match (idn.manufacturer, API_STRING (ti.manufacturerID)))
+ continue;
+
+ auto token_desc = [&ti] ()
+ {
+ string r ("token ");
+ string l (API_STRING (ti.label));
+
+ r += !l.empty ()
+ ? "'" + l + "'"
+ : "'" + API_STRING (ti.model) + "' by " +
+ API_STRING (ti.manufacturerID);
+
+ return r;
+ };
+
+ // Search for the matching RSA private key in the token.
+ //
+ // Open the read-only session with the token. Note that we can't see
+ // private objects until login.
+ //
+ CK_SESSION_HANDLE sh;
+ r = fs->C_OpenSession (sid,
+ CKF_SERIAL_SESSION,
+ nullptr /* pApplication */,
+ nullptr /* Notify */,
+ &sh);
+
+ if (r == CKR_DEVICE_REMOVED ||
+ r == CKR_TOKEN_NOT_PRESENT ||
+ r == CKR_TOKEN_NOT_RECOGNIZED)
+ continue;
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r, "unable to open session with " + token_desc ());
+
+ session_ptr session (new CK_SESSION_HANDLE (sh), close_session);
+
+ // Log into the token unless simulating.
+ //
+ if (simulate_)
+ continue;
+
+ // Note that all sessions with a token share login, so need to login
+ // once per all token sessions.
+ //
+ // Also note that there is no need to logout explicitly if you want
+ // to keep all token sessions logged in during their lifetime.
+ //
+ r = fs->C_Login (
+ *session,
+ CKU_USER,
+ reinterpret_cast<unsigned char*> (const_cast<char*> (pin)),
+ strlen (pin));
+
+ // We can fail because of the wrong PIN or trying to apply the PIN
+ // to a wrong token. Should we just skip the token if that's the
+ // case? Probably we should throw. Otherwise who knows how many pins
+ // we will reset going forward.
+ //
+ if (r != CKR_USER_ALREADY_LOGGED_IN && r != CKR_OK)
+ throw_api_error (r, "unable to login to " + token_desc ());
+
+ // Search for the private key.
+ //
+ // Fill the search attributes.
+ //
+ CK_OBJECT_CLASS oc (CKO_PRIVATE_KEY);
+ CK_KEY_TYPE kt (CKK_RSA);
+
+ vector<CK_ATTRIBUTE> sa ({{CKA_CLASS, &oc, sizeof (oc)},
+ {CKA_KEY_TYPE, &kt, sizeof (kt)}});
+ if (idn.id)
+ sa.push_back (
+ CK_ATTRIBUTE {CKA_ID,
+ const_cast<unsigned char*> (idn.id->data ()),
+ idn.id->size ()});
+
+ if (idn.object)
+ sa.push_back (CK_ATTRIBUTE {CKA_LABEL,
+ const_cast<char*> (idn.object->c_str ()),
+ idn.object->size ()});
+
+ // Initialize the search.
+ //
+ r = fs->C_FindObjectsInit (*session, sa.data (), sa.size ());
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r, "unable to enumerate private keys in " + token_desc ());
+
+ // Finally, search for the key.
+ //
+ // Note that we will query 2 keys to handle the 'multiple keys
+ // match' case.
+ //
+ CK_OBJECT_HANDLE key (0);
+ {
+ session_ptr search_deleter (
+ session.get (),
+ [] (CK_SESSION_HANDLE* p) {api ()->C_FindObjectsFinal (*p);});
+
+ CK_ULONG n;
+ CK_OBJECT_HANDLE keys[2];
+ r = fs->C_FindObjects (*session,
+ keys,
+ 2 /* ulMaxObjectCount */,
+ &n);
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r,
+ "unable to obtain private key handles from " + token_desc ());
+
+ if (n == 1)
+ key = keys[0]; // Exactly one key matches.
+ else if (n == 0)
+ continue; // No key matches.
+ else
+ mult_keys (); // Multiple keys match.
+ }
+
+ if (session_ != nullptr)
+ mult_keys ();
+
+ // Produce description for the found key.
+ //
+ description = "private key ";
+ {
+ CK_ATTRIBUTE attr {CKA_LABEL, nullptr, 0};
+ r = fs->C_GetAttributeValue (*session,
+ key,
+ &attr,
+ 1 /* ulCount */);
+
+ if (r == CKR_OK && attr.ulValueLen != 0)
+ {
+ vector<char> label (attr.ulValueLen);
+ attr.pValue = label.data ();
+
+ r = fs->C_GetAttributeValue (*session,
+ key,
+ &attr,
+ 1 /* ulCount */);
+ if (r == CKR_OK)
+ description += "'" + string (label.data (), label.size ()) +
+ "' ";
+ }
+ }
+
+ description += "in " + token_desc ();
+
+ // Note that for Yubikey 4 we cannot rely on the key's
+ // CKA_ALWAYS_AUTHENTICATE attribute value for detecting if
+ // authentication is required for the sign operation. For the
+ // private key imported into the 9c (SIGN key) slot with the
+ // --pin-policy=never option the sign operation doesn't require
+ // authentication but the CKA_ALWAYS_AUTHENTICATE value is still on.
+ // This seems to be some yubico-piv-tool issue (or deliberate
+ // behavior) as for the 9a (PIV AUTH key) slot the sign
+ // authentication is not required and the CKA_ALWAYS_AUTHENTICATE
+ // value is off. This issue makes it impossible to evaluate if the
+ // key requires sign authentication before the sign attempt. This is
+ // probably not a big deal as, if we want, we can always check this
+ // using some dummy data.
+ //
+#if 0
+ CK_BBOOL always_auth (CK_FALSE);
+
+ CK_ATTRIBUTE attr {
+ CKA_ALWAYS_AUTHENTICATE, &always_auth, sizeof (always_auth)};
+
+ r = fs->C_GetAttributeValue (*session,
+ key,
+ &attr,
+ 1 /* ulCount */);
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r,
+ "unable to obtain 'always auth' attribute for " + description);
+#endif
+
+ // Despite the fact that the key is found we will continue to iterate
+ // over slots to make sure that a single key matches the identity
+ // attributes.
+ //
+ session_ = move (session);
+ handle_ = key;
+ }
+
+ if (simulate_)
+ simulate ();
+ else if (session_ == nullptr)
+ no_key ();
+ }
+
+ vector<char> private_key::
+ sign (const vector<char>& data, const optional<simulate_outcome>& sim)
+ {
+ assert (!empty ());
+
+ if (sim && *sim == simulate_outcome::failure)
+ throw runtime_error ("unable to sign using " + description);
+
+ if (sim || simulate_)
+ {
+ // Otherwise would fail in the private_key constructor.
+ //
+ assert (!simulate_ || *simulate_ == simulate_outcome::success);
+
+ return vector<char> ({
+ 's', 'i', 'g', 'n', 'a', 't', 'u', 'r', 'e', '\n'});
+ }
+
+ CK_FUNCTION_LIST* fs (api ());
+
+ CK_MECHANISM mech;
+ memset (&mech, 0, sizeof (mech));
+ mech.mechanism = CKM_RSA_PKCS;
+
+ CK_RV r (fs->C_SignInit (*session_, &mech, handle_));
+
+ if (r != CKR_OK)
+ throw_api_error (
+ r, "unable to init sign operation using " + description);
+
+ for (vector<char> signature; true; signature_size_ *= 2)
+ {
+ signature.resize (signature_size_);
+
+ CK_ULONG n (signature_size_);
+
+ r = fs->C_Sign (*session_,
+ reinterpret_cast<unsigned char*> (
+ const_cast<char*> (data.data ())),
+ data.size (),
+ reinterpret_cast<unsigned char*> (
+ signature.data ()),
+ &n);
+
+ if (r == CKR_BUFFER_TOO_SMALL)
+ continue;
+
+ if (r != CKR_OK)
+ throw_api_error (r, "unable to sign using " + description);
+
+ assert (n != 0 && n <= signature_size_);
+
+ signature.resize (n);
+ return signature;
+ }
+ }
+ }
+ }
+}
diff --git a/openssl/agent/pkcs11/private-key.hxx b/openssl/agent/pkcs11/private-key.hxx
new file mode 100644
index 0000000..967f057
--- /dev/null
+++ b/openssl/agent/pkcs11/private-key.hxx
@@ -0,0 +1,95 @@
+// file : openssl/agent/pkcs11/private-key.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef OPENSSL_AGENT_PKCS11_PRIVATE_KEY_HXX
+#define OPENSSL_AGENT_PKCS11_PRIVATE_KEY_HXX
+
+#include <openssl/types.hxx>
+#include <openssl/utility.hxx>
+
+#include <openssl/agent/pkcs11/url.hxx>
+#include <openssl/agent/pkcs11/pkcs11.hxx>
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ // Unlocked private key.
+ //
+ // Keeps the authenticated session with the token containing the key.
+ //
+ // Note that the key should be configured not to require authentication
+ // of the sign operation. For Yubikey 4 this is achieved by passing the
+ // --pin-policy=never option to the yubico-piv-tool import-key command.
+ //
+ class private_key
+ {
+ public:
+ string description;
+
+ // Open PKCS#11 authenticated session with the token containing the
+ // private key that matches the identity attributes using the
+ // specified access attributes. Throw invalid_argument if there is
+ // something wrong with the identity or access attributes. Throw
+ // runtime_error if the matching private key cannot be found, accessed
+ // or multiple keys match the criteria.
+ //
+ // The token PIN is expected to be specified either as the pin
+ // argument (preferred) or as the pin_value access attribute. The
+ // pin_source access attribute is ignored. The pin argument is
+ // normally allocated on the stack and is overwritten with zeros
+ // after the usage. Using the pin_value attribute is insecure (may
+ // stay in memory) and is discouraged unless for debugging and
+ // testing.
+ //
+ private_key (const identity&,
+ const access&,
+ const char* pin,
+ optional<simulate_outcome> = nullopt);
+
+ // Create a special empty key that may not be used for any
+ // cryptographic operations.
+ //
+ private_key ();
+
+ // Movable-only type.
+ //
+ private_key (private_key&&);
+ private_key& operator= (private_key&&);
+ private_key (const private_key&) = delete;
+ private_key& operator= (const private_key&) = delete;
+
+ // Sign the data. Throw runtime_error if something goes wrong.
+ //
+ vector<char>
+ sign (const vector<char>&,
+ const optional<simulate_outcome>& = nullopt);
+
+ bool
+ empty () const {return session_ == nullptr && !simulate_;}
+
+ private:
+ using session_ptr = unique_ptr<CK_SESSION_HANDLE,
+ void (*)(CK_SESSION_HANDLE*)>;
+ session_ptr session_;
+
+ CK_OBJECT_HANDLE handle_; // Meaningless if session_ is NULL.
+
+ optional<simulate_outcome> simulate_;
+
+ // Normally the signature buffer size is the private key length.
+ // However, calculating this length is not trivial and would require
+ // using libcrypto library. To avoid this we will start with the 256
+ // bytes, doubling it while the sign operation complains about it, and
+ // cacheing the resulting size for future sign() calls.
+ //
+ CK_ULONG signature_size_ = 256;
+ };
+ }
+ }
+}
+
+#endif // OPENSSL_AGENT_PKCS11_PRIVATE_KEY_HXX
diff --git a/openssl/agent/pkcs11/private-key.test.cxx b/openssl/agent/pkcs11/private-key.test.cxx
new file mode 100644
index 0000000..52e6186
--- /dev/null
+++ b/openssl/agent/pkcs11/private-key.test.cxx
@@ -0,0 +1,72 @@
+// file : openssl/agent/pkcs11/private-key.test.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <iostream>
+
+#include <openssl/agent/pkcs11/url.hxx>
+#include <openssl/agent/pkcs11/private-key.hxx>
+
+// Usage: argv[0] <pkcs11-url>
+//
+// Create private_key object referenced by the <pkcs11-url>. Read data from
+// stdin, sign it with the private key, and print the signature to stdout.
+//
+int
+main (int argc, char* argv[])
+{
+ using namespace std;
+ using namespace openssl::agent::pkcs11;
+
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " <pkcs11-url>" << endl;
+ return 1;
+ }
+
+ cin.exceptions (ios::badbit);
+ cout.exceptions (ios::failbit | ios::badbit);
+
+ try
+ {
+ url u (argv[1]);
+ identity idn (u);
+ access acc (u);
+
+ vector<char> data ((istreambuf_iterator<char> (cin)),
+ istreambuf_iterator<char> ());
+
+ vector<char> signature;
+
+ // Stress the API a bit recreating, reusing and having concurrent keys.
+ //
+ for (size_t i (0); i < 5; ++i)
+ {
+ private_key key1 (idn, acc, nullptr /* secure_pin */);
+ private_key key2 (idn, acc, nullptr /* secure_pin */);
+
+ for (size_t i (0); i < 10; ++i)
+ {
+ vector<char> sign ((i % 2 == 0 ? key1 : key2).sign (data));
+
+ if (signature.empty ())
+ signature = move (sign);
+ else if (sign != signature)
+ throw runtime_error ("sign operation is unreliable");
+ }
+ }
+
+ cout.write (signature.data (), signature.size ());
+ return 0;
+ }
+ catch (const invalid_argument& e)
+ {
+ cerr << e << endl;
+ return 1;
+ }
+ catch (const runtime_error& e)
+ {
+ cerr << e << endl;
+ return 1;
+ }
+}
diff --git a/openssl/agent/pkcs11/private-key.test.testscript b/openssl/agent/pkcs11/private-key.test.testscript
new file mode 100644
index 0000000..0adaed1
--- /dev/null
+++ b/openssl/agent/pkcs11/private-key.test.testscript
@@ -0,0 +1,22 @@
+# file : openssl/agent/pkcs11/private-key.test.testscript -*- C++ -*-
+# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+url = 'pkcs11:token=name:cppget.org;object=SIGN%20key?pin-value=123123'
+
+: sign
+:
+: Enable this test with care as this is not a simulation and the above URL
+: must match the token PIN. In the worst case the test may reset the token
+# PIN.
+:
+if (false)
+{
+ $* "$url" <'test' | base64 >>EOO
+ jbTa3H3F2KHGbzDW/FaI5oeqPQknxyKhgbl6eDZlEzwaXKhRXueQNC1TMwc5HgWtuUWoJYkdTmpI
+ 20X4rBfECYIYSwZPBWCypgWn8/mnZEEtL+sfoDXrm/MRBQhdg3FJorL9lGy8+OFH83RNPwic+2yZ
+ ItoReDFjlzkOWmsym3BPhDDrOOQ7DEAdaQDmJXJJsNvpIWmr2957CDoieyCx8yUc8zVR1viOsY47
+ rdZrXuJ5BH+cda4tmLthoI0PhHxNn6f56qfYxboXSE6hvGo6DLjipCLNVfROsIHJO1RSEkFt2lQ+
+ jVi7ZST0ZTsZI4lb/t8b6LoHumTQeteMBnMyCQ==
+ EOO
+}
diff --git a/openssl/agent/pkcs11/url.cxx b/openssl/agent/pkcs11/url.cxx
new file mode 100644
index 0000000..0b9c3ac
--- /dev/null
+++ b/openssl/agent/pkcs11/url.cxx
@@ -0,0 +1,303 @@
+// file : openssl/agent/pkcs11/url.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <openssl/agent/pkcs11/url.hxx>
+
+#include <cerrno>
+#include <cstdlib> // strtoull()
+#include <iterator> // back_inserter()
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ using namespace std;
+
+ // Convenience functions.
+ //
+ static uint64_t
+ parse_uint64 (const string& s,
+ uint64_t min,
+ uint64_t max,
+ const char* what)
+ {
+ if (s[0] != '-' && s[0] != '+') // strtoull() allows these.
+ {
+ const char* b (s.c_str ());
+ char* e (nullptr);
+ uint64_t v (strtoull (b, &e, 10)); // Can't throw.
+
+ if (errno != ERANGE && e == b + s.size () && v >= min && v <= max)
+ return v;
+ }
+
+ throw invalid_argument (string ("invalid ") + what + " '" + s + "'");
+ }
+
+ // url_traits
+ //
+ optional<url_traits::scheme_type> url_traits::
+ translate_scheme (const string_type& /* url */,
+ string_type&& scheme,
+ optional<authority_type>& authority,
+ optional<path_type>& path,
+ optional<string_type>& /* query */,
+ optional<string_type>& fragment,
+ bool& rootless)
+ {
+ // If something is wrong with the URL leave the basic_url constructor
+ // to throw.
+ //
+ if (scheme.empty ())
+ return nullopt;
+
+ if (casecmp (scheme, "pkcs11") != 0)
+ throw invalid_argument ("invalid scheme");
+
+ if (authority)
+ throw invalid_argument ("unexpected authority");
+
+ if (path && (!rootless || path->find ('/') != string::npos))
+ throw invalid_argument ("one-level path expected");
+
+ if (fragment)
+ throw invalid_argument ("unexpected fragment");
+
+ return move (scheme);
+ }
+
+ url_traits::string_type url_traits::
+ translate_scheme (string_type& /* url */,
+ const scheme_type& scheme,
+ const optional<authority_type>& /* authority */,
+ const optional<path_type>& /* path */,
+ const optional<string_type>& /* query */,
+ const optional<string_type>& /* fragment */,
+ bool /* rootless */)
+ {
+ return scheme;
+ }
+
+ url_traits::path_type url_traits::
+ translate_path (string_type&& path)
+ {
+ return move (path);
+ }
+
+ url_traits::string_type url_traits::
+ translate_path (const path_type& path)
+ {
+ return path;
+ }
+
+ // library_version
+ //
+ library_version::
+ library_version (const string& s)
+ {
+ auto num = [] (const string& s, const char* what)
+ {
+ return static_cast<unsigned char> (parse_uint64 (s, 0, 255, what));
+ };
+
+ size_t p (s.find ('.'));
+
+ if (p != string::npos)
+ {
+ major = num (string (s, 0, p), "library major version");
+ minor = num (string (s, p + 1), "library minor version");
+ }
+ else
+ {
+ major = num (s, "library major version");
+ minor = 0;
+ }
+ }
+
+ // Parse the attribute name=value representation. The value can contain
+ // binary data.
+ //
+ // It would probably be cleaner to return pair<string, vector<char>>,
+ // but this would uglify a client code quite a bit and make it less
+ // efficient.
+ //
+ static pair<string, string>
+ attribute (const string& s, size_t b, size_t n)
+ {
+ size_t i (b);
+ size_t e (b + n);
+
+ for (; i != e && s[i] != '='; ++i) ;
+
+ if (i == e)
+ throw invalid_argument (
+ "no value for attribute '" + string (s, b, n) + "'");
+
+ string a;
+ url::decode (s.begin () + b, s.begin () + i, back_inserter (a));
+
+ string v;
+ url::decode (s.begin () + i + 1, s.begin () + e, back_inserter (v));
+
+ return make_pair (move (a), move (v));
+ }
+
+ // identity
+ //
+ identity::
+ identity (const url& u)
+ {
+ const optional<string>& path (u.path);
+
+ // If URL path component is absent then create the identity that
+ // matches all PKCS#11 entities in the system.
+ //
+ if (!path)
+ return;
+
+ for (size_t b (0), e (0), n; (n = next_word (*path, b, e, ';')); )
+ {
+ pair<string, string> a (attribute (*path, b, n));
+
+ const string& an (a.first);
+ string& av (a.second);
+
+ auto set = [&an] (auto& attr, auto&& val)
+ {
+ if (attr)
+ throw invalid_argument ("duplicate attribute '" + an + "'");
+
+ attr = move (val);
+ };
+
+ // Module.
+ //
+ if (an == "library-manufacturer")
+ set (library_manufacturer, move (av));
+ else if (an == "library-version")
+ set (library_version, library_version_type (av));
+ else if (an == "library-description")
+ set (library_description, move (av));
+
+ // Slot.
+ //
+ else if (an == "slot-id")
+ set (slot_id,
+ static_cast<unsigned long> (
+ parse_uint64 (av, 0, ~0UL, "slot-id attribute value")));
+ else if (an == "slot-manufacturer")
+ set (slot_manufacturer, move (av));
+ else if (an == "slot-description")
+ set (slot_description, move (av));
+
+ // Token.
+ //
+ else if (an == "serial")
+ set (serial, move (av));
+ else if (an == "token")
+ set (token, move (av));
+ else if (an == "model")
+ set (model, move (av));
+ else if (an == "manufacturer")
+ set (manufacturer, move (av));
+
+ // Storage object.
+ //
+ else if (an == "id")
+ set (id, vector<unsigned char> (av.begin (), av.end ()));
+ else if (an == "object")
+ set (object, move (av));
+ else if (an == "type")
+ set (type, move (av));
+ else
+ throw invalid_argument ("unknown attribute '" + an + "'");
+ }
+ }
+
+ // access
+ //
+ access::
+ access (const url& u)
+ {
+ const optional<string>& query (u.query);
+
+ // If URL query component is absent then create an object that
+ // provides no access attributes.
+ //
+ if (!query)
+ return;
+
+ for (size_t b (0), e (0), n; (n = next_word (*query, b, e, ';')); )
+ {
+ pair<string, string> a (attribute (*query, b, n));
+
+ const string& an (a.first);
+ string& av (a.second);
+
+ auto set = [&an] (auto& attr, auto&& val)
+ {
+ if (attr)
+ throw invalid_argument ("duplicate attribute '" + an + "'");
+
+ attr = move (val);
+ };
+
+ // Note that unrecognized attributes are ignored (see the traits
+ // class notes for details).
+ //
+ if (an == "pin-source")
+ set (pin_source, move (av));
+ else if (an == "pin-value")
+ set (pin_value, move (av));
+ else if (an == "module-name")
+ {
+ try
+ {
+ path p (av);
+
+ if (!p.empty () && p.simple ())
+ {
+ set (module_name, move (p));
+ continue;
+ }
+
+ // Fall through.
+ }
+ catch (const invalid_path& e)
+ {
+ // Fall through.
+ }
+
+ throw invalid_argument (
+ "invalid value '" + av + "' for module-name attribute");
+ }
+ else if (an == "module-path")
+ {
+ try
+ {
+ path p (move (av));
+
+ if (p.relative ())
+ throw invalid_argument ("relative path '" + p.string () +
+ "' for module-path attribute");
+
+ set (module_path, move (p));
+ }
+ catch (const invalid_path& e)
+ {
+ throw invalid_argument (
+ "invalid path '" + e.path + "' for module-path attribute");
+ }
+ }
+ }
+
+ if (pin_source && pin_value)
+ throw invalid_argument (
+ "both pin-source and pin-value attributes specified");
+ }
+ }
+ }
+}
diff --git a/openssl/agent/pkcs11/url.hxx b/openssl/agent/pkcs11/url.hxx
new file mode 100644
index 0000000..b8ca056
--- /dev/null
+++ b/openssl/agent/pkcs11/url.hxx
@@ -0,0 +1,246 @@
+// file : openssl/agent/pkcs11/url.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef OPENSSL_AGENT_PKCS11_URL_HXX
+#define OPENSSL_AGENT_PKCS11_URL_HXX
+
+#include <libbutl/url.mxx>
+
+#include <openssl/types.hxx>
+#include <openssl/utility.hxx>
+
+// glibc defines these macros in its <sys/types.h>.
+//
+#ifdef major
+# undef major
+#endif
+
+#ifdef minor
+# undef minor
+#endif
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ // RFC7512 The PKCS #11 URI Scheme.
+ //
+ // Traits class for the PKCS#11 URL object.
+ //
+ // Notes:
+ //
+ // - The 'pkcs11:' URI scheme is rootless and doesn't use the fragment
+ // component.
+ //
+ // - The one-level path component is a sequence of semicolon-separated
+ // attribute name/value pairs that identify the referenced entity. It
+ // is stored in the URL-encoded representation as the id attribute
+ // contains binary data.
+ //
+ // - The query is a sequence of ampersand-separated access attribute
+ // name/value pairs that may or may not be used by the URL consumer.
+ //
+ // - All attribute values are textual, except for the id attribute which
+ // is binary.
+ //
+ // - There shouldn't be duplicate attributes in the path and query
+ // components.
+ //
+ // - Both path and query components can contain vendor-specific
+ // attributes.
+ //
+ // - An unrecognized attribute in the path component results in the
+ // parsing error. An unrecognized attribute in the query component is
+ // skipped.
+ //
+ // - The URL-referenced entity kind is context-specific. For example,
+ // the pkcs11:token=abc URL can refer the abc token or all objects
+ // stored in the abc token.
+ //
+ // - An attribute that is not present in the URL path component matches
+ // everything. Each additional attribute present in the path component
+ // further restricts the selection. Thus, in particular, the 'pkcs11:'
+ // URL is valid and matches everything.
+ //
+ struct url_traits
+ {
+ using string_type = string;
+ using path_type = string;
+
+ using scheme_type = string;
+ using authority_type = butl::basic_url_authority<string_type>;
+
+ static optional<scheme_type>
+ translate_scheme (const string_type&,
+ string_type&&,
+ optional<authority_type>&,
+ optional<path_type>&,
+ optional<string_type>&,
+ optional<string_type>&,
+ bool&);
+
+ static string_type
+ translate_scheme (string_type&,
+ const scheme_type&,
+ const optional<authority_type>&,
+ const optional<path_type>&,
+ const optional<string_type>&,
+ const optional<string_type>&,
+ bool);
+
+ static path_type
+ translate_path (string_type&&);
+
+ static string_type
+ translate_path (const path_type&);
+ };
+
+ using url = butl::basic_url<string, url_traits>;
+
+ // PKCS#11 entity (storage object, token, slot, or module) identity
+ // attributes.
+ //
+ struct library_version
+ {
+ unsigned char major;
+ unsigned char minor;
+
+ // Create the version object from its string representation. Throw
+ // invalid_argument on the parsing error.
+ //
+ explicit
+ library_version (const string&);
+
+ library_version (unsigned char mj, unsigned char mn)
+ : major (mj), minor (mn) {}
+ };
+
+ class identity
+ {
+ public:
+ // Module.
+ //
+ using library_version_type = pkcs11::library_version;
+
+ optional<string> library_manufacturer;
+ optional<library_version_type> library_version;
+ optional<string> library_description;
+
+ // Slot.
+ //
+ // Note that not all PKCS#11 libraries guarantee slot id to be stable
+ // across initializations.
+ //
+ optional<unsigned long> slot_id;
+ optional<string> slot_manufacturer;
+ optional<string> slot_description;
+
+ // Token.
+ //
+ optional<string> serial;
+ optional<string> token; // Token label.
+ optional<string> model;
+ optional<string> manufacturer;
+
+ // Storage object.
+ //
+ optional<vector<unsigned char>> id;
+
+ optional<string> object; // Object label.
+ optional<string> type; // cert, data, private, public, or
+ // secret-key.
+
+ // Parse the path component of pkcs11_url object. Throw
+ // invalid_argument if invalid attribute is encountered.
+ //
+ explicit
+ identity (const url&);
+
+ // Create an identity that matches all PKCS#11 entities in the system.
+ //
+ identity () = default;
+ };
+
+ // PKCS#11 entity access attributes.
+ //
+ class access
+ {
+ public:
+ optional<string> pin_value;
+ optional<string> pin_source;
+
+ // The library name with an extension and "lib" prefix stripped.
+ //
+ optional<path> module_name;
+
+ // The library absolute path or the directory path where the PKCS#11
+ // libraries are located.
+ //
+ optional<path> module_path;
+
+ // Parse the query component of pkcs11_url object. Throw
+ // invalid_argument if invalid attribute is encountered.
+ //
+ explicit
+ access (const url&);
+
+ // Create an object that provides no access attributes.
+ //
+ access () = default;
+ };
+
+ inline bool
+ operator== (const library_version& x, const library_version& y)
+ {
+ return x.major == y.major && x.minor == y.minor;
+ }
+
+ inline bool
+ operator!= (const library_version& x, const library_version& y)
+ {
+ return !(x == y);
+ }
+
+ inline bool
+ operator== (const identity& x, const identity& y)
+ {
+ return
+ // Module.
+ //
+ x.library_manufacturer == y.library_manufacturer &&
+ x.library_version == y.library_version &&
+ x.library_description == y.library_description &&
+
+ // Slot.
+ //
+ x.slot_id == y.slot_id &&
+ x.slot_manufacturer == y.slot_manufacturer &&
+ x.slot_description == y.slot_description &&
+
+ // Token.
+ //
+ x.serial == y.serial &&
+ x.token == y.token &&
+ x.model == y.model &&
+ x.manufacturer == y.manufacturer &&
+
+ // Storage object.
+ //
+ x.id == y.id &&
+ x.object == y.object &&
+ x.type == y.type;
+ }
+
+ inline bool
+ operator!= (const identity& x, const identity& y)
+ {
+ return !(x == y);
+ }
+ }
+ }
+}
+
+#endif // OPENSSL_AGENT_PKCS11_URL_HXX
diff --git a/openssl/agent/pkcs11/url.test.cxx b/openssl/agent/pkcs11/url.test.cxx
new file mode 100644
index 0000000..501137a
--- /dev/null
+++ b/openssl/agent/pkcs11/url.test.cxx
@@ -0,0 +1,46 @@
+// file : openssl/agent/pkcs11/url.test.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <iostream>
+
+#include <openssl/agent/pkcs11/url.hxx>
+
+// Usage: argv[0]
+//
+// Create pkcs11::url objects from stdin lines, and for each of them print its
+// string representation to stdout, one per line.
+//
+int
+main ()
+{
+ using namespace std;
+ using namespace openssl;
+ using namespace openssl::agent::pkcs11;
+
+ cin.exceptions (ios::badbit);
+ cout.exceptions (ios::failbit | ios::badbit);
+
+ try
+ {
+ string s;
+ while (!eof (getline (cin, s)))
+ {
+ url u (s);
+
+ // Validate the URL attributes.
+ //
+ identity idn (u);
+ access acc (u);
+
+ cout << u.string () << endl;
+ }
+
+ return 0;
+ }
+ catch (const exception& e)
+ {
+ cerr << e << endl;
+ return 1;
+ }
+}
diff --git a/openssl/agent/pkcs11/url.test.testscript b/openssl/agent/pkcs11/url.test.testscript
new file mode 100644
index 0000000..807fad9
--- /dev/null
+++ b/openssl/agent/pkcs11/url.test.testscript
@@ -0,0 +1,34 @@
+# file : openssl/agent/pkcs11/url.test.testscript -*- C++ -*-
+# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+: valid
+:
+$* <<EOF >>EOF
+pkcs11:token=unused;object=SIGN%20key
+pkcs11:token=unused;object=SIGN%20key?pin-value=123123
+pkcs11:
+pkcs11:?pin=123123
+pkcs11:library-version=1.2
+pkcs11:?module-path=/usr/lib
+pkcs11:id=%01%00%38%02;token=unused
+pkcs11:?a=b
+EOF
+
+: invalid
+:
+{
+ $* <'file:/abc' 2>'invalid scheme' != 0 : invalid-scheme
+ $* <'pkcs11:/abc' 2>'one-level path expected' != 0 : root
+ $* <'pkcs11:a/bc' 2>'one-level path expected' != 0 : multi-level
+ $* <'pkcs11://a/abc' 2>'unexpected authority' != 0 : authority
+ $* <'pkcs11:abc#x' 2>'unexpected fragment' != 0 : fragment
+
+ $* <'pkcs11:slot-id=a' 2>"invalid slot-id attribute value 'a'"!= 0 : slot-id
+
+ $* <'pkcs11:a=b' 2>"unknown attribute 'a'" != 0 : unknown-ident
+
+ : lib-min-ver
+ :
+ $* <'pkcs11:library-version=1.a' 2>"invalid library minor version 'a'" != 0
+}