summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2012-08-23 15:34:04 +0200
committerStef Walter <stef@thewalter.net>2014-06-23 11:33:48 +0200
commit774d6c65160d4438cddda59ecd63024866cfea39 (patch)
treeeb65c277f34974be6a838946e592c7b153aa9acc
parentd21967cdcd18c8fcb749f874c492b7f6c4965817 (diff)
downloadp11-kit-774d6c65160d4438cddda59ecd63024866cfea39.tar.gz
rpc: Implement PKCS#11 messages/client/server code
* This enables passing around bytes which represent PKCS#11 RPC calls. * Caller is responsible for connecting/disconnecting and so on. * Client side caller gets a mixin from p11_rpc_client_init() to call into, which generates callbacks with byte arrays to be transported. * Server side calls p11_rpc_server_handle() with a CK_FUNCTION_LIST_PTR on which relevant methods get called. * Doesn't yet implement the actual daemon or clients etc... https://bugs.freedesktop.org/show_bug.cgi?id=54105
-rw-r--r--common/debug.c1
-rw-r--r--common/debug.h1
-rw-r--r--common/mock.c7
-rw-r--r--common/mock.h3
-rw-r--r--doc/manual/Makefile.am2
-rw-r--r--p11-kit/Makefile.am2
-rw-r--r--p11-kit/rpc-client.c2092
-rw-r--r--p11-kit/rpc-message.c769
-rw-r--r--p11-kit/rpc-message.h368
-rw-r--r--p11-kit/rpc-server.c1901
-rw-r--r--p11-kit/rpc.h69
-rw-r--r--p11-kit/tests/Makefile.am1
-rw-r--r--p11-kit/tests/test-mock.c10
-rw-r--r--p11-kit/tests/test-rpc.c939
14 files changed, 6163 insertions, 2 deletions
diff --git a/common/debug.c b/common/debug.c
index b3327be..1fbdc7f 100644
--- a/common/debug.c
+++ b/common/debug.c
@@ -57,6 +57,7 @@ static struct DebugKey debug_keys[] = {
{ "proxy", P11_DEBUG_PROXY },
{ "trust", P11_DEBUG_TRUST },
{ "tool", P11_DEBUG_TOOL },
+ { "rpc", P11_DEBUG_RPC },
{ 0, }
};
diff --git a/common/debug.h b/common/debug.h
index 0dcfeae..6106f19 100644
--- a/common/debug.h
+++ b/common/debug.h
@@ -45,6 +45,7 @@ enum {
P11_DEBUG_PROXY = 1 << 4,
P11_DEBUG_TRUST = 1 << 5,
P11_DEBUG_TOOL = 1 << 6,
+ P11_DEBUG_RPC = 1 << 7,
};
extern int p11_debug_current_flags;
diff --git a/common/mock.c b/common/mock.c
index 51b32b6..01e095d 100644
--- a/common/mock.c
+++ b/common/mock.c
@@ -458,6 +458,13 @@ mock_C_Initialize__fails (CK_VOID_PTR init_args)
}
CK_RV
+mock_X_Initialize__fails (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR init_args)
+{
+ return mock_C_Initialize__fails (init_args);
+}
+
+CK_RV
mock_C_Finalize (CK_VOID_PTR reserved)
{
return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
diff --git a/common/mock.h b/common/mock.h
index 9128a63..6253386 100644
--- a/common/mock.h
+++ b/common/mock.h
@@ -133,6 +133,9 @@ CK_RV mock_C_Initialize__fails (CK_VOID_PTR init_args)
CK_RV mock_X_Initialize (CK_X_FUNCTION_LIST *self,
CK_VOID_PTR init_args);
+CK_RV mock_X_Initialize__fails (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR init_args);
+
CK_RV mock_C_Finalize (CK_VOID_PTR reserved);
CK_RV mock_X_Finalize (CK_X_FUNCTION_LIST *self,
diff --git a/doc/manual/Makefile.am b/doc/manual/Makefile.am
index c9ff264..dc15075 100644
--- a/doc/manual/Makefile.am
+++ b/doc/manual/Makefile.am
@@ -59,6 +59,8 @@ IGNORE_HFILES= \
pkcs11x.h \
private.h \
proxy.h \
+ rpc.h \
+ rpc-message.h \
util.h \
virtual.h \
array.h \
diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am
index 92cddfb..da195ac 100644
--- a/p11-kit/Makefile.am
+++ b/p11-kit/Makefile.am
@@ -36,6 +36,8 @@ MODULE_SRCS = \
proxy.c proxy.h \
private.h \
messages.c \
+ rpc-message.c rpc-message.h \
+ rpc-client.c rpc-server.c rpc.h \
uri.c \
virtual.c virtual.h \
$(inc_HEADERS)
diff --git a/p11-kit/rpc-client.c b/p11-kit/rpc-client.c
new file mode 100644
index 0000000..810ef12
--- /dev/null
+++ b/p11-kit/rpc-client.c
@@ -0,0 +1,2092 @@
+/*
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#include "config.h"
+
+#define P11_DEBUG_FLAG P11_DEBUG_RPC
+#include "debug.h"
+#include "pkcs11.h"
+#include "pkcs11x.h"
+#include "library.h"
+#include "message.h"
+#include "private.h"
+#include "rpc.h"
+#include "rpc-message.h"
+#include "virtual.h"
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+
+/* The error used by us when parsing of rpc message fails */
+#define PARSE_ERROR CKR_DEVICE_ERROR
+
+typedef struct {
+ p11_mutex_t mutex;
+ p11_rpc_client_vtable *vtable;
+ pid_t initialized_pid;
+ bool initialize_done;
+} rpc_client;
+
+/* Allocator for call session buffers */
+static void *
+log_allocator (void *pointer,
+ size_t size)
+{
+ void *result = realloc (pointer, (size_t)size);
+ return_val_if_fail (!size || result != NULL, NULL);
+ return result;
+}
+
+static CK_RV
+call_prepare (rpc_client *module,
+ p11_rpc_message *msg,
+ int call_id)
+{
+ p11_buffer *buffer;
+
+ assert (module != NULL);
+ assert (msg != NULL);
+
+ if (module->initialized_pid == 0)
+ return CKR_CRYPTOKI_NOT_INITIALIZED;
+ if (!module->initialize_done)
+ return CKR_DEVICE_REMOVED;
+
+ buffer = p11_rpc_buffer_new_full (64, log_allocator, free);
+ return_val_if_fail (buffer != NULL, CKR_GENERAL_ERROR);
+
+ /* We use the same buffer for reading and writing */
+ p11_rpc_message_init (msg, buffer, buffer);
+
+ /* Put in the Call ID and signature */
+ if (!p11_rpc_message_prep (msg, call_id, P11_RPC_REQUEST))
+ return_val_if_reached (CKR_HOST_MEMORY);
+
+ p11_debug ("prepared call: %d", call_id);
+ return CKR_OK;
+}
+
+static CK_RV
+call_run (rpc_client *module,
+ p11_rpc_message *msg)
+{
+ CK_RV ret = CKR_OK;
+ CK_ULONG ckerr;
+
+ int call_id;
+
+ assert (module != NULL);
+ assert (msg != NULL);
+
+ /* Did building the call fail? */
+ if (p11_buffer_failed (msg->output))
+ return_val_if_reached (CKR_HOST_MEMORY);
+
+ /* Make sure that the signature is valid */
+ assert (p11_rpc_message_is_verified (msg));
+ call_id = msg->call_id;
+
+ /* Do the transport send and receive */
+ assert (module->vtable->transport != NULL);
+ ret = (module->vtable->transport) (module->vtable,
+ msg->output,
+ msg->input);
+
+ if (ret != CKR_OK)
+ return ret;
+
+ if (!p11_rpc_message_parse (msg, P11_RPC_RESPONSE))
+ return CKR_DEVICE_ERROR;
+
+ /* If it's an error code then return it */
+ if (msg->call_id == P11_RPC_CALL_ERROR) {
+ if (!p11_rpc_message_read_ulong (msg, &ckerr)) {
+ p11_message ("invalid rpc error response: too short");
+ return CKR_DEVICE_ERROR;
+ }
+
+ if (ckerr <= CKR_OK) {
+ p11_message ("invalid rpc error response: bad error code");
+ return CKR_DEVICE_ERROR;
+ }
+
+ /* An error code from the other side */
+ return (CK_RV)ckerr;
+ }
+
+ /* Make sure other side answered the right call */
+ if (call_id != msg->call_id) {
+ p11_message ("invalid rpc response: call mismatch");
+ return CKR_DEVICE_ERROR;
+ }
+
+ assert (!p11_buffer_failed (msg->input));
+
+ p11_debug ("parsing response values");
+ return CKR_OK;
+}
+
+static CK_RV
+call_done (rpc_client *module,
+ p11_rpc_message *msg,
+ CK_RV ret)
+{
+ assert (module != NULL);
+ assert (msg != NULL);
+
+ /* Check for parsing errors that were not caught elsewhere */
+ if (ret == CKR_OK) {
+ if (p11_buffer_failed (msg->input)) {
+ p11_message ("invalid rpc response: bad argument data");
+ ret = CKR_GENERAL_ERROR;
+ } else {
+ /* Double check that the signature matched our decoding */
+ assert (p11_rpc_message_is_verified (msg));
+ }
+ }
+
+ /* We used the same buffer for input/output, so this frees both */
+ assert (msg->input == msg->output);
+ p11_rpc_buffer_free (msg->input);
+
+ p11_rpc_message_clear (msg);
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * MODULE SPECIFIC PROTOCOL CODE
+ */
+
+static CK_RV
+proto_read_attribute_array (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG len)
+{
+ uint32_t i, num, value, type;
+ CK_ATTRIBUTE_PTR attr;
+ const unsigned char *attrval;
+ size_t attrlen;
+ unsigned char validity;
+ CK_RV ret;
+
+ assert (len != 0);
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "aA"));
+
+ /* Get the number of items. We need this value to be correct */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &num))
+ return PARSE_ERROR;
+
+ /*
+ * This should never happen in normal operation. It denotes a goof up
+ * on the other side of our RPC. We should be indicating the exact number
+ * of attributes to the other side. And it should respond with the same
+ * number.
+ */
+ if (len != num) {
+ p11_message ("received an attribute array with wrong number of attributes");
+ return PARSE_ERROR;
+ }
+
+ ret = CKR_OK;
+
+ /* We need to go ahead and read everything in all cases */
+ for (i = 0; i < num; ++i) {
+
+ /* The attribute type */
+ p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &type);
+
+ /* Attribute validity */
+ p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &validity);
+
+ /* And the data itself */
+ if (validity) {
+ if (p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value) &&
+ p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &attrval, &attrlen)) {
+ if (attrval && value != attrlen) {
+ p11_message ("attribute length does not match attribute data");
+ return PARSE_ERROR;
+ }
+ attrlen = value;
+ }
+ }
+
+ /* Don't act on this data unless no errors */
+ if (p11_buffer_failed (msg->input))
+ break;
+
+ /* Try and stuff it in the output data */
+ if (arr) {
+ attr = &(arr[i]);
+ if (attr->type != type) {
+ p11_message ("returned attributes in invalid order");
+ return PARSE_ERROR;
+ }
+
+ if (validity) {
+ /* Just requesting the attribute size */
+ if (!attr->pValue) {
+ attr->ulValueLen = attrlen;
+
+ /* Wants attribute data, but too small */
+ } else if (attr->ulValueLen < attrlen) {
+ attr->ulValueLen = attrlen;
+ ret = CKR_BUFFER_TOO_SMALL;
+
+ /* Wants attribute data, value is null */
+ } else if (attrval == NULL) {
+ attr->ulValueLen = 0;
+
+ /* Wants attribute data, enough space */
+ } else {
+ attr->ulValueLen = attrlen;
+ memcpy (attr->pValue, attrval, attrlen);
+ }
+
+ /* Not a valid attribute */
+ } else {
+ attr->ulValueLen = ((CK_ULONG)-1);
+ }
+ }
+ }
+
+ if (p11_buffer_failed (msg->input))
+ return PARSE_ERROR;
+
+ /* Read in the code that goes along with these attributes */
+ if (!p11_rpc_message_read_ulong (msg, &ret))
+ return PARSE_ERROR;
+
+ return ret;
+}
+
+static CK_RV
+proto_read_byte_array (p11_rpc_message *msg,
+ CK_BYTE_PTR arr,
+ CK_ULONG_PTR len,
+ CK_ULONG max)
+{
+ const unsigned char *val;
+ unsigned char valid;
+ uint32_t length;
+ size_t vlen;
+
+ assert (len != NULL);
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "ay"));
+
+ /* A single byte which determines whether valid or not */
+ if (!p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ /* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */
+ if (!valid) {
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &length))
+ return PARSE_ERROR;
+
+ *len = length;
+
+ if (arr)
+ return CKR_BUFFER_TOO_SMALL;
+ else
+ return CKR_OK;
+ }
+
+ /* Get the actual bytes */
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &val, &vlen))
+ return PARSE_ERROR;
+
+ *len = vlen;
+
+ /* Just asking us for size */
+ if (!arr)
+ return CKR_OK;
+
+ if (max < vlen)
+ return CKR_BUFFER_TOO_SMALL;
+
+ /* Enough space, yay */
+ memcpy (arr, val, vlen);
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_ulong_array (p11_rpc_message *msg, CK_ULONG_PTR arr,
+ CK_ULONG_PTR len, CK_ULONG max)
+{
+ uint32_t i, num;
+ uint64_t val;
+ unsigned char valid;
+
+ assert (len != NULL);
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "au"));
+
+ /* A single byte which determines whether valid or not */
+ if (!p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ /* Get the number of items. */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &num))
+ return PARSE_ERROR;
+
+ *len = num;
+
+ /* If not valid, then just the length is encoded, this can signify CKR_BUFFER_TOO_SMALL */
+ if (!valid) {
+ if (arr)
+ return CKR_BUFFER_TOO_SMALL;
+ else
+ return CKR_OK;
+ }
+
+ if (max < num)
+ return CKR_BUFFER_TOO_SMALL;
+
+ /* We need to go ahead and read everything in all cases */
+ for (i = 0; i < num; ++i) {
+ p11_rpc_buffer_get_uint64 (msg->input, &msg->parsed, &val);
+ if (arr)
+ arr[i] = (CK_ULONG)val;
+ }
+
+ return p11_buffer_failed (msg->input) ? PARSE_ERROR : CKR_OK;
+}
+
+/* Used to override the supported mechanisms in tests */
+CK_MECHANISM_TYPE *p11_rpc_mechanisms_override_supported = NULL;
+
+static bool
+mechanism_has_sane_parameters (CK_MECHANISM_TYPE type)
+{
+ int i;
+
+ /* This can be set from tests, to override default set of supported */
+ if (p11_rpc_mechanisms_override_supported) {
+ for (i = 0; p11_rpc_mechanisms_override_supported[i] != 0; i++) {
+ if (p11_rpc_mechanisms_override_supported[i] == type)
+ return true;
+ }
+
+ return false;
+ }
+
+ /* This list is incomplete */
+ switch (type) {
+ case CKM_RSA_PKCS_OAEP:
+ case CKM_RSA_PKCS_PSS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+mechanism_has_no_parameters (CK_MECHANISM_TYPE mech)
+{
+ /* This list is incomplete */
+
+ switch (mech) {
+ case CKM_RSA_PKCS_KEY_PAIR_GEN:
+ case CKM_RSA_X9_31_KEY_PAIR_GEN:
+ case CKM_RSA_PKCS:
+ case CKM_RSA_9796:
+ case CKM_RSA_X_509:
+ case CKM_RSA_X9_31:
+ case CKM_MD2_RSA_PKCS:
+ case CKM_MD5_RSA_PKCS:
+ case CKM_SHA1_RSA_PKCS:
+ case CKM_SHA256_RSA_PKCS:
+ case CKM_SHA384_RSA_PKCS:
+ case CKM_SHA512_RSA_PKCS:
+ case CKM_RIPEMD128_RSA_PKCS:
+ case CKM_RIPEMD160_RSA_PKCS:
+ case CKM_SHA1_RSA_X9_31:
+ case CKM_DSA_KEY_PAIR_GEN:
+ case CKM_DSA_PARAMETER_GEN:
+ case CKM_DSA:
+ case CKM_DSA_SHA1:
+ case CKM_FORTEZZA_TIMESTAMP:
+ case CKM_EC_KEY_PAIR_GEN:
+ case CKM_ECDSA:
+ case CKM_ECDSA_SHA1:
+ case CKM_DH_PKCS_KEY_PAIR_GEN:
+ case CKM_DH_PKCS_PARAMETER_GEN:
+ case CKM_X9_42_DH_KEY_PAIR_GEN:
+ case CKM_X9_42_DH_PARAMETER_GEN:
+ case CKM_KEA_KEY_PAIR_GEN:
+ case CKM_GENERIC_SECRET_KEY_GEN:
+ case CKM_RC2_KEY_GEN:
+ case CKM_RC4_KEY_GEN:
+ case CKM_RC4:
+ case CKM_RC5_KEY_GEN:
+ case CKM_AES_KEY_GEN:
+ case CKM_AES_ECB:
+ case CKM_AES_MAC:
+ case CKM_DES_KEY_GEN:
+ case CKM_DES2_KEY_GEN:
+ case CKM_DES3_KEY_GEN:
+ case CKM_CDMF_KEY_GEN:
+ case CKM_CAST_KEY_GEN:
+ case CKM_CAST3_KEY_GEN:
+ case CKM_CAST128_KEY_GEN:
+ case CKM_IDEA_KEY_GEN:
+ case CKM_SSL3_PRE_MASTER_KEY_GEN:
+ case CKM_TLS_PRE_MASTER_KEY_GEN:
+ case CKM_SKIPJACK_KEY_GEN:
+ case CKM_BATON_KEY_GEN:
+ case CKM_JUNIPER_KEY_GEN:
+ case CKM_RC2_ECB:
+ case CKM_DES_ECB:
+ case CKM_DES3_ECB:
+ case CKM_CDMF_ECB:
+ case CKM_CAST_ECB:
+ case CKM_CAST3_ECB:
+ case CKM_CAST128_ECB:
+ case CKM_RC5_ECB:
+ case CKM_IDEA_ECB:
+ case CKM_RC2_MAC:
+ case CKM_DES_MAC:
+ case CKM_DES3_MAC:
+ case CKM_CDMF_MAC:
+ case CKM_CAST_MAC:
+ case CKM_CAST3_MAC:
+ case CKM_RC5_MAC:
+ case CKM_IDEA_MAC:
+ case CKM_SSL3_MD5_MAC:
+ case CKM_SSL3_SHA1_MAC:
+ case CKM_SKIPJACK_WRAP:
+ case CKM_BATON_WRAP:
+ case CKM_JUNIPER_WRAP:
+ case CKM_MD2:
+ case CKM_MD2_HMAC:
+ case CKM_MD5:
+ case CKM_MD5_HMAC:
+ case CKM_SHA_1:
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA256:
+ case CKM_SHA256_HMAC:
+ case CKM_SHA384:
+ case CKM_SHA384_HMAC:
+ case CKM_SHA512:
+ case CKM_SHA512_HMAC:
+ case CKM_FASTHASH:
+ case CKM_RIPEMD128:
+ case CKM_RIPEMD128_HMAC:
+ case CKM_RIPEMD160:
+ case CKM_RIPEMD160_HMAC:
+ case CKM_KEY_WRAP_LYNKS:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool
+mechanism_is_supported (CK_MECHANISM_TYPE mech)
+{
+ if (mechanism_has_no_parameters (mech) ||
+ mechanism_has_sane_parameters (mech))
+ return true;
+ return false;
+}
+static void
+mechanism_list_purge (CK_MECHANISM_TYPE_PTR mechs,
+ CK_ULONG *n_mechs)
+{
+ int i;
+
+ assert (mechs != NULL);
+ assert (n_mechs != NULL);
+
+ for (i = 0; i < (int)(*n_mechs); ++i) {
+ if (!mechanism_is_supported (mechs[i])) {
+
+ /* Remove the mechanism from the list */
+ memmove (&mechs[i], &mechs[i + 1],
+ (*n_mechs - i) * sizeof (CK_MECHANISM_TYPE));
+
+ --(*n_mechs);
+ --i;
+ }
+ }
+}
+
+static CK_RV
+proto_write_mechanism (p11_rpc_message *msg,
+ CK_MECHANISM_PTR mech)
+{
+ assert (msg != NULL);
+ assert (mech != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "M"));
+
+ /* The mechanism type */
+ p11_rpc_buffer_add_uint32 (msg->output, mech->mechanism);
+
+ /*
+ * PKCS#11 mechanism parameters are not easy to serialize. They're
+ * completely different for so many mechanisms, they contain
+ * pointers to arbitrary memory, and many callers don't initialize
+ * them completely or properly.
+ *
+ * We only support certain mechanisms.
+ *
+ * Also callers do yucky things like leaving parts of the structure
+ * pointing to garbage if they don't think it's going to be used.
+ */
+
+ if (mechanism_has_no_parameters (mech->mechanism))
+ p11_rpc_buffer_add_byte_array (msg->output, NULL, 0);
+ else if (mechanism_has_sane_parameters (mech->mechanism))
+ p11_rpc_buffer_add_byte_array (msg->output, mech->pParameter,
+ mech->ulParameterLen);
+ else
+ return CKR_MECHANISM_INVALID;
+
+ return p11_buffer_failed (msg->output) ? CKR_HOST_MEMORY : CKR_OK;
+}
+
+static CK_RV
+proto_read_info (p11_rpc_message *msg,
+ CK_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_read_version (msg, &info->cryptokiVersion) ||
+ !p11_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_read_ulong (msg, &info->flags) ||
+ !p11_rpc_message_read_space_string (msg, info->libraryDescription, 32) ||
+ !p11_rpc_message_read_version (msg, &info->libraryVersion))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_slot_info (p11_rpc_message *msg,
+ CK_SLOT_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_read_space_string (msg, info->slotDescription, 64) ||
+ !p11_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_read_ulong (msg, &info->flags) ||
+ !p11_rpc_message_read_version (msg, &info->hardwareVersion) ||
+ !p11_rpc_message_read_version (msg, &info->firmwareVersion))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_token_info (p11_rpc_message *msg,
+ CK_TOKEN_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_read_space_string (msg, info->label, 32) ||
+ !p11_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_read_space_string (msg, info->model, 16) ||
+ !p11_rpc_message_read_space_string (msg, info->serialNumber, 16) ||
+ !p11_rpc_message_read_ulong (msg, &info->flags) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulMaxSessionCount) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulSessionCount) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulMaxRwSessionCount) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulRwSessionCount) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulMaxPinLen) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulMinPinLen) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulTotalPublicMemory) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulFreePublicMemory) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulTotalPrivateMemory) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulFreePrivateMemory) ||
+ !p11_rpc_message_read_version (msg, &info->hardwareVersion) ||
+ !p11_rpc_message_read_version (msg, &info->firmwareVersion) ||
+ !p11_rpc_message_read_space_string (msg, info->utcTime, 16))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_mechanism_info (p11_rpc_message *msg,
+ CK_MECHANISM_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_read_ulong (msg, &info->ulMinKeySize) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulMaxKeySize) ||
+ !p11_rpc_message_read_ulong (msg, &info->flags))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_sesssion_info (p11_rpc_message *msg,
+ CK_SESSION_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_read_ulong (msg, &info->slotID) ||
+ !p11_rpc_message_read_ulong (msg, &info->state) ||
+ !p11_rpc_message_read_ulong (msg, &info->flags) ||
+ !p11_rpc_message_read_ulong (msg, &info->ulDeviceError))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+/* -------------------------------------------------------------------
+ * CALL MACROS
+ */
+
+#define BEGIN_CALL_OR(call_id, self, if_no_daemon) \
+ p11_debug (#call_id ": enter"); \
+ { \
+ rpc_client *_mod = ((p11_virtual *)self)->lower_module; p11_rpc_message _msg; \
+ CK_RV _ret = call_prepare (_mod, &_msg, P11_RPC_CALL_##call_id); \
+ if (_ret == CKR_DEVICE_REMOVED) return (if_no_daemon); \
+ if (_ret != CKR_OK) return _ret;
+
+#define PROCESS_CALL \
+ _ret = call_run (_mod, &_msg); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define RETURN(ret) \
+ _ret = ret; \
+ goto _cleanup;
+
+#define END_CALL \
+ _cleanup: \
+ _ret = call_done (_mod, &_msg, _ret); \
+ p11_debug ("ret: %lu", _ret); \
+ return _ret; \
+ }
+
+#define IN_BYTE(val) \
+ if (!p11_rpc_message_write_byte (&_msg, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG(val) \
+ if (!p11_rpc_message_write_ulong (&_msg, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_STRING(val) \
+ if (!p11_rpc_message_write_zero_string (&_msg, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_BYTE_BUFFER(arr, len) \
+ if (len == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!p11_rpc_message_write_byte_buffer (&_msg, arr ? *len : 0)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_BYTE_ARRAY(arr, len) \
+ if (len != 0 && arr == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!p11_rpc_message_write_byte_array (&_msg, arr, len)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG_BUFFER(arr, len) \
+ if (len == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!p11_rpc_message_write_ulong_buffer (&_msg, arr ? *len : 0)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG_ARRAY(arr, len) \
+ if (len != 0 && arr == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; }\
+ if (!p11_rpc_message_write_ulong_array (&_msg, arr, len)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ATTRIBUTE_BUFFER(arr, num) \
+ if (num != 0 && arr == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!p11_rpc_message_write_attribute_buffer (&_msg, (arr), (num))) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ATTRIBUTE_ARRAY(arr, num) \
+ if (num != 0 && arr == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!p11_rpc_message_write_attribute_array (&_msg, (arr), (num))) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_MECHANISM_TYPE(val) \
+ if(!mechanism_is_supported (val)) \
+ { _ret = CKR_MECHANISM_INVALID; goto _cleanup; } \
+ if (!p11_rpc_message_write_ulong (&_msg, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_MECHANISM(val) \
+ if (val == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ _ret = proto_write_mechanism (&_msg, val); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+
+
+#define OUT_ULONG(val) \
+ if (val == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK && !p11_rpc_message_read_ulong (&_msg, val)) \
+ _ret = PARSE_ERROR;
+
+#define OUT_BYTE_ARRAY(arr, len) \
+ if (len == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_byte_array (&_msg, (arr), (len), *(len));
+
+#define OUT_ULONG_ARRAY(a, len) \
+ if (len == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_ulong_array (&_msg, (a), (len), *(len));
+
+#define OUT_ATTRIBUTE_ARRAY(arr, num) \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_attribute_array (&_msg, (arr), (num));
+
+#define OUT_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_info (&_msg, info);
+
+#define OUT_SLOT_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_slot_info (&_msg, info);
+
+#define OUT_TOKEN_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_token_info (&_msg, info);
+
+#define OUT_SESSION_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_sesssion_info (&_msg, info);
+
+#define OUT_MECHANISM_TYPE_ARRAY(arr, len) \
+ if (len == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_ulong_array (&_msg, (arr), (len), *(len)); \
+ if (_ret == CKR_OK && arr) \
+ mechanism_list_purge (arr, len);
+
+#define OUT_MECHANISM_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_mechanism_info (&_msg, info);
+
+
+/* -------------------------------------------------------------------
+ * INITIALIZATION and 'GLOBAL' CALLS
+ */
+
+static CK_RV
+rpc_C_Initialize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR init_args)
+{
+ rpc_client *module = ((p11_virtual *)self)->lower_module;
+ CK_C_INITIALIZE_ARGS_PTR args = NULL;
+ void *reserved = NULL;
+ CK_RV ret = CKR_OK;
+ p11_rpc_message msg;
+ pid_t pid;
+
+ assert (module != NULL);
+ p11_debug ("C_Initialize: enter");
+
+ if (init_args != NULL) {
+ int supplied_ok;
+
+ /* pReserved must be NULL */
+ args = init_args;
+
+ /* ALL supplied function pointers need to have the value either NULL or non-NULL. */
+ supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL &&
+ args->LockMutex == NULL && args->UnlockMutex == NULL) ||
+ (args->CreateMutex != NULL && args->DestroyMutex != NULL &&
+ args->LockMutex != NULL && args->UnlockMutex != NULL);
+ if (!supplied_ok) {
+ p11_message ("invalid set of mutex calls supplied");
+ return CKR_ARGUMENTS_BAD;
+ }
+
+ /*
+ * When the CKF_OS_LOCKING_OK flag isn't set return an error.
+ * We must be able to use our mutex functionality.
+ */
+ if (!(args->flags & CKF_OS_LOCKING_OK)) {
+ p11_message ("can't do without os locking");
+ return CKR_CANT_LOCK;
+ }
+
+ if (args->pReserved)
+ reserved = args->pReserved;
+ }
+
+ p11_mutex_lock (&module->mutex);
+
+ pid = getpid ();
+ if (module->initialized_pid != 0) {
+ /* This process has called C_Initialize already */
+ if (pid == module->initialized_pid) {
+ p11_message ("C_Initialize called twice for same process");
+ ret = CKR_CRYPTOKI_ALREADY_INITIALIZED;
+ goto done;
+ }
+ }
+
+ /* Call out to initialize client callback */
+ assert (module->vtable->connect != NULL);
+ ret = (module->vtable->connect) (module->vtable, reserved);
+
+ /* Successfully initialized */
+ if (ret == CKR_OK) {
+ module->initialized_pid = pid;
+ module->initialize_done = true;
+
+ /* Server doesn't exist, initialize but don't call */
+ } else if (ret == CKR_DEVICE_REMOVED) {
+ module->initialized_pid = pid;
+ module->initialize_done = false;
+ ret = CKR_OK;
+ goto done;
+
+ } else {
+ goto done;
+ }
+
+ /* If we don't have read and write fds now, then initialize other side */
+ ret = call_prepare (module, &msg, P11_RPC_CALL_C_Initialize);
+ if (ret == CKR_OK)
+ if (!p11_rpc_message_write_byte_array (&msg, P11_RPC_HANDSHAKE, P11_RPC_HANDSHAKE_LEN))
+ ret = CKR_HOST_MEMORY;
+ if (ret == CKR_OK)
+ ret = call_run (module, &msg);
+ call_done (module, &msg, ret);
+
+done:
+ /* If failed then unmark initialized */
+ if (ret != CKR_OK && ret != CKR_CRYPTOKI_ALREADY_INITIALIZED)
+ module->initialized_pid = 0;
+
+ /* If we told our caller that we're initialized, but not really, then finalize */
+ if (ret != CKR_OK && module->initialize_done) {
+ module->initialize_done = false;
+ assert (module->vtable->disconnect != NULL);
+ (module->vtable->disconnect) (module->vtable, reserved);
+ }
+
+ p11_mutex_unlock (&module->mutex);
+
+ p11_debug ("C_Initialize: %lu", ret);
+ return ret;
+}
+
+static CK_RV
+rpc_C_Finalize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR reserved)
+{
+ rpc_client *module = ((p11_virtual *)self)->lower_module;
+ CK_RV ret = CKR_OK;
+ p11_rpc_message msg;
+
+ p11_debug ("C_Finalize: enter");
+ return_val_if_fail (module->initialized_pid != 0, CKR_CRYPTOKI_NOT_INITIALIZED);
+ return_val_if_fail (!reserved, CKR_ARGUMENTS_BAD);
+
+ p11_mutex_lock (&module->mutex);
+
+ if (module->initialize_done) {
+ ret = call_prepare (module, &msg, P11_RPC_CALL_C_Finalize);
+ if (ret == CKR_OK)
+ ret = call_run (module, &msg);
+ call_done (module, &msg, ret);
+ if (ret != CKR_OK)
+ p11_message ("finalizing rpc module returned an error: %lu", ret);
+
+ module->initialize_done = false;
+ assert (module->vtable->disconnect != NULL);
+ (module->vtable->disconnect) (module->vtable, reserved);
+ }
+
+ module->initialized_pid = 0;
+
+ p11_mutex_unlock (&module->mutex);
+
+ p11_debug ("C_Finalize: %lu", CKR_OK);
+ return CKR_OK;
+}
+
+static CK_RV
+fill_stand_in_info (CK_INFO_PTR info)
+{
+ static CK_INFO stand_in_info = {
+ { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
+ "p11-kit ",
+ 0,
+ "p11-kit (no connection) ",
+ { 1, 1 },
+ };
+ memcpy (info, &stand_in_info, sizeof (CK_INFO));
+ return CKR_OK;
+
+}
+
+static CK_RV
+rpc_C_GetInfo (CK_X_FUNCTION_LIST *self,
+ CK_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetInfo, self, fill_stand_in_info (info));
+ PROCESS_CALL;
+ OUT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotList (CK_X_FUNCTION_LIST *self,
+ CK_BBOOL token_present,
+ CK_SLOT_ID_PTR slot_list,
+ CK_ULONG_PTR count)
+{
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetSlotList, self, (*count = 0, CKR_OK));
+ IN_BYTE (token_present);
+ IN_ULONG_BUFFER (slot_list, count);
+ PROCESS_CALL;
+ OUT_ULONG_ARRAY (slot_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_SLOT_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetSlotInfo, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ PROCESS_CALL;
+ OUT_SLOT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetTokenInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_TOKEN_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetTokenInfo, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ PROCESS_CALL;
+ OUT_TOKEN_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismList (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_MECHANISM_TYPE_PTR mechanism_list,
+ CK_ULONG_PTR count)
+{
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetMechanismList, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ IN_ULONG_BUFFER (mechanism_list, count);
+ PROCESS_CALL;
+ OUT_MECHANISM_TYPE_ARRAY (mechanism_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetMechanismInfo, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ IN_MECHANISM_TYPE (type);
+ PROCESS_CALL;
+ OUT_MECHANISM_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitToken (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_UTF8CHAR_PTR pin, CK_ULONG pin_len,
+ CK_UTF8CHAR_PTR label)
+{
+ BEGIN_CALL_OR (C_InitToken, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ IN_BYTE_ARRAY (pin, pin_len);
+ IN_STRING (label);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WaitForSlotEvent (CK_X_FUNCTION_LIST *self,
+ CK_FLAGS flags,
+ CK_SLOT_ID_PTR slot,
+ CK_VOID_PTR reserved)
+{
+ return_val_if_fail (slot, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_WaitForSlotEvent, self, CKR_DEVICE_REMOVED);
+ IN_ULONG (flags);
+ PROCESS_CALL;
+ OUT_ULONG (slot);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_OpenSession (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id,
+ CK_FLAGS flags,
+ CK_VOID_PTR user_data,
+ CK_NOTIFY callback,
+ CK_SESSION_HANDLE_PTR session)
+{
+ return_val_if_fail (session, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_OpenSession, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ IN_ULONG (flags);
+ PROCESS_CALL;
+ OUT_ULONG (session);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseSession (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL_OR (C_CloseSession, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseAllSessions (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slot_id)
+{
+ BEGIN_CALL_OR (C_CloseAllSessions, self, CKR_SLOT_ID_INVALID);
+ IN_ULONG (slot_id);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSessionInfo (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_SESSION_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetSessionInfo, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ OUT_SESSION_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitPIN (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ BEGIN_CALL_OR (C_InitPIN, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetPIN (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_UTF8CHAR_PTR old_pin,
+ CK_ULONG old_pin_len,
+ CK_UTF8CHAR_PTR new_pin,
+ CK_ULONG new_pin_len)
+{
+ BEGIN_CALL_OR (C_SetPIN, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (old_pin, old_pin_len);
+ IN_BYTE_ARRAY (new_pin, new_pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetOperationState (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR operation_state,
+ CK_ULONG_PTR operation_state_len)
+{
+ return_val_if_fail (operation_state_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetOperationState, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (operation_state, operation_state_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (operation_state, operation_state_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetOperationState (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR operation_state,
+ CK_ULONG operation_state_len,
+ CK_OBJECT_HANDLE encryption_key,
+ CK_OBJECT_HANDLE authentication_key)
+{
+ BEGIN_CALL_OR (C_SetOperationState, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (operation_state, operation_state_len);
+ IN_ULONG (encryption_key);
+ IN_ULONG (authentication_key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Login (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_USER_TYPE user_type,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ BEGIN_CALL_OR (C_Login, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (user_type);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Logout (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL_OR (C_Logout, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CreateObject (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR new_object)
+{
+ return_val_if_fail (new_object, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_CreateObject, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CopyObject (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR new_object)
+{
+ return_val_if_fail (new_object, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_CopyObject, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+
+static CK_RV
+rpc_C_DestroyObject (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object)
+{
+ BEGIN_CALL_OR (C_DestroyObject, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetObjectSize (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ CK_ULONG_PTR size)
+{
+ return_val_if_fail (size, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_GetObjectSize, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL;
+ OUT_ULONG (size);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetAttributeValue (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ BEGIN_CALL_OR (C_GetAttributeValue, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_BUFFER (template, count);
+ PROCESS_CALL;
+ OUT_ATTRIBUTE_ARRAY (template, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetAttributeValue (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ BEGIN_CALL_OR (C_SetAttributeValue, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ BEGIN_CALL_OR (C_FindObjectsInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjects (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_count,
+ CK_ULONG_PTR count)
+{
+ /* HACK: To fix a stupid gcc warning */
+ CK_ULONG_PTR address_of_max_count = &max_count;
+
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_FindObjects, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG_BUFFER (objects, address_of_max_count);
+ PROCESS_CALL;
+ *count = max_count;
+ OUT_ULONG_ARRAY (objects, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL_OR (C_FindObjectsFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_EncryptInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Encrypt (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR encrypted_data,
+ CK_ULONG_PTR encrypted_data_len)
+{
+ return_val_if_fail (encrypted_data_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_Encrypt, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (encrypted_data, encrypted_data_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (encrypted_data, encrypted_data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR encrypted_part,
+ CK_ULONG_PTR encrypted_part_len)
+{
+ return_val_if_fail (encrypted_part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_EncryptUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR last_part,
+ CK_ULONG_PTR last_part_len)
+{
+ return_val_if_fail (last_part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_EncryptFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_part, last_part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (last_part, last_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_DecryptInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Decrypt (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR enc_data,
+ CK_ULONG enc_data_len,
+ CK_BYTE_PTR data,
+ CK_ULONG_PTR data_len)
+{
+ return_val_if_fail (data_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_Decrypt, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (enc_data, enc_data_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_fail (part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DecryptUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (enc_part, enc_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR last_part,
+ CK_ULONG_PTR last_part_len)
+{
+ return_val_if_fail (last_part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DecryptFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_part, last_part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (last_part, last_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism)
+{
+ BEGIN_CALL_OR (C_DigestInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Digest (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ return_val_if_fail (digest_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_Digest, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ BEGIN_CALL_OR (C_DigestUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestKey (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_DigestKey, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ return_val_if_fail (digest_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DigestFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_SignInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Sign (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_fail (signature_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_Sign, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ return_val_if_fail (part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_SignUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_fail (signature_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_SignFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecoverInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_SignRecoverInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecover (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
+{
+ return_val_if_fail (signature_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_SignRecover, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_VerifyInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Verify (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ BEGIN_CALL_OR (C_Verify, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ BEGIN_CALL_OR (C_VerifyUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyFinal (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ BEGIN_CALL_OR (C_VerifyFinal, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecoverInit (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL_OR (C_VerifyRecoverInit, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecover (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len,
+ CK_BYTE_PTR data,
+ CK_ULONG_PTR data_len)
+{
+ return_val_if_fail (data_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_VerifyRecover, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestEncryptUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG_PTR enc_part_len)
+{
+ return_val_if_fail (enc_part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DigestEncryptUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (enc_part, enc_part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (enc_part, enc_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptDigestUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_fail (part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DecryptDigestUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (enc_part, enc_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignEncryptUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG_PTR enc_part_len)
+{
+ return_val_if_fail (enc_part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_SignEncryptUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (enc_part, enc_part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (enc_part, enc_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptVerifyUpdate (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_fail (part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_DecryptVerifyUpdate, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (enc_part, enc_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateKey (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ BEGIN_CALL_OR (C_GenerateKey, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateKeyPair (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR pub_template,
+ CK_ULONG pub_count,
+ CK_ATTRIBUTE_PTR priv_template,
+ CK_ULONG priv_count,
+ CK_OBJECT_HANDLE_PTR pub_key,
+ CK_OBJECT_HANDLE_PTR priv_key)
+{
+ BEGIN_CALL_OR (C_GenerateKeyPair, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ATTRIBUTE_ARRAY (pub_template, pub_count);
+ IN_ATTRIBUTE_ARRAY (priv_template, priv_count);
+ PROCESS_CALL;
+ OUT_ULONG (pub_key);
+ OUT_ULONG (priv_key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WrapKey (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE wrapping_key,
+ CK_OBJECT_HANDLE key,
+ CK_BYTE_PTR wrapped_key,
+ CK_ULONG_PTR wrapped_key_len)
+{
+ return_val_if_fail (wrapped_key_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL_OR (C_WrapKey, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (wrapping_key);
+ IN_ULONG (key);
+ IN_BYTE_BUFFER (wrapped_key, wrapped_key_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (wrapped_key, wrapped_key_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_UnwrapKey (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE unwrapping_key,
+ CK_BYTE_PTR wrapped_key,
+ CK_ULONG wrapped_key_len,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ BEGIN_CALL_OR (C_UnwrapKey, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (unwrapping_key);
+ IN_BYTE_ARRAY (wrapped_key, wrapped_key_len);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DeriveKey (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE base_key,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ BEGIN_CALL_OR (C_DeriveKey, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (base_key);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SeedRandom (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR seed,
+ CK_ULONG seed_len)
+{
+ BEGIN_CALL_OR (C_SeedRandom, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (seed, seed_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateRandom (CK_X_FUNCTION_LIST *self,
+ CK_SESSION_HANDLE session,
+ CK_BYTE_PTR random_data,
+ CK_ULONG random_len)
+{
+ CK_ULONG_PTR address = &random_len;
+
+ BEGIN_CALL_OR (C_GenerateRandom, self, CKR_SESSION_HANDLE_INVALID);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (random_data, address);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (random_data, address);
+ END_CALL;
+}
+
+static CK_X_FUNCTION_LIST rpc_functions = {
+ { -1, -1 },
+ rpc_C_Initialize,
+ rpc_C_Finalize,
+ rpc_C_GetInfo,
+ rpc_C_GetSlotList,
+ rpc_C_GetSlotInfo,
+ rpc_C_GetTokenInfo,
+ rpc_C_GetMechanismList,
+ rpc_C_GetMechanismInfo,
+ rpc_C_InitToken,
+ rpc_C_InitPIN,
+ rpc_C_SetPIN,
+ rpc_C_OpenSession,
+ rpc_C_CloseSession,
+ rpc_C_CloseAllSessions,
+ rpc_C_GetSessionInfo,
+ rpc_C_GetOperationState,
+ rpc_C_SetOperationState,
+ rpc_C_Login,
+ rpc_C_Logout,
+ rpc_C_CreateObject,
+ rpc_C_CopyObject,
+ rpc_C_DestroyObject,
+ rpc_C_GetObjectSize,
+ rpc_C_GetAttributeValue,
+ rpc_C_SetAttributeValue,
+ rpc_C_FindObjectsInit,
+ rpc_C_FindObjects,
+ rpc_C_FindObjectsFinal,
+ rpc_C_EncryptInit,
+ rpc_C_Encrypt,
+ rpc_C_EncryptUpdate,
+ rpc_C_EncryptFinal,
+ rpc_C_DecryptInit,
+ rpc_C_Decrypt,
+ rpc_C_DecryptUpdate,
+ rpc_C_DecryptFinal,
+ rpc_C_DigestInit,
+ rpc_C_Digest,
+ rpc_C_DigestUpdate,
+ rpc_C_DigestKey,
+ rpc_C_DigestFinal,
+ rpc_C_SignInit,
+ rpc_C_Sign,
+ rpc_C_SignUpdate,
+ rpc_C_SignFinal,
+ rpc_C_SignRecoverInit,
+ rpc_C_SignRecover,
+ rpc_C_VerifyInit,
+ rpc_C_Verify,
+ rpc_C_VerifyUpdate,
+ rpc_C_VerifyFinal,
+ rpc_C_VerifyRecoverInit,
+ rpc_C_VerifyRecover,
+ rpc_C_DigestEncryptUpdate,
+ rpc_C_DecryptDigestUpdate,
+ rpc_C_SignEncryptUpdate,
+ rpc_C_DecryptVerifyUpdate,
+ rpc_C_GenerateKey,
+ rpc_C_GenerateKeyPair,
+ rpc_C_WrapKey,
+ rpc_C_UnwrapKey,
+ rpc_C_DeriveKey,
+ rpc_C_SeedRandom,
+ rpc_C_GenerateRandom,
+ rpc_C_WaitForSlotEvent,
+};
+
+static void
+rpc_client_free (void *data)
+{
+ rpc_client *client = data;
+ p11_mutex_uninit (&client->mutex);
+ free (client);
+}
+
+bool
+p11_rpc_client_init (p11_virtual *virt,
+ p11_rpc_client_vtable *vtable)
+{
+ rpc_client *client;
+
+ p11_message_clear ();
+
+ return_val_if_fail (vtable != NULL, false);
+ return_val_if_fail (vtable->connect != NULL, false);
+ return_val_if_fail (vtable->transport != NULL, false);
+ return_val_if_fail (vtable->disconnect != NULL, false);
+
+ P11_RPC_CHECK_CALLS ();
+
+ client = calloc (1, sizeof (rpc_client));
+ return_val_if_fail (client != NULL, false);
+
+ p11_mutex_init (&client->mutex);
+ client->vtable = vtable;
+
+ p11_virtual_init (virt, &rpc_functions, client, rpc_client_free);
+ return true;
+}
diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c
new file mode 100644
index 0000000..30c331e
--- /dev/null
+++ b/p11-kit/rpc-message.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#include "config.h"
+
+#include "debug.h"
+#include "library.h"
+#include "message.h"
+#include "private.h"
+#include "rpc-message.h"
+
+#include <assert.h>
+#include <string.h>
+
+void
+p11_rpc_message_init (p11_rpc_message *msg,
+ p11_buffer *input,
+ p11_buffer *output)
+{
+ assert (input != NULL);
+ assert (output != NULL);
+ assert (output->ffree != NULL);
+ assert (output->frealloc != NULL);
+
+ memset (msg, 0, sizeof (*msg));
+
+ msg->output = output;
+ msg->input = input;
+}
+
+void
+p11_rpc_message_clear (p11_rpc_message *msg)
+{
+ void *allocated;
+ void **data;
+
+ assert (msg != NULL);
+
+ /* Free up the extra allocated memory */
+ allocated = msg->extra;
+ while (allocated != NULL) {
+ data = (void **)allocated;
+
+ /* Pointer to the next allocation */
+ allocated = *data;
+ assert (msg->output->ffree);
+ (msg->output->ffree) (data);
+ }
+
+ msg->output = NULL;
+ msg->input = NULL;
+ msg->extra = NULL;
+}
+
+void *
+p11_rpc_message_alloc_extra (p11_rpc_message *msg,
+ size_t length)
+{
+ void **data;
+
+ assert (msg != NULL);
+
+ if (length > 0x7fffffff)
+ return NULL;
+
+ assert (msg->output->frealloc != NULL);
+ data = (msg->output->frealloc) (NULL, sizeof (void *) + length);
+ if (data == NULL)
+ return NULL;
+
+ /* Munch up the memory to help catch bugs */
+ memset (data, 0xff, sizeof (void *) + length);
+
+ /* Store pointer to next allocated block at beginning */
+ *data = msg->extra;
+ msg->extra = data;
+
+ /* Data starts after first pointer */
+ return (void *)(data + 1);
+}
+
+bool
+p11_rpc_message_prep (p11_rpc_message *msg,
+ int call_id,
+ p11_rpc_message_type type)
+{
+ int len;
+
+ assert (type != 0);
+ assert (call_id >= P11_RPC_CALL_ERROR);
+ assert (call_id < P11_RPC_CALL_MAX);
+
+ p11_buffer_reset (msg->output, 0);
+ msg->signature = NULL;
+
+ /* The call id and signature */
+ if (type == P11_RPC_REQUEST)
+ msg->signature = p11_rpc_calls[call_id].request;
+ else if (type == P11_RPC_RESPONSE)
+ msg->signature = p11_rpc_calls[call_id].response;
+ else
+ assert_not_reached ();
+ assert (msg->signature != NULL);
+ msg->sigverify = msg->signature;
+
+ msg->call_id = call_id;
+ msg->call_type = type;
+
+ /* Encode the two of them */
+ p11_rpc_buffer_add_uint32 (msg->output, call_id);
+ if (msg->signature) {
+ len = strlen (msg->signature);
+ p11_rpc_buffer_add_byte_array (msg->output, (unsigned char*)msg->signature, len);
+ }
+
+ msg->parsed = 0;
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_parse (p11_rpc_message *msg,
+ p11_rpc_message_type type)
+{
+ const unsigned char *val;
+ size_t len;
+ uint32_t call_id;
+
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ msg->parsed = 0;
+
+ /* Pull out the call identifier */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &call_id)) {
+ p11_message ("invalid message: couldn't read call identifier");
+ return false;
+ }
+
+ msg->signature = msg->sigverify = NULL;
+
+ /* The call id and signature */
+ if (call_id < 0 || call_id >= P11_RPC_CALL_MAX) {
+ p11_message ("invalid message: bad call id: %d", call_id);
+ return false;
+ }
+ if (type == P11_RPC_REQUEST)
+ msg->signature = p11_rpc_calls[call_id].request;
+ else if (type == P11_RPC_RESPONSE)
+ msg->signature = p11_rpc_calls[call_id].response;
+ else
+ assert_not_reached ();
+ assert (msg->signature != NULL);
+ msg->call_id = call_id;
+ msg->call_type = type;
+ msg->sigverify = msg->signature;
+
+ /* Verify the incoming signature */
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &val, &len)) {
+ p11_message ("invalid message: couldn't read signature");
+ return false;
+ }
+
+ if ((strlen (msg->signature) != len) || (memcmp (val, msg->signature, len) != 0)) {
+ p11_message ("invalid message: signature doesn't match");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+p11_rpc_message_verify_part (p11_rpc_message *msg,
+ const char* part)
+{
+ int len;
+ bool ok;
+
+ if (!msg->sigverify)
+ return true;
+
+ len = strlen (part);
+ ok = (strncmp (msg->sigverify, part, len) == 0);
+ if (ok)
+ msg->sigverify += len;
+ return ok;
+}
+
+bool
+p11_rpc_message_write_attribute_buffer (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num)
+{
+ CK_ATTRIBUTE_PTR attr;
+ CK_ULONG i;
+
+ assert (num == 0 || arr != NULL);
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fA"));
+
+ /* Write the number of items */
+ p11_rpc_buffer_add_uint32 (msg->output, num);
+
+ for (i = 0; i < num; ++i) {
+ attr = &(arr[i]);
+
+ /* The attribute type */
+ p11_rpc_buffer_add_uint32 (msg->output, attr->type);
+
+ /* And the attribute buffer length */
+ p11_rpc_buffer_add_uint32 (msg->output, attr->pValue ? attr->ulValueLen : 0);
+ }
+
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_attribute_array (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num)
+{
+ CK_ULONG i;
+ CK_ATTRIBUTE_PTR attr;
+ unsigned char validity;
+
+ assert (num == 0 || arr != NULL);
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "aA"));
+
+ /* Write the number of items */
+ p11_rpc_buffer_add_uint32 (msg->output, num);
+
+ for (i = 0; i < num; ++i) {
+ attr = &(arr[i]);
+
+ /* The attribute type */
+ p11_rpc_buffer_add_uint32 (msg->output, attr->type);
+
+ /* Write out the attribute validity */
+ validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1;
+ p11_rpc_buffer_add_byte (msg->output, validity);
+
+ /* The attribute length and value */
+ if (validity) {
+ p11_rpc_buffer_add_uint32 (msg->output, attr->ulValueLen);
+ p11_rpc_buffer_add_byte_array (msg->output, attr->pValue, attr->ulValueLen);
+ }
+ }
+
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_read_byte (p11_rpc_message *msg,
+ CK_BYTE *val)
+{
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "y"));
+ return p11_rpc_buffer_get_byte (msg->input, &msg->parsed, val);
+}
+
+bool
+p11_rpc_message_write_byte (p11_rpc_message *msg,
+ CK_BYTE val)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "y"));
+ p11_rpc_buffer_add_byte (msg->output, val);
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_read_ulong (p11_rpc_message *msg,
+ CK_ULONG *val)
+{
+ uint64_t v;
+
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "u"));
+
+ if (!p11_rpc_buffer_get_uint64 (msg->input, &msg->parsed, &v))
+ return false;
+ if (val)
+ *val = (CK_ULONG)v;
+ return true;
+}
+
+bool
+p11_rpc_message_write_ulong (p11_rpc_message *msg,
+ CK_ULONG val)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "u"));
+ p11_rpc_buffer_add_uint64 (msg->output, val);
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_byte_buffer (p11_rpc_message *msg,
+ CK_ULONG count)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fy"));
+ p11_rpc_buffer_add_uint32 (msg->output, count);
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_byte_array (p11_rpc_message *msg,
+ CK_BYTE_PTR arr,
+ CK_ULONG num)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "ay"));
+
+ /* No array, no data, just length */
+ if (!arr) {
+ p11_rpc_buffer_add_byte (msg->output, 0);
+ p11_rpc_buffer_add_uint32 (msg->output, num);
+ } else {
+ p11_rpc_buffer_add_byte (msg->output, 1);
+ p11_rpc_buffer_add_byte_array (msg->output, arr, num);
+ }
+
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_ulong_buffer (p11_rpc_message *msg,
+ CK_ULONG count)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fu"));
+ p11_rpc_buffer_add_uint32 (msg->output, count);
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_ulong_array (p11_rpc_message *msg,
+ CK_ULONG_PTR array,
+ CK_ULONG n_array)
+{
+ CK_ULONG i;
+
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "au"));
+
+ /* We send a byte which determines whether there's actual data present or not */
+ p11_rpc_buffer_add_byte (msg->output, array ? 1 : 0);
+ p11_rpc_buffer_add_uint32 (msg->output, n_array);
+
+ /* Now send the data if valid */
+ if (array) {
+ for (i = 0; i < n_array; ++i)
+ p11_rpc_buffer_add_uint64 (msg->output, array[i]);
+ }
+
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_read_version (p11_rpc_message *msg,
+ CK_VERSION *version)
+{
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+ assert (version != NULL);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "v"));
+
+ return p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &version->major) &&
+ p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &version->minor);
+}
+
+bool
+p11_rpc_message_write_version (p11_rpc_message *msg,
+ CK_VERSION *version)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+ assert (version != NULL);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "v"));
+
+ p11_rpc_buffer_add_byte (msg->output, version->major);
+ p11_rpc_buffer_add_byte (msg->output, version->minor);
+
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_read_space_string (p11_rpc_message *msg,
+ CK_UTF8CHAR *buffer,
+ CK_ULONG length)
+{
+ const unsigned char *data;
+ size_t n_data;
+
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+ assert (buffer != NULL);
+ assert (length != 0);
+
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "s"));
+
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &data, &n_data))
+ return false;
+
+ if (n_data != length) {
+ p11_message ("invalid length space padded string received: %d != %d",
+ (int)length, (int)n_data);
+ return false;
+ }
+
+ memcpy (buffer, data, length);
+ return true;
+}
+
+bool
+p11_rpc_message_write_space_string (p11_rpc_message *msg,
+ CK_UTF8CHAR *data,
+ CK_ULONG length)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+ assert (data != NULL);
+ assert (length != 0);
+
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "s"));
+
+ p11_rpc_buffer_add_byte_array (msg->output, data, length);
+ return !p11_buffer_failed (msg->output);
+}
+
+bool
+p11_rpc_message_write_zero_string (p11_rpc_message *msg,
+ CK_UTF8CHAR *string)
+{
+ assert (msg != NULL);
+ assert (msg->output != NULL);
+ assert (string != NULL);
+
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "z"));
+
+ p11_rpc_buffer_add_byte_array (msg->output, string,
+ string ? strlen ((char *)string) : 0);
+ return !p11_buffer_failed (msg->output);
+}
+
+static void *
+log_allocator (void *pointer,
+ size_t size)
+{
+ void *result = realloc (pointer, (size_t)size);
+ return_val_if_fail (!size || result != NULL, NULL);
+ return result;
+}
+
+p11_buffer *
+p11_rpc_buffer_new (size_t reserve)
+{
+ return p11_rpc_buffer_new_full (reserve, log_allocator, free);
+}
+
+p11_buffer *
+p11_rpc_buffer_new_full (size_t reserve,
+ void * (* frealloc) (void *data, size_t size),
+ void (* ffree) (void *data))
+{
+ p11_buffer *buffer;
+
+ buffer = calloc (1, sizeof (p11_buffer));
+ return_val_if_fail (buffer != NULL, NULL);
+
+ p11_buffer_init_full (buffer, NULL, 0, 0, frealloc, ffree);
+ if (!p11_buffer_reset (buffer, reserve))
+ return_val_if_reached (NULL);
+
+ return buffer;
+}
+
+void
+p11_rpc_buffer_free (p11_buffer *buf)
+{
+ if (buf == NULL)
+ return;
+
+ p11_buffer_uninit (buf);
+ free (buf);
+}
+
+void
+p11_rpc_buffer_add_byte (p11_buffer *buf,
+ unsigned char value)
+{
+ p11_buffer_add (buf, &value, 1);
+}
+
+int
+p11_rpc_buffer_get_byte (p11_buffer *buf,
+ size_t *offset,
+ unsigned char *val)
+{
+ unsigned char *ptr;
+ if (buf->len < 1 || *offset > buf->len - 1) {
+ p11_buffer_fail (buf);
+ return 0;
+ }
+ ptr = (unsigned char *)buf->data + *offset;
+ if (val != NULL)
+ *val = *ptr;
+ *offset = *offset + 1;
+ return 1;
+}
+
+void
+p11_rpc_buffer_encode_uint16 (unsigned char* data,
+ uint16_t value)
+{
+ data[0] = (value >> 8) & 0xff;
+ data[1] = (value >> 0) & 0xff;
+}
+
+uint16_t
+p11_rpc_buffer_decode_uint16 (unsigned char* data)
+{
+ uint16_t value = data[0] << 8 | data[1];
+ return value;
+}
+
+void
+p11_rpc_buffer_add_uint16 (p11_buffer *buffer,
+ uint16_t value)
+{
+ size_t offset = buffer->len;
+ if (!p11_buffer_append (buffer, 2))
+ return_if_reached ();
+ p11_rpc_buffer_set_uint16 (buffer, offset, value);
+}
+
+bool
+p11_rpc_buffer_set_uint16 (p11_buffer *buffer,
+ size_t offset,
+ uint16_t value)
+{
+ unsigned char *ptr;
+ if (buffer->len < 2 || offset > buffer->len - 2) {
+ p11_buffer_fail (buffer);
+ return false;
+ }
+ ptr = (unsigned char *)buffer->data + offset;
+ p11_rpc_buffer_encode_uint16 (ptr, value);
+ return true;
+}
+
+bool
+p11_rpc_buffer_get_uint16 (p11_buffer *buf,
+ size_t *offset,
+ uint16_t *value)
+{
+ unsigned char *ptr;
+ if (buf->len < 2 || *offset > buf->len - 2) {
+ p11_buffer_fail (buf);
+ return false;
+ }
+ ptr = (unsigned char*)buf->data + *offset;
+ if (value != NULL)
+ *value = p11_rpc_buffer_decode_uint16 (ptr);
+ *offset = *offset + 2;
+ return true;
+}
+
+void
+p11_rpc_buffer_encode_uint32 (unsigned char* data,
+ uint32_t value)
+{
+ data[0] = (value >> 24) & 0xff;
+ data[1] = (value >> 16) & 0xff;
+ data[2] = (value >> 8) & 0xff;
+ data[3] = (value >> 0) & 0xff;
+}
+
+uint32_t
+p11_rpc_buffer_decode_uint32 (unsigned char* ptr)
+{
+ uint32_t val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+ return val;
+}
+
+void
+p11_rpc_buffer_add_uint32 (p11_buffer *buffer,
+ uint32_t value)
+{
+ size_t offset = buffer->len;
+ if (!p11_buffer_append (buffer, 4))
+ return_val_if_reached ();
+ p11_rpc_buffer_set_uint32 (buffer, offset, value);
+}
+
+bool
+p11_rpc_buffer_set_uint32 (p11_buffer *buffer,
+ size_t offset,
+ uint32_t value)
+{
+ unsigned char *ptr;
+ if (buffer->len < 4 || offset > buffer->len - 4) {
+ p11_buffer_fail (buffer);
+ return false;
+ }
+ ptr = (unsigned char*)buffer->data + offset;
+ p11_rpc_buffer_encode_uint32 (ptr, value);
+ return true;
+}
+
+bool
+p11_rpc_buffer_get_uint32 (p11_buffer *buf,
+ size_t *offset,
+ uint32_t *value)
+{
+ unsigned char *ptr;
+ if (buf->len < 4 || *offset > buf->len - 4) {
+ p11_buffer_fail (buf);
+ return false;
+ }
+ ptr = (unsigned char*)buf->data + *offset;
+ if (value != NULL)
+ *value = p11_rpc_buffer_decode_uint32 (ptr);
+ *offset = *offset + 4;
+ return true;
+}
+
+void
+p11_rpc_buffer_add_uint64 (p11_buffer *buffer,
+ uint64_t value)
+{
+ p11_rpc_buffer_add_uint32 (buffer, ((value >> 32) & 0xffffffff));
+ p11_rpc_buffer_add_uint32 (buffer, (value & 0xffffffff));
+}
+
+bool
+p11_rpc_buffer_get_uint64 (p11_buffer *buf,
+ size_t *offset,
+ uint64_t *value)
+{
+ size_t off = *offset;
+ uint32_t a, b;
+ if (!p11_rpc_buffer_get_uint32 (buf, &off, &a) ||
+ !p11_rpc_buffer_get_uint32 (buf, &off, &b))
+ return false;
+ if (value != NULL)
+ *value = ((uint64_t)a) << 32 | b;
+ *offset = off;
+ return true;
+}
+
+void
+p11_rpc_buffer_add_byte_array (p11_buffer *buffer,
+ const unsigned char *data,
+ size_t length)
+{
+ if (data == NULL) {
+ p11_rpc_buffer_add_uint32 (buffer, 0xffffffff);
+ return;
+ } else if (length >= 0x7fffffff) {
+ p11_buffer_fail (buffer);
+ return;
+ }
+ p11_rpc_buffer_add_uint32 (buffer, length);
+ p11_buffer_add (buffer, data, length);
+}
+
+bool
+p11_rpc_buffer_get_byte_array (p11_buffer *buf,
+ size_t *offset,
+ const unsigned char **data,
+ size_t *length)
+{
+ size_t off = *offset;
+ uint32_t len;
+ if (!p11_rpc_buffer_get_uint32 (buf, &off, &len))
+ return false;
+ if (len == 0xffffffff) {
+ *offset = off;
+ if (data)
+ *data = NULL;
+ if (length)
+ *length = 0;
+ return true;
+ } else if (len >= 0x7fffffff) {
+ p11_buffer_fail (buf);
+ return false;
+ }
+
+ if (buf->len < len || *offset > buf->len - len) {
+ p11_buffer_fail (buf);
+ return false;
+ }
+
+ if (data)
+ *data = (unsigned char *)buf->data + off;
+ if (length)
+ *length = len;
+ *offset = off + len;
+
+ return true;
+}
diff --git a/p11-kit/rpc-message.h b/p11-kit/rpc-message.h
new file mode 100644
index 0000000..f85265b
--- /dev/null
+++ b/p11-kit/rpc-message.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#ifndef _RPC_MESSAGE_H
+#define _RPC_MESSAGE_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "buffer.h"
+#include "pkcs11.h"
+
+/* The calls, must be in sync with array below */
+enum {
+ P11_RPC_CALL_ERROR = 0,
+
+ P11_RPC_CALL_C_Initialize,
+ P11_RPC_CALL_C_Finalize,
+ P11_RPC_CALL_C_GetInfo,
+ P11_RPC_CALL_C_GetSlotList,
+ P11_RPC_CALL_C_GetSlotInfo,
+ P11_RPC_CALL_C_GetTokenInfo,
+ P11_RPC_CALL_C_GetMechanismList,
+ P11_RPC_CALL_C_GetMechanismInfo,
+ P11_RPC_CALL_C_InitToken,
+ P11_RPC_CALL_C_OpenSession,
+ P11_RPC_CALL_C_CloseSession,
+ P11_RPC_CALL_C_CloseAllSessions,
+ P11_RPC_CALL_C_GetSessionInfo,
+ P11_RPC_CALL_C_InitPIN,
+ P11_RPC_CALL_C_SetPIN,
+ P11_RPC_CALL_C_GetOperationState,
+ P11_RPC_CALL_C_SetOperationState,
+ P11_RPC_CALL_C_Login,
+ P11_RPC_CALL_C_Logout,
+ P11_RPC_CALL_C_CreateObject,
+ P11_RPC_CALL_C_CopyObject,
+ P11_RPC_CALL_C_DestroyObject,
+ P11_RPC_CALL_C_GetObjectSize,
+ P11_RPC_CALL_C_GetAttributeValue,
+ P11_RPC_CALL_C_SetAttributeValue,
+ P11_RPC_CALL_C_FindObjectsInit,
+ P11_RPC_CALL_C_FindObjects,
+ P11_RPC_CALL_C_FindObjectsFinal,
+ P11_RPC_CALL_C_EncryptInit,
+ P11_RPC_CALL_C_Encrypt,
+ P11_RPC_CALL_C_EncryptUpdate,
+ P11_RPC_CALL_C_EncryptFinal,
+ P11_RPC_CALL_C_DecryptInit,
+ P11_RPC_CALL_C_Decrypt,
+ P11_RPC_CALL_C_DecryptUpdate,
+ P11_RPC_CALL_C_DecryptFinal,
+ P11_RPC_CALL_C_DigestInit,
+ P11_RPC_CALL_C_Digest,
+ P11_RPC_CALL_C_DigestUpdate,
+ P11_RPC_CALL_C_DigestKey,
+ P11_RPC_CALL_C_DigestFinal,
+ P11_RPC_CALL_C_SignInit,
+ P11_RPC_CALL_C_Sign,
+ P11_RPC_CALL_C_SignUpdate,
+ P11_RPC_CALL_C_SignFinal,
+ P11_RPC_CALL_C_SignRecoverInit,
+ P11_RPC_CALL_C_SignRecover,
+ P11_RPC_CALL_C_VerifyInit,
+ P11_RPC_CALL_C_Verify,
+ P11_RPC_CALL_C_VerifyUpdate,
+ P11_RPC_CALL_C_VerifyFinal,
+ P11_RPC_CALL_C_VerifyRecoverInit,
+ P11_RPC_CALL_C_VerifyRecover,
+ P11_RPC_CALL_C_DigestEncryptUpdate,
+ P11_RPC_CALL_C_DecryptDigestUpdate,
+ P11_RPC_CALL_C_SignEncryptUpdate,
+ P11_RPC_CALL_C_DecryptVerifyUpdate,
+ P11_RPC_CALL_C_GenerateKey,
+ P11_RPC_CALL_C_GenerateKeyPair,
+ P11_RPC_CALL_C_WrapKey,
+ P11_RPC_CALL_C_UnwrapKey,
+ P11_RPC_CALL_C_DeriveKey,
+ P11_RPC_CALL_C_SeedRandom,
+ P11_RPC_CALL_C_GenerateRandom,
+ P11_RPC_CALL_C_WaitForSlotEvent,
+
+ P11_RPC_CALL_MAX
+};
+
+typedef struct {
+ int call_id;
+ const char* name;
+ const char* request;
+ const char* response;
+} p11_rpc_call;
+
+/*
+ * a_ = prefix denotes array of _
+ * A = CK_ATTRIBUTE
+ * f_ = prefix denotes buffer for _
+ * M = CK_MECHANISM
+ * u = CK_ULONG
+ * s = space padded string
+ * v = CK_VERSION
+ * y = CK_BYTE
+ * z = null terminated string
+ */
+
+static const p11_rpc_call p11_rpc_calls[] = {
+ { P11_RPC_CALL_ERROR, "ERROR", NULL, "u" },
+ { P11_RPC_CALL_C_Initialize, "C_Initialize", "ay", "" },
+ { P11_RPC_CALL_C_Finalize, "C_Finalize", "", "" },
+ { P11_RPC_CALL_C_GetInfo, "C_GetInfo", "", "vsusv" },
+ { P11_RPC_CALL_C_GetSlotList, "C_GetSlotList", "yfu", "au" },
+ { P11_RPC_CALL_C_GetSlotInfo, "C_GetSlotInfo", "u", "ssuvv" },
+ { P11_RPC_CALL_C_GetTokenInfo, "C_GetTokenInfo", "u", "ssssuuuuuuuuuuuvvs" },
+ { P11_RPC_CALL_C_GetMechanismList, "C_GetMechanismList", "ufu", "au" },
+ { P11_RPC_CALL_C_GetMechanismInfo, "C_GetMechanismInfo", "uu", "uuu" },
+ { P11_RPC_CALL_C_InitToken, "C_InitToken", "uayz", "" },
+ { P11_RPC_CALL_C_OpenSession, "C_OpenSession", "uu", "u" },
+ { P11_RPC_CALL_C_CloseSession, "C_CloseSession", "u", "" },
+ { P11_RPC_CALL_C_CloseAllSessions, "C_CloseAllSessions", "u", "" },
+ { P11_RPC_CALL_C_GetSessionInfo, "C_GetSessionInfo", "u", "uuuu" },
+ { P11_RPC_CALL_C_InitPIN, "C_InitPIN", "uay", "" },
+ { P11_RPC_CALL_C_SetPIN, "C_SetPIN", "uayay", "" },
+ { P11_RPC_CALL_C_GetOperationState, "C_GetOperationState", "ufy", "ay" },
+ { P11_RPC_CALL_C_SetOperationState, "C_SetOperationState", "uayuu", "" },
+ { P11_RPC_CALL_C_Login, "C_Login", "uuay", "" },
+ { P11_RPC_CALL_C_Logout, "C_Logout", "u", "" },
+ { P11_RPC_CALL_C_CreateObject, "C_CreateObject", "uaA", "u" },
+ { P11_RPC_CALL_C_CopyObject, "C_CopyObject", "uuaA", "u" },
+ { P11_RPC_CALL_C_DestroyObject, "C_DestroyObject", "uu", "" },
+ { P11_RPC_CALL_C_GetObjectSize, "C_GetObjectSize", "uu", "u" },
+ { P11_RPC_CALL_C_GetAttributeValue, "C_GetAttributeValue", "uufA", "aAu" },
+ { P11_RPC_CALL_C_SetAttributeValue, "C_SetAttributeValue", "uuaA", "" },
+ { P11_RPC_CALL_C_FindObjectsInit, "C_FindObjectsInit", "uaA", "" },
+ { P11_RPC_CALL_C_FindObjects, "C_FindObjects", "ufu", "au" },
+ { P11_RPC_CALL_C_FindObjectsFinal, "C_FindObjectsFinal", "u", "" },
+ { P11_RPC_CALL_C_EncryptInit, "C_EncryptInit", "uMu", "" },
+ { P11_RPC_CALL_C_Encrypt, "C_Encrypt", "uayfy", "ay" },
+ { P11_RPC_CALL_C_EncryptUpdate, "C_EncryptUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_EncryptFinal, "C_EncryptFinal", "ufy", "ay" },
+ { P11_RPC_CALL_C_DecryptInit, "C_DecryptInit", "uMu", "" },
+ { P11_RPC_CALL_C_Decrypt, "C_Decrypt", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DecryptUpdate, "C_DecryptUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DecryptFinal, "C_DecryptFinal", "ufy", "ay" },
+ { P11_RPC_CALL_C_DigestInit, "C_DigestInit", "uM", "" },
+ { P11_RPC_CALL_C_Digest, "C_Digest", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DigestUpdate, "C_DigestUpdate", "uay", "" },
+ { P11_RPC_CALL_C_DigestKey, "C_DigestKey", "uu", "" },
+ { P11_RPC_CALL_C_DigestFinal, "C_DigestFinal", "ufy", "ay" },
+ { P11_RPC_CALL_C_SignInit, "C_SignInit", "uMu", "" },
+ { P11_RPC_CALL_C_Sign, "C_Sign", "uayfy", "ay" },
+ { P11_RPC_CALL_C_SignUpdate, "C_SignUpdate", "uay", "" },
+ { P11_RPC_CALL_C_SignFinal, "C_SignFinal", "ufy", "ay" },
+ { P11_RPC_CALL_C_SignRecoverInit, "C_SignRecoverInit", "uMu", "" },
+ { P11_RPC_CALL_C_SignRecover, "C_SignRecover", "uayfy", "ay" },
+ { P11_RPC_CALL_C_VerifyInit, "C_VerifyInit", "uMu", "" },
+ { P11_RPC_CALL_C_Verify, "C_Verify", "uayay", "" },
+ { P11_RPC_CALL_C_VerifyUpdate, "C_VerifyUpdate", "uay", "" },
+ { P11_RPC_CALL_C_VerifyFinal, "C_VerifyFinal", "uay", "" },
+ { P11_RPC_CALL_C_VerifyRecoverInit, "C_VerifyRecoverInit", "uMu", "" },
+ { P11_RPC_CALL_C_VerifyRecover, "C_VerifyRecover", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DigestEncryptUpdate, "C_DigestEncryptUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DecryptDigestUpdate, "C_DecryptDigestUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_SignEncryptUpdate, "C_SignEncryptUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_DecryptVerifyUpdate, "C_DecryptVerifyUpdate", "uayfy", "ay" },
+ { P11_RPC_CALL_C_GenerateKey, "C_GenerateKey", "uMaA", "u" },
+ { P11_RPC_CALL_C_GenerateKeyPair, "C_GenerateKeyPair", "uMaAaA", "uu" },
+ { P11_RPC_CALL_C_WrapKey, "C_WrapKey", "uMuufy", "ay" },
+ { P11_RPC_CALL_C_UnwrapKey, "C_UnwrapKey", "uMuayaA", "u" },
+ { P11_RPC_CALL_C_DeriveKey, "C_DeriveKey", "uMuaA", "u" },
+ { P11_RPC_CALL_C_SeedRandom, "C_SeedRandom", "uay", "" },
+ { P11_RPC_CALL_C_GenerateRandom, "C_GenerateRandom", "ufy", "ay" },
+ { P11_RPC_CALL_C_WaitForSlotEvent, "C_WaitForSlotEvent", "u", "u" },
+};
+
+#ifdef _DEBUG
+#define P11_RPC_CHECK_CALLS() \
+ { int i; for (i = 0; i < P11_RPC_CALL_MAX; ++i) assert (p11_rpc_calls[i].call_id == i); }
+#endif
+
+#define P11_RPC_HANDSHAKE \
+ ((unsigned char *)"PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-1")
+#define P11_RPC_HANDSHAKE_LEN \
+ (strlen ((char *)P11_RPC_HANDSHAKE))
+
+typedef enum _p11_rpc_message_type {
+ P11_RPC_REQUEST = 1,
+ P11_RPC_RESPONSE
+} p11_rpc_message_type;
+
+typedef struct {
+ int call_id;
+ p11_rpc_message_type call_type;
+ const char *signature;
+ p11_buffer *input;
+ p11_buffer *output;
+ size_t parsed;
+ const char *sigverify;
+ void *extra;
+} p11_rpc_message;
+
+void p11_rpc_message_init (p11_rpc_message *msg,
+ p11_buffer *input,
+ p11_buffer *output);
+
+void p11_rpc_message_clear (p11_rpc_message *msg);
+
+#define p11_rpc_message_is_verified(msg) (!(msg)->sigverify || (msg)->sigverify[0] == 0)
+
+void * p11_rpc_message_alloc_extra (p11_rpc_message *msg,
+ size_t length);
+
+bool p11_rpc_message_prep (p11_rpc_message *msg,
+ int call_id,
+ p11_rpc_message_type type);
+
+bool p11_rpc_message_parse (p11_rpc_message *msg,
+ p11_rpc_message_type type);
+
+bool p11_rpc_message_verify_part (p11_rpc_message *msg,
+ const char* part);
+
+bool p11_rpc_message_write_byte (p11_rpc_message *msg,
+ CK_BYTE val);
+
+bool p11_rpc_message_write_ulong (p11_rpc_message *msg,
+ CK_ULONG val);
+
+bool p11_rpc_message_write_zero_string (p11_rpc_message *msg,
+ CK_UTF8CHAR *string);
+
+bool p11_rpc_message_write_space_string (p11_rpc_message *msg,
+ CK_UTF8CHAR *buffer,
+ CK_ULONG length);
+
+bool p11_rpc_message_write_byte_buffer (p11_rpc_message *msg,
+ CK_ULONG count);
+
+bool p11_rpc_message_write_byte_array (p11_rpc_message *msg,
+ CK_BYTE_PTR arr,
+ CK_ULONG num);
+
+bool p11_rpc_message_write_ulong_buffer (p11_rpc_message *msg,
+ CK_ULONG count);
+
+bool p11_rpc_message_write_ulong_array (p11_rpc_message *msg,
+ CK_ULONG_PTR arr,
+ CK_ULONG num);
+
+bool p11_rpc_message_write_attribute_buffer (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num);
+
+bool p11_rpc_message_write_attribute_array (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num);
+
+bool p11_rpc_message_write_version (p11_rpc_message *msg,
+ CK_VERSION* version);
+
+bool p11_rpc_message_read_byte (p11_rpc_message *msg,
+ CK_BYTE* val);
+
+bool p11_rpc_message_read_ulong (p11_rpc_message *msg,
+ CK_ULONG* val);
+
+bool p11_rpc_message_read_space_string (p11_rpc_message *msg,
+ CK_UTF8CHAR* buffer,
+ CK_ULONG length);
+
+bool p11_rpc_message_read_version (p11_rpc_message *msg,
+ CK_VERSION* version);
+
+p11_buffer * p11_rpc_buffer_new (size_t reserve);
+
+p11_buffer * p11_rpc_buffer_new_full (size_t reserve,
+ void * (* frealloc) (void *data, size_t size),
+ void (* ffree) (void *data));
+
+void p11_rpc_buffer_free (p11_buffer *buf);
+
+void p11_rpc_buffer_add_byte (p11_buffer *buf,
+ unsigned char value);
+
+int p11_rpc_buffer_get_byte (p11_buffer *buf,
+ size_t *offset,
+ unsigned char *val);
+
+void p11_rpc_buffer_encode_uint32 (unsigned char *data,
+ uint32_t value);
+
+uint32_t p11_rpc_buffer_decode_uint32 (unsigned char *data);
+
+void p11_rpc_buffer_add_uint32 (p11_buffer *buffer,
+ uint32_t value);
+
+bool p11_rpc_buffer_set_uint32 (p11_buffer *buffer,
+ size_t offset,
+ uint32_t value);
+
+bool p11_rpc_buffer_get_uint32 (p11_buffer *buf,
+ size_t *offset,
+ uint32_t *value);
+
+void p11_rpc_buffer_encode_uint16 (unsigned char *data,
+ uint16_t value);
+
+uint16_t p11_rpc_buffer_decode_uint16 (unsigned char *data);
+
+void p11_rpc_buffer_add_uint16 (p11_buffer *buffer,
+ uint16_t val);
+
+bool p11_rpc_buffer_set_uint16 (p11_buffer *buffer,
+ size_t offset,
+ uint16_t val);
+
+bool p11_rpc_buffer_get_uint16 (p11_buffer *buf,
+ size_t *offset,
+ uint16_t *val);
+
+void p11_rpc_buffer_add_byte_array (p11_buffer *buffer,
+ const unsigned char *val,
+ size_t len);
+
+bool p11_rpc_buffer_get_byte_array (p11_buffer *buf,
+ size_t *offset,
+ const unsigned char **val,
+ size_t *vlen);
+
+void p11_rpc_buffer_add_uint64 (p11_buffer *buffer,
+ uint64_t val);
+
+bool p11_rpc_buffer_get_uint64 (p11_buffer *buf,
+ size_t *offset,
+ uint64_t *val);
+
+#endif /* _RPC_MESSAGE_H */
diff --git a/p11-kit/rpc-server.c b/p11-kit/rpc-server.c
new file mode 100644
index 0000000..a468e7a
--- /dev/null
+++ b/p11-kit/rpc-server.c
@@ -0,0 +1,1901 @@
+/*
+ * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#include "config.h"
+
+#define P11_DEBUG_FLAG P11_DEBUG_RPC
+#include "debug.h"
+#include "pkcs11.h"
+#include "library.h"
+#include "private.h"
+#include "message.h"
+#include "rpc.h"
+#include "rpc-message.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* The error returned on protocol failures */
+#define PARSE_ERROR CKR_DEVICE_ERROR
+#define PREP_ERROR CKR_DEVICE_MEMORY
+
+static CK_RV
+proto_read_byte_buffer (p11_rpc_message *msg,
+ CK_BYTE_PTR *buffer,
+ CK_ULONG *n_buffer)
+{
+ uint32_t length;
+
+ assert (msg != NULL);
+ assert (buffer != NULL);
+ assert (n_buffer != NULL);
+ assert (msg->input != NULL);
+
+ /* Check that we're supposed to be reading this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fy"));
+
+ /* The number of ulongs there's room for on the other end */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &length))
+ return PARSE_ERROR;
+
+ *n_buffer = length;
+ *buffer = NULL;
+
+ /* If set to zero, then they just want the length */
+ if (length == 0)
+ return CKR_OK;
+
+ *buffer = p11_rpc_message_alloc_extra (msg, length * sizeof (CK_BYTE));
+ if (*buffer == NULL)
+ return CKR_DEVICE_MEMORY;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_byte_array (p11_rpc_message *msg,
+ CK_BYTE_PTR *array,
+ CK_ULONG *n_array)
+{
+ const unsigned char *data;
+ unsigned char valid;
+ size_t n_data;
+
+ assert (msg != NULL);
+ assert (msg->input != NULL);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "ay"));
+
+ /* Read out the byte which says whether data is present or not */
+ if (!p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ if (!valid) {
+ *array = NULL;
+ *n_array = 0;
+ return CKR_OK;
+ }
+
+ /* Point our arguments into the buffer */
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+
+ *array = (CK_BYTE_PTR)data;
+ *n_array = n_data;
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_byte_array (p11_rpc_message *msg,
+ CK_BYTE_PTR array,
+ CK_ULONG len,
+ CK_RV ret)
+{
+ assert (msg != NULL);
+
+ /*
+ * When returning an byte array, in many cases we need to pass
+ * an invalid array along with a length, which signifies CKR_BUFFER_TOO_SMALL.
+ */
+
+ switch (ret) {
+ case CKR_BUFFER_TOO_SMALL:
+ array = NULL;
+ /* fall through */
+ case CKR_OK:
+ break;
+
+ /* Pass all other errors straight through */
+ default:
+ return ret;
+ };
+
+ if (!p11_rpc_message_write_byte_array (msg, array, len))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_ulong_buffer (p11_rpc_message *msg,
+ CK_ULONG_PTR *buffer,
+ CK_ULONG *n_buffer)
+{
+ uint32_t length;
+
+ assert (msg != NULL);
+ assert (buffer != NULL);
+ assert (n_buffer != NULL);
+ assert (msg->input != NULL);
+
+ /* Check that we're supposed to be reading this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fu"));
+
+ /* The number of ulongs there's room for on the other end */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &length))
+ return PARSE_ERROR;
+
+ *n_buffer = length;
+ *buffer = NULL;
+
+ /* If set to zero, then they just want the length */
+ if (length == 0)
+ return CKR_OK;
+
+ *buffer = p11_rpc_message_alloc_extra (msg, length * sizeof (CK_ULONG));
+ if (!*buffer)
+ return CKR_DEVICE_MEMORY;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_ulong_array (p11_rpc_message *msg,
+ CK_ULONG_PTR array,
+ CK_ULONG len,
+ CK_RV ret)
+{
+ assert (msg != NULL);
+
+ /*
+ * When returning an ulong array, in many cases we need to pass
+ * an invalid array along with a length, which signifies CKR_BUFFER_TOO_SMALL.
+ */
+
+ switch (ret) {
+ case CKR_BUFFER_TOO_SMALL:
+ array = NULL;
+ /* fall through */
+ case CKR_OK:
+ break;
+
+ /* Pass all other errors straight through */
+ default:
+ return ret;
+ };
+
+ if (!p11_rpc_message_write_ulong_array (msg, array, len))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_attribute_buffer (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR *result,
+ CK_ULONG *n_result)
+{
+ CK_ATTRIBUTE_PTR attrs;
+ uint32_t n_attrs, i;
+ uint32_t value;
+
+ assert (msg != NULL);
+ assert (result != NULL);
+ assert (n_result != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "fA"));
+
+ /* Read the number of attributes */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &n_attrs))
+ return PARSE_ERROR;
+
+ /* Allocate memory for the attribute structures */
+ attrs = p11_rpc_message_alloc_extra (msg, n_attrs * sizeof (CK_ATTRIBUTE));
+ if (attrs == NULL)
+ return CKR_DEVICE_MEMORY;
+
+ /* Now go through and fill in each one */
+ for (i = 0; i < n_attrs; ++i) {
+
+ /* The attribute type */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ attrs[i].type = value;
+
+ /* The number of bytes to allocate */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ if (value == 0) {
+ attrs[i].pValue = NULL;
+ attrs[i].ulValueLen = 0;
+ } else {
+ attrs[i].pValue = p11_rpc_message_alloc_extra (msg, value);
+ if (!attrs[i].pValue)
+ return CKR_DEVICE_MEMORY;
+ attrs[i].ulValueLen = value;
+ }
+ }
+
+ *result = attrs;
+ *n_result = n_attrs;
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_attribute_array (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR *result,
+ CK_ULONG *n_result)
+{
+ CK_ATTRIBUTE_PTR attrs;
+ const unsigned char *data;
+ unsigned char valid;
+ uint32_t n_attrs, i;
+ uint32_t value;
+ size_t n_data;
+
+ assert (msg != NULL);
+ assert (result != NULL);
+ assert (n_result != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "aA"));
+
+ /* Read the number of attributes */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &n_attrs))
+ return PARSE_ERROR;
+
+ /* Allocate memory for the attribute structures */
+ attrs = p11_rpc_message_alloc_extra (msg, n_attrs * sizeof (CK_ATTRIBUTE));
+ if (attrs == NULL)
+ return CKR_DEVICE_MEMORY;
+
+ /* Now go through and fill in each one */
+ for (i = 0; i < n_attrs; ++i) {
+
+ /* The attribute type */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ attrs[i].type = value;
+
+ /* Whether this one is valid or not */
+ if (!p11_rpc_buffer_get_byte (msg->input, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ if (valid) {
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value))
+ return PARSE_ERROR;
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+
+ if (data != NULL && n_data != value) {
+ p11_message ("attribute length and data do not match");
+ return PARSE_ERROR;
+ }
+
+ attrs[i].pValue = (CK_VOID_PTR)data;
+ attrs[i].ulValueLen = value;
+ } else {
+ attrs[i].pValue = NULL;
+ attrs[i].ulValueLen = -1;
+ }
+ }
+
+ *result = attrs;
+ *n_result = n_attrs;
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_attribute_array (p11_rpc_message *msg,
+ CK_ATTRIBUTE_PTR array,
+ CK_ULONG len,
+ CK_RV ret)
+{
+ assert (msg != NULL);
+
+ /*
+ * When returning an attribute array, certain errors aren't
+ * actually real errors, these are passed through to the other
+ * side along with the attribute array.
+ */
+
+ switch (ret) {
+ case CKR_ATTRIBUTE_SENSITIVE:
+ case CKR_ATTRIBUTE_TYPE_INVALID:
+ case CKR_BUFFER_TOO_SMALL:
+ case CKR_OK:
+ break;
+
+ /* Pass all other errors straight through */
+ default:
+ return ret;
+ };
+
+ if (!p11_rpc_message_write_attribute_array (msg, array, len) ||
+ !p11_rpc_message_write_ulong (msg, ret))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_null_string (p11_rpc_message *msg,
+ CK_UTF8CHAR_PTR *val)
+{
+ const unsigned char *data;
+ size_t n_data;
+
+ assert (msg != NULL);
+ assert (val != NULL);
+ assert (msg->input != NULL);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "z"));
+
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+
+ /* Allocate a block of memory for it */
+ *val = p11_rpc_message_alloc_extra (msg, n_data + 1);
+ if (*val == NULL)
+ return CKR_DEVICE_MEMORY;
+
+ memcpy (*val, data, n_data);
+ (*val)[n_data] = 0;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_mechanism (p11_rpc_message *msg,
+ CK_MECHANISM_PTR mech)
+{
+ const unsigned char *data;
+ uint32_t value;
+ size_t n_data;
+
+ assert (msg != NULL);
+ assert (mech != NULL);
+ assert (msg->input != NULL);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || p11_rpc_message_verify_part (msg, "M"));
+
+ /* The mechanism type */
+ if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ /* The mechanism data */
+ if (!p11_rpc_buffer_get_byte_array (msg->input, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+
+ mech->mechanism = value;
+ mech->pParameter = (CK_VOID_PTR)data;
+ mech->ulParameterLen = n_data;
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_info (p11_rpc_message *msg,
+ CK_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_write_version (msg, &info->cryptokiVersion) ||
+ !p11_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_write_ulong (msg, info->flags) ||
+ !p11_rpc_message_write_space_string (msg, info->libraryDescription, 32) ||
+ !p11_rpc_message_write_version (msg, &info->libraryVersion))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_slot_info (p11_rpc_message *msg,
+ CK_SLOT_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_write_space_string (msg, info->slotDescription, 64) ||
+ !p11_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_write_ulong (msg, info->flags) ||
+ !p11_rpc_message_write_version (msg, &info->hardwareVersion) ||
+ !p11_rpc_message_write_version (msg, &info->firmwareVersion))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_token_info (p11_rpc_message *msg,
+ CK_TOKEN_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_write_space_string (msg, info->label, 32) ||
+ !p11_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !p11_rpc_message_write_space_string (msg, info->model, 16) ||
+ !p11_rpc_message_write_space_string (msg, info->serialNumber, 16) ||
+ !p11_rpc_message_write_ulong (msg, info->flags) ||
+ !p11_rpc_message_write_ulong (msg, info->ulMaxSessionCount) ||
+ !p11_rpc_message_write_ulong (msg, info->ulSessionCount) ||
+ !p11_rpc_message_write_ulong (msg, info->ulMaxRwSessionCount) ||
+ !p11_rpc_message_write_ulong (msg, info->ulRwSessionCount) ||
+ !p11_rpc_message_write_ulong (msg, info->ulMaxPinLen) ||
+ !p11_rpc_message_write_ulong (msg, info->ulMinPinLen) ||
+ !p11_rpc_message_write_ulong (msg, info->ulTotalPublicMemory) ||
+ !p11_rpc_message_write_ulong (msg, info->ulFreePublicMemory) ||
+ !p11_rpc_message_write_ulong (msg, info->ulTotalPrivateMemory) ||
+ !p11_rpc_message_write_ulong (msg, info->ulFreePrivateMemory) ||
+ !p11_rpc_message_write_version (msg, &info->hardwareVersion) ||
+ !p11_rpc_message_write_version (msg, &info->firmwareVersion) ||
+ !p11_rpc_message_write_space_string (msg, info->utcTime, 16))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_mechanism_info (p11_rpc_message *msg,
+ CK_MECHANISM_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_write_ulong (msg, info->ulMinKeySize) ||
+ !p11_rpc_message_write_ulong (msg, info->ulMaxKeySize) ||
+ !p11_rpc_message_write_ulong (msg, info->flags))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_session_info (p11_rpc_message *msg,
+ CK_SESSION_INFO_PTR info)
+{
+ assert (msg != NULL);
+ assert (info != NULL);
+
+ if (!p11_rpc_message_write_ulong (msg, info->slotID) ||
+ !p11_rpc_message_write_ulong (msg, info->state) ||
+ !p11_rpc_message_write_ulong (msg, info->flags) ||
+ !p11_rpc_message_write_ulong (msg, info->ulDeviceError))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+call_ready (p11_rpc_message *msg)
+{
+ assert (msg->output);
+
+ /*
+ * Called right before invoking the actual PKCS#11 function
+ * Reading out of data is complete, get ready to write return values.
+ */
+
+ if (p11_buffer_failed (msg->output)) {
+ p11_message ("invalid request from module, probably too short"); \
+ return PARSE_ERROR;
+ }
+
+ assert (p11_rpc_message_is_verified (msg));
+
+ /* All done parsing input */
+ msg->input = NULL;
+
+ if (!p11_rpc_message_prep (msg, msg->call_id, P11_RPC_RESPONSE)) {
+ p11_message ("couldn't initialize rpc response");
+ return CKR_DEVICE_MEMORY;
+ }
+
+ return CKR_OK;
+}
+
+/* -------------------------------------------------------------------
+ * CALL MACROS
+ */
+
+#define BEGIN_CALL(call_id) \
+ p11_debug (#call_id ": enter"); \
+ assert (msg != NULL); \
+ assert (self != NULL); \
+ { \
+ CK_X_##call_id _func = self->C_##call_id; \
+ CK_RV _ret = CKR_OK; \
+ if (!_func) { _ret = CKR_GENERAL_ERROR; goto _cleanup; }
+
+#define PROCESS_CALL(args) \
+ _ret = call_ready (msg); \
+ if (_ret != CKR_OK) { goto _cleanup; } \
+ _ret = _func args
+
+#define END_CALL \
+ _cleanup: \
+ p11_debug ("ret: %d", (int)_ret); \
+ return _ret; \
+ }
+
+#define IN_BYTE(val) \
+ if (!p11_rpc_message_read_byte (msg, &val)) \
+ { _ret = PARSE_ERROR; goto _cleanup; }
+
+#define IN_ULONG(val) \
+ if (!p11_rpc_message_read_ulong (msg, &val)) \
+ { _ret = PARSE_ERROR; goto _cleanup; }
+
+#define IN_STRING(val) \
+ _ret = proto_read_null_string (msg, &val); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_BYTE_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_byte_buffer (msg, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_BYTE_ARRAY(buffer, buffer_len) \
+ _ret = proto_read_byte_array (msg, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ULONG_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_ulong_buffer (msg, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ATTRIBUTE_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_attribute_buffer (msg, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ATTRIBUTE_ARRAY(attrs, n_attrs) \
+ _ret = proto_read_attribute_array (msg, &attrs, &n_attrs); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_MECHANISM(mech) \
+ _ret = proto_read_mechanism (msg, &mech); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+
+#define OUT_ULONG(val) \
+ if (_ret == CKR_OK && !p11_rpc_message_write_ulong (msg, val)) \
+ _ret = PREP_ERROR;
+
+#define OUT_BYTE_ARRAY(array, len) \
+ /* Note how we filter return codes */ \
+ _ret = proto_write_byte_array (msg, array, len, _ret);
+
+#define OUT_ULONG_ARRAY(array, len) \
+ /* Note how we filter return codes */ \
+ _ret = proto_write_ulong_array (msg, array, len, _ret);
+
+#define OUT_ATTRIBUTE_ARRAY(array, len) \
+ /* Note how we filter return codes */ \
+ _ret = proto_write_attribute_array (msg, array, len, _ret);
+
+#define OUT_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_info (msg, &val);
+
+#define OUT_SLOT_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_slot_info (msg, &val);
+
+#define OUT_TOKEN_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_token_info (msg, &val);
+
+#define OUT_MECHANISM_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_mechanism_info (msg, &val);
+
+#define OUT_SESSION_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_session_info (msg, &val);
+
+/* ---------------------------------------------------------------------------
+ * DISPATCH SPECIFIC CALLS
+ */
+
+static CK_RV
+rpc_C_Initialize (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_X_Initialize func;
+ CK_C_INITIALIZE_ARGS init_args;
+ CK_BYTE_PTR handshake;
+ CK_ULONG n_handshake;
+ CK_RV ret = CKR_OK;
+
+ p11_debug ("C_Initialize: enter");
+
+ assert (msg != NULL);
+ assert (self != NULL);
+
+ ret = proto_read_byte_array (msg, &handshake, &n_handshake);
+ if (ret == CKR_OK) {
+
+ /* Check to make sure the header matches */
+ if (n_handshake != P11_RPC_HANDSHAKE_LEN ||
+ memcmp (handshake, P11_RPC_HANDSHAKE, n_handshake) != 0) {
+ p11_message ("invalid handshake received from connecting module");
+ ret = CKR_GENERAL_ERROR;
+ }
+
+ assert (p11_rpc_message_is_verified (msg));
+ }
+
+ memset (&init_args, 0, sizeof (init_args));
+ init_args.flags = CKF_OS_LOCKING_OK;
+
+ func = self->C_Initialize;
+ assert (func != NULL);
+ ret = (func) (self, &init_args);
+
+ /* Empty response */
+ if (ret == CKR_OK)
+ ret = call_ready (msg);
+
+ p11_debug ("ret: %d", (int)ret);
+ return ret;
+}
+
+static CK_RV
+rpc_C_Finalize (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ BEGIN_CALL (Finalize);
+ PROCESS_CALL ((self, NULL));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetInfo (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_INFO info;
+
+ BEGIN_CALL (GetInfo);
+ PROCESS_CALL ((self, &info));
+ OUT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotList (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_BBOOL token_present;
+ CK_SLOT_ID_PTR slot_list;
+ CK_ULONG count;
+
+ BEGIN_CALL (GetSlotList);
+ IN_BYTE (token_present);
+ IN_ULONG_BUFFER (slot_list, count);
+ PROCESS_CALL ((self, token_present, slot_list, &count));
+ OUT_ULONG_ARRAY (slot_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotInfo (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_SLOT_INFO info;
+
+ BEGIN_CALL (GetSlotInfo);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((self, slot_id, &info));
+ OUT_SLOT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetTokenInfo (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_TOKEN_INFO info;
+
+ BEGIN_CALL (GetTokenInfo);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((self, slot_id, &info));
+ OUT_TOKEN_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismList (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_MECHANISM_TYPE_PTR mechanism_list;
+ CK_ULONG count;
+
+ BEGIN_CALL (GetMechanismList);
+ IN_ULONG (slot_id);
+ IN_ULONG_BUFFER (mechanism_list, count);
+ PROCESS_CALL ((self, slot_id, mechanism_list, &count));
+ OUT_ULONG_ARRAY (mechanism_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismInfo (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_MECHANISM_TYPE type;
+ CK_MECHANISM_INFO info;
+
+ BEGIN_CALL (GetMechanismInfo);
+ IN_ULONG (slot_id);
+ IN_ULONG (type);
+ PROCESS_CALL ((self, slot_id, type, &info));
+ OUT_MECHANISM_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitToken (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+ CK_UTF8CHAR_PTR label;
+
+ BEGIN_CALL (InitToken);
+ IN_ULONG (slot_id);
+ IN_BYTE_ARRAY (pin, pin_len);
+ IN_STRING (label);
+ PROCESS_CALL ((self, slot_id, pin, pin_len, label));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WaitForSlotEvent (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_FLAGS flags;
+ CK_SLOT_ID slot_id;
+
+ BEGIN_CALL (WaitForSlotEvent);
+ IN_ULONG (flags);
+ PROCESS_CALL ((self, flags, &slot_id, NULL));
+ OUT_ULONG (slot_id);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_OpenSession (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+ CK_FLAGS flags;
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (OpenSession);
+ IN_ULONG (slot_id);
+ IN_ULONG (flags);
+ PROCESS_CALL ((self, slot_id, flags, NULL, NULL, &session));
+ OUT_ULONG (session);
+ END_CALL;
+}
+
+
+static CK_RV
+rpc_C_CloseSession (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (CloseSession);
+ IN_ULONG (session);
+ PROCESS_CALL ((self, session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseAllSessions (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SLOT_ID slot_id;
+
+ /* Slot id becomes appartment so lower layers can tell clients apart. */
+
+ BEGIN_CALL (CloseAllSessions);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((self, slot_id));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSessionInfo (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_SESSION_INFO info;
+
+ BEGIN_CALL (GetSessionInfo);
+ IN_ULONG (session);
+ PROCESS_CALL ((self, session, &info));
+ OUT_SESSION_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitPIN (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+
+ BEGIN_CALL (InitPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL ((self, session, pin, pin_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetPIN (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_UTF8CHAR_PTR old_pin;
+ CK_ULONG old_len;
+ CK_UTF8CHAR_PTR new_pin;
+ CK_ULONG new_len;
+
+ BEGIN_CALL (SetPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (old_pin, old_len);
+ IN_BYTE_ARRAY (new_pin, new_len);
+ PROCESS_CALL ((self, session, old_pin, old_len, new_pin, new_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetOperationState (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR operation_state;
+ CK_ULONG operation_state_len;
+
+ BEGIN_CALL (GetOperationState);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (operation_state, operation_state_len);
+ PROCESS_CALL ((self, session, operation_state, &operation_state_len));
+ OUT_BYTE_ARRAY (operation_state, operation_state_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetOperationState (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR operation_state;
+ CK_ULONG operation_state_len;
+ CK_OBJECT_HANDLE encryption_key;
+ CK_OBJECT_HANDLE authentication_key;
+
+ BEGIN_CALL (SetOperationState);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (operation_state, operation_state_len);
+ IN_ULONG (encryption_key);
+ IN_ULONG (authentication_key);
+ PROCESS_CALL ((self, session, operation_state, operation_state_len, encryption_key, authentication_key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Login (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_USER_TYPE user_type;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+
+ BEGIN_CALL (Login);
+ IN_ULONG (session);
+ IN_ULONG (user_type);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL ((self, session, user_type, pin, pin_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Logout (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (Logout);
+ IN_ULONG (session);
+ PROCESS_CALL ((self, session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CreateObject (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE new_object;
+
+ BEGIN_CALL (CreateObject);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((self, session, template, count, &new_object));
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CopyObject (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE new_object;
+
+ BEGIN_CALL (CopyObject);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((self, session, object, template, count, &new_object));
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DestroyObject (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+
+ BEGIN_CALL (DestroyObject);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL ((self, session, object));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetObjectSize (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG size;
+
+ BEGIN_CALL (GetObjectSize);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL ((self, session, object, &size));
+ OUT_ULONG (size);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetAttributeValue (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (GetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_BUFFER (template, count);
+ PROCESS_CALL ((self, session, object, template, count));
+ OUT_ATTRIBUTE_ARRAY (template, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetAttributeValue (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (SetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((self, session, object, template, count));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (FindObjectsInit);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((self, session, template, count));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjects (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE_PTR objects;
+ CK_ULONG max_object_count;
+ CK_ULONG object_count;
+
+ BEGIN_CALL (FindObjects);
+ IN_ULONG (session);
+ IN_ULONG_BUFFER (objects, max_object_count);
+ PROCESS_CALL ((self, session, objects, max_object_count, &object_count));
+ OUT_ULONG_ARRAY (objects, object_count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (FindObjectsFinal);
+ IN_ULONG (session);
+ PROCESS_CALL ((self, session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (EncryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+
+}
+
+static CK_RV
+rpc_C_Encrypt (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR encrypted_data;
+ CK_ULONG encrypted_data_len;
+
+ BEGIN_CALL (Encrypt);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (encrypted_data, encrypted_data_len);
+ PROCESS_CALL ((self, session, data, data_len, encrypted_data, &encrypted_data_len));
+ OUT_BYTE_ARRAY (encrypted_data, encrypted_data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (EncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((self, session, part, part_len, encrypted_part, &encrypted_part_len));
+ OUT_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR last_encrypted_part;
+ CK_ULONG last_encrypted_part_len;
+
+ BEGIN_CALL (EncryptFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_encrypted_part, last_encrypted_part_len);
+ PROCESS_CALL ((self, session, last_encrypted_part, &last_encrypted_part_len));
+ OUT_BYTE_ARRAY (last_encrypted_part, last_encrypted_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (DecryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Decrypt (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_data;
+ CK_ULONG encrypted_data_len;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+
+ BEGIN_CALL (Decrypt);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_data, encrypted_data_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL ((self, session, encrypted_data, encrypted_data_len, data, &data_len));
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (DecryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((self, session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR last_part;
+ CK_ULONG last_part_len;
+
+ BEGIN_CALL (DecryptFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_part, last_part_len);
+ PROCESS_CALL ((self, session, last_part, &last_part_len));
+ OUT_BYTE_ARRAY (last_part, last_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+
+ BEGIN_CALL (DigestInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ PROCESS_CALL ((self, session, &mechanism));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Digest (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR digest;
+ CK_ULONG digest_len;
+
+ BEGIN_CALL (Digest);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL ((self, session, data, data_len, digest, &digest_len));
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (DigestUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((self, session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestKey (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (DigestKey);
+ IN_ULONG (session);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR digest;
+ CK_ULONG digest_len;
+
+ BEGIN_CALL (DigestFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL ((self, session, digest, &digest_len));
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (SignInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Sign (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (Sign);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((self, session, part, part_len, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+
+}
+
+static CK_RV
+rpc_C_SignUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (SignUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((self, session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (SignFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((self, session, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecoverInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (SignRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecover (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (SignRecover);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((self, session, data, data_len, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (VerifyInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Verify (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (Verify);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL ((self, session, data, data_len, signature, signature_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (VerifyUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((self, session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyFinal (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (VerifyFinal);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL ((self, session, signature, signature_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecoverInit (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (VerifyRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((self, session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecover (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+
+ BEGIN_CALL (VerifyRecover);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL ((self, session, signature, signature_len, data, &data_len));
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestEncryptUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (DigestEncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((self, session, part, part_len, encrypted_part, &encrypted_part_len));
+ OUT_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptDigestUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (DecryptDigestUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((self, session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignEncryptUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (SignEncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((self, session, part, part_len, encrypted_part, &encrypted_part_len));
+ OUT_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptVerifyUpdate (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (DecryptVerifyUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((self, session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateKey (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (GenerateKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((self, session, &mechanism, template, count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateKeyPair (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_ATTRIBUTE_PTR public_key_template;
+ CK_ULONG public_key_attribute_count;
+ CK_ATTRIBUTE_PTR private_key_template;
+ CK_ULONG private_key_attribute_count;
+ CK_OBJECT_HANDLE public_key;
+ CK_OBJECT_HANDLE private_key;
+
+ BEGIN_CALL (GenerateKeyPair);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ATTRIBUTE_ARRAY (public_key_template, public_key_attribute_count);
+ IN_ATTRIBUTE_ARRAY (private_key_template, private_key_attribute_count);
+ PROCESS_CALL ((self, session, &mechanism, public_key_template, public_key_attribute_count, private_key_template, private_key_attribute_count, &public_key, &private_key));
+ OUT_ULONG (public_key);
+ OUT_ULONG (private_key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WrapKey (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE wrapping_key;
+ CK_OBJECT_HANDLE key;
+ CK_BYTE_PTR wrapped_key;
+ CK_ULONG wrapped_key_len;
+
+ BEGIN_CALL (WrapKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (wrapping_key);
+ IN_ULONG (key);
+ IN_BYTE_BUFFER (wrapped_key, wrapped_key_len);
+ PROCESS_CALL ((self, session, &mechanism, wrapping_key, key, wrapped_key, &wrapped_key_len));
+ OUT_BYTE_ARRAY (wrapped_key, wrapped_key_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_UnwrapKey (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE unwrapping_key;
+ CK_BYTE_PTR wrapped_key;
+ CK_ULONG wrapped_key_len;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG attribute_count;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (UnwrapKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (unwrapping_key);
+ IN_BYTE_ARRAY (wrapped_key, wrapped_key_len);
+ IN_ATTRIBUTE_ARRAY (template, attribute_count);
+ PROCESS_CALL ((self, session, &mechanism, unwrapping_key, wrapped_key, wrapped_key_len, template, attribute_count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DeriveKey (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE base_key;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG attribute_count;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (DeriveKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (base_key);
+ IN_ATTRIBUTE_ARRAY (template, attribute_count);
+ PROCESS_CALL ((self, session, &mechanism, base_key, template, attribute_count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SeedRandom (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR seed;
+ CK_ULONG seed_len;
+
+ BEGIN_CALL (SeedRandom);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (seed, seed_len);
+ PROCESS_CALL ((self, session, seed, seed_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateRandom (CK_X_FUNCTION_LIST *self,
+ p11_rpc_message *msg)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR random_data;
+ CK_ULONG random_len;
+
+ BEGIN_CALL (GenerateRandom);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (random_data, random_len);
+ PROCESS_CALL ((self, session, random_data, random_len));
+ OUT_BYTE_ARRAY (random_data, random_len);
+ END_CALL;
+}
+
+bool
+p11_rpc_server_handle (CK_X_FUNCTION_LIST *self,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ p11_rpc_message msg;
+ CK_RV ret;
+ int req_id;
+
+ return_val_if_fail (self != NULL, false);
+ return_val_if_fail (request != NULL, false);
+ return_val_if_fail (response != NULL, false);
+
+ p11_message_clear ();
+
+ p11_rpc_message_init (&msg, request, response);
+
+ if (!p11_rpc_message_parse (&msg, P11_RPC_REQUEST)) {
+ p11_rpc_message_clear (&msg);
+ p11_message ("couldn't parse pkcs11 rpc message");
+ return false;
+ }
+
+ /* This should have been checked by the parsing code */
+ assert (msg.call_id > P11_RPC_CALL_ERROR);
+ assert (msg.call_id < P11_RPC_CALL_MAX);
+ req_id = msg.call_id;
+
+ switch(req_id) {
+ #define CASE_CALL(name) \
+ case P11_RPC_CALL_##name: \
+ ret = rpc_##name (self, &msg); \
+ break;
+ CASE_CALL (C_Initialize)
+ CASE_CALL (C_Finalize)
+ CASE_CALL (C_GetInfo)
+ CASE_CALL (C_GetSlotList)
+ CASE_CALL (C_GetSlotInfo)
+ CASE_CALL (C_GetTokenInfo)
+ CASE_CALL (C_GetMechanismList)
+ CASE_CALL (C_GetMechanismInfo)
+ CASE_CALL (C_InitToken)
+ CASE_CALL (C_OpenSession)
+ CASE_CALL (C_CloseSession)
+ CASE_CALL (C_CloseAllSessions)
+ CASE_CALL (C_GetSessionInfo)
+ CASE_CALL (C_InitPIN)
+ CASE_CALL (C_SetPIN)
+ CASE_CALL (C_GetOperationState)
+ CASE_CALL (C_SetOperationState)
+ CASE_CALL (C_Login)
+ CASE_CALL (C_Logout)
+ CASE_CALL (C_CreateObject)
+ CASE_CALL (C_CopyObject)
+ CASE_CALL (C_DestroyObject)
+ CASE_CALL (C_GetObjectSize)
+ CASE_CALL (C_GetAttributeValue)
+ CASE_CALL (C_SetAttributeValue)
+ CASE_CALL (C_FindObjectsInit)
+ CASE_CALL (C_FindObjects)
+ CASE_CALL (C_FindObjectsFinal)
+ CASE_CALL (C_EncryptInit)
+ CASE_CALL (C_Encrypt)
+ CASE_CALL (C_EncryptUpdate)
+ CASE_CALL (C_EncryptFinal)
+ CASE_CALL (C_DecryptInit)
+ CASE_CALL (C_Decrypt)
+ CASE_CALL (C_DecryptUpdate)
+ CASE_CALL (C_DecryptFinal)
+ CASE_CALL (C_DigestInit)
+ CASE_CALL (C_Digest)
+ CASE_CALL (C_DigestUpdate)
+ CASE_CALL (C_DigestKey)
+ CASE_CALL (C_DigestFinal)
+ CASE_CALL (C_SignInit)
+ CASE_CALL (C_Sign)
+ CASE_CALL (C_SignUpdate)
+ CASE_CALL (C_SignFinal)
+ CASE_CALL (C_SignRecoverInit)
+ CASE_CALL (C_SignRecover)
+ CASE_CALL (C_VerifyInit)
+ CASE_CALL (C_Verify)
+ CASE_CALL (C_VerifyUpdate)
+ CASE_CALL (C_VerifyFinal)
+ CASE_CALL (C_VerifyRecoverInit)
+ CASE_CALL (C_VerifyRecover)
+ CASE_CALL (C_DigestEncryptUpdate)
+ CASE_CALL (C_DecryptDigestUpdate)
+ CASE_CALL (C_SignEncryptUpdate)
+ CASE_CALL (C_DecryptVerifyUpdate)
+ CASE_CALL (C_GenerateKey)
+ CASE_CALL (C_GenerateKeyPair)
+ CASE_CALL (C_WrapKey)
+ CASE_CALL (C_UnwrapKey)
+ CASE_CALL (C_DeriveKey)
+ CASE_CALL (C_SeedRandom)
+ CASE_CALL (C_GenerateRandom)
+ CASE_CALL (C_WaitForSlotEvent)
+ #undef CASE_CALL
+ default:
+ /* This should have been caught by the parse code */
+ assert (0 && "Unchecked call");
+ break;
+ };
+
+ if (p11_buffer_failed (msg.output)) {
+ p11_message ("out of memory error putting together message");
+ p11_rpc_message_clear (&msg);
+ return false;
+ }
+
+ /* A filled in response */
+ if (ret == CKR_OK) {
+
+ /*
+ * Since we're dealing with many many functions above generating
+ * these messages we want to make sure each of them actually
+ * does what it's supposed to.
+ */
+ assert (p11_rpc_message_is_verified (&msg));
+ assert (msg.call_type == P11_RPC_RESPONSE);
+ assert (msg.call_id == req_id);
+ assert (p11_rpc_calls[msg.call_id].response);
+ assert (strcmp (p11_rpc_calls[msg.call_id].response, msg.signature) == 0);
+
+ /* Fill in an error respnose */
+ } else {
+ if (!p11_rpc_message_prep (&msg, P11_RPC_CALL_ERROR, P11_RPC_RESPONSE) ||
+ !p11_rpc_message_write_ulong (&msg, (uint32_t)ret) ||
+ p11_buffer_failed (msg.output)) {
+ p11_message ("out of memory responding with error");
+ p11_rpc_message_clear (&msg);
+ return false;
+ }
+ }
+
+ p11_rpc_message_clear (&msg);
+ return true;
+}
diff --git a/p11-kit/rpc.h b/p11-kit/rpc.h
new file mode 100644
index 0000000..a86e796
--- /dev/null
+++ b/p11-kit/rpc.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 Stefan Walter
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#ifndef __P11_KIT_RPC_H__
+#define __P11_KIT_RPC_H__
+
+#include "pkcs11.h"
+#include "buffer.h"
+#include "virtual.h"
+
+typedef struct _p11_rpc_client_vtable p11_rpc_client_vtable;
+
+struct _p11_rpc_client_vtable {
+ void *data;
+
+ CK_RV (* connect) (p11_rpc_client_vtable *vtable,
+ void *init_reserved);
+
+ CK_RV (* transport) (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response);
+
+ void (* disconnect) (p11_rpc_client_vtable *vtable,
+ void *fini_reserved);
+
+ void *reserved[16];
+};
+
+bool p11_rpc_client_init (p11_virtual *virt,
+ p11_rpc_client_vtable *vtable);
+
+bool p11_rpc_server_handle (CK_X_FUNCTION_LIST *funcs,
+ p11_buffer *request,
+ p11_buffer *response);
+
+extern CK_MECHANISM_TYPE * p11_rpc_mechanisms_override_supported;
+
+#endif /* __P11_KIT_RPC_H__ */
diff --git a/p11-kit/tests/Makefile.am b/p11-kit/tests/Makefile.am
index d270c74..2192fed 100644
--- a/p11-kit/tests/Makefile.am
+++ b/p11-kit/tests/Makefile.am
@@ -26,6 +26,7 @@ CHECK_PROGS = \
test-deprecated \
test-proxy \
test-iter \
+ test-rpc \
$(NULL)
if WITH_FFI
diff --git a/p11-kit/tests/test-mock.c b/p11-kit/tests/test-mock.c
index 5fba7ec..079ff0d 100644
--- a/p11-kit/tests/test-mock.c
+++ b/p11-kit/tests/test-mock.c
@@ -55,8 +55,14 @@ test_get_info (void)
module = setup_mock_module (NULL);
rv = (module->C_GetInfo) (&info);
- assert (rv == CKR_OK);
- assert (memcmp (&info, &MOCK_INFO, sizeof (CK_INFO)) == 0);
+ assert_num_eq (rv, CKR_OK);
+ assert_num_eq (MOCK_INFO.cryptokiVersion.major, info.cryptokiVersion.major);
+ assert_num_eq (MOCK_INFO.cryptokiVersion.minor, info.cryptokiVersion.minor);
+ assert (memcmp (MOCK_INFO.manufacturerID, info.manufacturerID, sizeof (info.manufacturerID)) == 0);
+ assert_num_eq (MOCK_INFO.flags, info.flags);
+ assert (memcmp (MOCK_INFO.libraryDescription, info.libraryDescription, sizeof (info.libraryDescription)) == 0);
+ assert_num_eq (MOCK_INFO.libraryVersion.major, info.libraryVersion.major);
+ assert_num_eq (MOCK_INFO.libraryVersion.minor, info.libraryVersion.minor);
teardown_mock_module (module);
}
diff --git a/p11-kit/tests/test-rpc.c b/p11-kit/tests/test-rpc.c
new file mode 100644
index 0000000..d945efd
--- /dev/null
+++ b/p11-kit/tests/test-rpc.c
@@ -0,0 +1,939 @@
+/*
+ * Copyright (c) 2012 Stefan Walter
+ * Copyright (c) 2012 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stef@thewalter.net>
+ */
+
+#include "config.h"
+#include "test.h"
+
+#include "debug.h"
+#include "library.h"
+#include "message.h"
+#include "mock.h"
+#include "p11-kit.h"
+#include "private.h"
+#include "rpc.h"
+#include "rpc-message.h"
+#include "virtual.h"
+
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+test_new_free (void)
+{
+ p11_buffer *buf;
+
+ buf = p11_rpc_buffer_new (0);
+
+ assert_ptr_not_null (buf->data);
+ assert_num_eq (0, buf->len);
+ assert_num_eq (0, buf->flags);
+ assert (buf->size == 0);
+ assert_ptr_not_null (buf->ffree);
+ assert_ptr_not_null (buf->frealloc);
+
+ p11_rpc_buffer_free (buf);
+}
+
+static void
+test_uint16 (void)
+{
+ p11_buffer buffer;
+ uint16_t val = 0xFFFF;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ next = 0;
+ ret = p11_rpc_buffer_get_uint16 (&buffer, &next, &val);
+ assert_num_eq (false, ret);
+ assert_num_eq (0, next);
+ assert_num_eq (0xFFFF, val);
+
+ p11_buffer_reset (&buffer, 0);
+
+ ret = p11_rpc_buffer_set_uint16 (&buffer, 0, 0x6789);
+ assert_num_eq (false, ret);
+
+ p11_buffer_reset (&buffer, 0);
+
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+
+ p11_rpc_buffer_add_uint16 (&buffer, 0x6789);
+ assert_num_eq (9, buffer.len);
+ assert (!p11_buffer_failed (&buffer));
+
+ next = 7;
+ ret = p11_rpc_buffer_get_uint16 (&buffer, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (9, next);
+ assert_num_eq (0x6789, val);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_uint16_static (void)
+{
+ p11_buffer buf = { (unsigned char *)"pad0\x67\x89", 6, };
+ uint16_t val = 0xFFFF;
+ size_t next;
+ bool ret;
+
+ next = 4;
+ ret = p11_rpc_buffer_get_uint16 (&buf, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (6, next);
+ assert_num_eq (0x6789, val);
+}
+
+static void
+test_uint32 (void)
+{
+ p11_buffer buffer;
+ uint32_t val = 0xFFFFFFFF;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ next = 0;
+ ret = p11_rpc_buffer_get_uint32 (&buffer, &next, &val);
+ assert_num_eq (false, ret);
+ assert_num_eq (0, next);
+ assert_num_eq (0xFFFFFFFF, val);
+
+ p11_buffer_reset (&buffer, 0);
+
+ ret = p11_rpc_buffer_set_uint32 (&buffer, 0, 0x12345678);
+ assert_num_eq (false, ret);
+
+ p11_buffer_reset (&buffer, 0);
+
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+
+ p11_rpc_buffer_add_uint32 (&buffer, 0x12345678);
+ assert_num_eq (11, buffer.len);
+ assert (!p11_buffer_failed (&buffer));
+
+ next = 7;
+ ret = p11_rpc_buffer_get_uint32 (&buffer, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (11, next);
+ assert_num_eq (0x12345678, val);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_uint32_static (void)
+{
+ p11_buffer buf = { (unsigned char *)"pad0\x23\x45\x67\x89", 8, };
+ uint32_t val = 0xFFFFFFFF;
+ size_t next;
+ bool ret;
+
+ next = 4;
+ ret = p11_rpc_buffer_get_uint32 (&buf, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (8, next);
+ assert_num_eq (0x23456789, val);
+}
+
+static void
+test_uint64 (void)
+{
+ p11_buffer buffer;
+ uint64_t val = 0xFFFFFFFFFFFFFFFF;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ next = 0;
+ ret = p11_rpc_buffer_get_uint64 (&buffer, &next, &val);
+ assert_num_eq (0, ret);
+ assert_num_eq (0, next);
+ assert (0xFFFFFFFFFFFFFFFF == val);
+
+ p11_buffer_reset (&buffer, 0);
+
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+
+ p11_rpc_buffer_add_uint64 (&buffer, 0x0123456708ABCDEF);
+ assert_num_eq (15, buffer.len);
+ assert (!p11_buffer_failed (&buffer));
+
+ next = 7;
+ ret = p11_rpc_buffer_get_uint64 (&buffer, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (15, next);
+ assert (0x0123456708ABCDEF == val);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_uint64_static (void)
+{
+ p11_buffer buf = { (unsigned char *)"pad0\x89\x67\x45\x23\x11\x22\x33\x44", 12, };
+ uint64_t val = 0xFFFFFFFFFFFFFFFF;
+ size_t next;
+ bool ret;
+
+ next = 4;
+ ret = p11_rpc_buffer_get_uint64 (&buf, &next, &val);
+ assert_num_eq (true, ret);
+ assert_num_eq (12, next);
+ assert (0x8967452311223344 == val);
+}
+
+static void
+test_byte_array (void)
+{
+ p11_buffer buffer;
+ unsigned char bytes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+
+ const unsigned char *val;
+ size_t length = ~0;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ /* Invalid read */
+
+ next = 0;
+ ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length);
+ assert_num_eq (false, ret);
+ assert_num_eq (0, next);
+ assert_num_eq (~0, length);
+
+ /* Test full array */
+
+ p11_buffer_reset (&buffer, 0);
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+
+ p11_rpc_buffer_add_byte_array (&buffer, bytes, 32);
+ assert_num_eq (43, buffer.len);
+ assert (!p11_buffer_failed (&buffer));
+
+ next = 7;
+ ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length);
+ assert_num_eq (true, ret);
+ assert_num_eq (43, next);
+ assert_num_eq (32, length);
+ assert (memcmp (val, bytes, 32) == 0);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_byte_array_null (void)
+{
+ p11_buffer buffer;
+ const unsigned char *val;
+ size_t length = ~0;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ p11_buffer_reset (&buffer, 0);
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+
+ p11_rpc_buffer_add_byte_array (&buffer, NULL, 0);
+ assert_num_eq (11, buffer.len);
+ assert (!p11_buffer_failed (&buffer));
+
+ next = 7;
+ ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length);
+ assert_num_eq (true, ret);
+ assert_num_eq (11, next);
+ assert_num_eq (0, length);
+ assert_ptr_eq (NULL, (void*)val);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_byte_array_too_long (void)
+{
+ p11_buffer buffer;
+ const unsigned char *val = NULL;
+ size_t length = ~0;
+ size_t next;
+ bool ret;
+
+ p11_buffer_init (&buffer, 0);
+
+ p11_buffer_reset (&buffer, 0);
+ p11_buffer_add (&buffer, (unsigned char *)"padding", 7);
+ assert (!p11_buffer_failed (&buffer));
+
+ /* Passing a too short buffer here shouldn't matter, as length is checked for sanity */
+ p11_rpc_buffer_add_byte_array (&buffer, (unsigned char *)"", 0x9fffffff);
+ assert (p11_buffer_failed (&buffer));
+
+ /* Force write a too long byte arary to buffer */
+ p11_buffer_reset (&buffer, 0);
+ p11_rpc_buffer_add_uint32 (&buffer, 0x9fffffff);
+
+ next = 0;
+ ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length);
+ assert_num_eq (false, ret);
+ assert_num_eq (0, next);
+ assert_num_eq (~0, length);
+ assert_ptr_eq (NULL, (void*)val);
+
+ p11_buffer_uninit (&buffer);
+}
+
+static void
+test_byte_array_static (void)
+{
+ unsigned char data[] = { 'p', 'a', 'd', 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ p11_buffer buf = { data, 0x40, };
+ const unsigned char *val;
+ size_t length = ~0;
+ size_t next;
+ bool ret;
+
+ next = 4;
+ ret = p11_rpc_buffer_get_byte_array (&buf, &next, &val, &length);
+ assert_num_eq (true, ret);
+ assert_num_eq (40, next);
+ assert_num_eq (32, length);
+ assert (memcmp (data + 8, val, 32) == 0);
+}
+
+static p11_virtual base;
+static bool rpc_initialized = false;
+
+static CK_RV
+rpc_initialize (p11_rpc_client_vtable *vtable,
+ void *init_reserved)
+{
+ assert_str_eq (vtable->data, "vtable-data");
+ assert_num_eq (false, rpc_initialized);
+ rpc_initialized = true;
+
+ return CKR_OK;
+}
+
+static CK_RV
+rpc_initialize_fails (p11_rpc_client_vtable *vtable,
+ void *init_reserved)
+{
+ assert_str_eq (vtable->data, "vtable-data");
+ assert_num_eq (false, rpc_initialized);
+ return CKR_FUNCTION_FAILED;
+}
+
+static CK_RV
+rpc_initialize_device_removed (p11_rpc_client_vtable *vtable,
+ void *init_reserved)
+{
+ assert_str_eq (vtable->data, "vtable-data");
+ assert_num_eq (false, rpc_initialized);
+ return CKR_DEVICE_REMOVED;
+}
+
+static CK_RV
+rpc_transport (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ bool ret;
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ /* Just pass directly to the server code */
+ ret = p11_rpc_server_handle (&base.funcs, request, response);
+ assert (ret == true);
+
+ return CKR_OK;
+}
+
+static void
+rpc_finalize (p11_rpc_client_vtable *vtable,
+ void *fini_reserved)
+{
+ assert_str_eq (vtable->data, "vtable-data");
+ assert_num_eq (true, rpc_initialized);
+ rpc_initialized = false;
+}
+
+static void
+test_initialize (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ rpc_initialized = false;
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ rv = mixin.funcs.C_Initialize (&mixin.funcs, NULL);
+ assert (rv == CKR_OK);
+ assert_num_eq (true, rpc_initialized);
+
+ rv = mixin.funcs.C_Finalize (&mixin.funcs, NULL);
+ assert (rv == CKR_OK);
+ assert_num_eq (false, rpc_initialized);
+
+ p11_virtual_uninit (&mixin);
+}
+
+static void
+test_not_initialized (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize };
+ p11_virtual mixin;
+ CK_INFO info;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ rpc_initialized = false;
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ rv = (mixin.funcs.C_GetInfo) (&mixin.funcs, &info);
+ assert (rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+ p11_virtual_uninit (&mixin);
+}
+
+static void
+test_initialize_fails_on_client (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize_fails, rpc_transport, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ rpc_initialized = false;
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_FUNCTION_FAILED);
+ assert_num_eq (false, rpc_initialized);
+
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_fails (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ return CKR_FUNCTION_REJECTED;
+}
+
+static void
+test_transport_fails (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_fails, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ rpc_initialized = false;
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_FUNCTION_REJECTED);
+ assert_num_eq (false, rpc_initialized);
+
+ p11_virtual_uninit (&mixin);
+}
+
+static void
+test_initialize_fails_on_server (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+ base.funcs.C_Initialize = mock_X_Initialize__fails;
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_FUNCTION_FAILED);
+ assert_num_eq (false, rpc_initialized);
+
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_bad_parse (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ int rc;
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ /* Just zero bytes is an invalid message */
+ rc = p11_buffer_reset (response, 2);
+ assert (rc >= 0);
+
+ memset (response->data, 0, 2);
+ response->len = 2;
+ return CKR_OK;
+}
+
+static void
+test_transport_bad_parse (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_bad_parse, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ rpc_initialized = false;
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ p11_kit_be_quiet ();
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_DEVICE_ERROR);
+ assert_num_eq (0, rpc_initialized);
+
+ p11_message_loud ();
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_short_error (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ int rc;
+
+ unsigned char data[] = {
+ 0x00, 0x00, 0x00, 0x00, /* RPC_CALL_ERROR */
+ 0x00, 0x00, 0x00, 0x01, 0x75, /* signature 'u' */
+ 0x00, 0x01, /* short error */
+ };
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ rc = p11_buffer_reset (response, sizeof (data));
+ assert (rc >= 0);
+
+ memcpy (response->data, data, sizeof (data));
+ response->len = sizeof (data);
+ return CKR_OK;
+}
+
+static void
+test_transport_short_error (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_short_error, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ p11_kit_be_quiet ();
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_DEVICE_ERROR);
+ assert_num_eq (0, rpc_initialized);
+
+ p11_message_loud ();
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_invalid_error (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ int rc;
+
+ unsigned char data[] = {
+ 0x00, 0x00, 0x00, 0x00, /* RPC_CALL_ERROR */
+ 0x00, 0x00, 0x00, 0x01, 0x75, /* signature 'u' */
+ 0x00, 0x00, 0x00, 0x00, /* a CKR_OK error*/
+ 0x00, 0x00, 0x00, 0x00,
+ };
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ rc = p11_buffer_reset (response, sizeof (data));
+ assert (rc >= 0);
+ memcpy (response->data, data, sizeof (data));
+ response->len = sizeof (data);
+ return CKR_OK;
+}
+
+static void
+test_transport_invalid_error (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_invalid_error, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ p11_kit_be_quiet ();
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_DEVICE_ERROR);
+ assert_num_eq (0, rpc_initialized);
+
+ p11_message_loud ();
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_wrong_response (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ int rc;
+
+ unsigned char data[] = {
+ 0x00, 0x00, 0x00, 0x02, /* RPC_CALL_C_Finalize */
+ 0x00, 0x00, 0x00, 0x00, /* signature '' */
+ };
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ rc = p11_buffer_reset (response, sizeof (data));
+ assert (rc >= 0);
+ memcpy (response->data, data, sizeof (data));
+ response->len = sizeof (data);
+ return CKR_OK;
+}
+
+static void
+test_transport_wrong_response (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_wrong_response, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ p11_kit_be_quiet ();
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_DEVICE_ERROR);
+ assert_num_eq (0, rpc_initialized);
+
+ p11_message_loud ();
+ p11_virtual_uninit (&mixin);
+}
+
+static CK_RV
+rpc_transport_bad_contents (p11_rpc_client_vtable *vtable,
+ p11_buffer *request,
+ p11_buffer *response)
+{
+ int rc;
+
+ unsigned char data[] = {
+ 0x00, 0x00, 0x00, 0x02, /* RPC_CALL_C_GetInfo */
+ 0x00, 0x00, 0x00, 0x05, /* signature 'vsusv' */
+ 'v', 's', 'u', 's', 'v',
+ 0x00, 0x00, 0x00, 0x00, /* invalid data */
+ };
+
+ assert_str_eq (vtable->data, "vtable-data");
+
+ rc = p11_buffer_reset (response, sizeof (data));
+ assert (rc >= 0);
+ memcpy (response->data, data, sizeof (data));
+ response->len = sizeof (data);
+ return CKR_OK;
+}
+
+static void
+test_transport_bad_contents (void)
+{
+ p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_bad_contents, rpc_finalize };
+ p11_virtual mixin;
+ bool ret;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL);
+
+ ret = p11_rpc_client_init (&mixin, &vtable);
+ assert_num_eq (true, ret);
+
+ p11_kit_be_quiet ();
+
+ rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL);
+ assert (rv == CKR_DEVICE_ERROR);
+ assert_num_eq (0, rpc_initialized);
+
+ p11_message_loud ();
+ p11_virtual_uninit (&mixin);
+}
+
+static p11_rpc_client_vtable test_normal_vtable = {
+ NULL,
+ rpc_initialize,
+ rpc_transport,
+ rpc_finalize,
+};
+
+static p11_rpc_client_vtable test_device_removed_vtable = {
+ NULL,
+ rpc_initialize_device_removed,
+ rpc_transport,
+ rpc_finalize,
+};
+
+static void
+mixin_free (void *data)
+{
+ p11_virtual *mixin = data;
+ p11_virtual_uninit (mixin);
+ free (mixin);
+}
+
+static CK_FUNCTION_LIST_PTR
+setup_test_rpc_module (p11_rpc_client_vtable *vtable,
+ CK_FUNCTION_LIST *module_template,
+ CK_SESSION_HANDLE *session)
+{
+ CK_FUNCTION_LIST *rpc_module;
+ p11_virtual *mixin;
+ CK_RV rv;
+
+ /* Build up our own function list */
+ p11_virtual_init (&base, &p11_virtual_base, module_template, NULL);
+
+ mixin = calloc (1, sizeof (p11_virtual));
+ assert (mixin != NULL);
+
+ vtable->data = "vtable-data";
+ if (!p11_rpc_client_init (mixin, vtable))
+ assert_not_reached ();
+
+ rpc_module = p11_virtual_wrap (mixin, mixin_free);
+ assert_ptr_not_null (rpc_module);
+
+ rv = p11_kit_module_initialize (rpc_module);
+ assert (rv == CKR_OK);
+
+ if (session) {
+ rv = (rpc_module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_RW_SESSION | CKF_SERIAL_SESSION,
+ NULL, NULL, session);
+ assert (rv == CKR_OK);
+ }
+
+ return rpc_module;
+}
+
+static CK_FUNCTION_LIST *
+setup_mock_module (CK_SESSION_HANDLE *session)
+{
+ return setup_test_rpc_module (&test_normal_vtable, &mock_module, session);
+}
+
+static void
+teardown_mock_module (CK_FUNCTION_LIST *rpc_module)
+{
+ p11_kit_module_finalize (rpc_module);
+ p11_virtual_unwrap (rpc_module);
+}
+
+static void
+test_get_info_stand_in (void)
+{
+ CK_FUNCTION_LIST_PTR rpc_module;
+ CK_INFO info;
+ CK_RV rv;
+ char *string;
+
+ rpc_module = setup_test_rpc_module (&test_device_removed_vtable,
+ &mock_module_no_slots, NULL);
+
+ rv = (rpc_module->C_GetInfo) (&info);
+ assert (rv == CKR_OK);
+
+ assert_num_eq (CRYPTOKI_VERSION_MAJOR, info.cryptokiVersion.major);
+ assert_num_eq (CRYPTOKI_VERSION_MINOR, info.cryptokiVersion.minor);
+ string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+ assert_str_eq ("p11-kit", string);
+ free (string);
+ string = p11_kit_space_strdup (info.libraryDescription, sizeof (info.libraryDescription));
+ assert_str_eq ("p11-kit (no connection)", string);
+ free (string);
+ assert_num_eq (0, info.flags);
+ assert_num_eq (1, info.libraryVersion.major);
+ assert_num_eq (1, info.libraryVersion.minor);
+
+ teardown_mock_module (rpc_module);
+}
+
+static void
+test_get_slot_list_no_device (void)
+{
+ CK_FUNCTION_LIST_PTR rpc_module;
+ CK_SLOT_ID slot_list[8];
+ CK_ULONG count;
+ CK_RV rv;
+
+ rpc_module = setup_test_rpc_module (&test_device_removed_vtable,
+ &mock_module_no_slots, NULL);
+
+ rv = (rpc_module->C_GetSlotList) (CK_TRUE, NULL, &count);
+ assert (rv == CKR_OK);
+ assert_num_eq (0, count);
+ rv = (rpc_module->C_GetSlotList) (CK_FALSE, NULL, &count);
+ assert (rv == CKR_OK);
+ assert_num_eq (0, count);
+
+ count = 8;
+ rv = (rpc_module->C_GetSlotList) (CK_TRUE, slot_list, &count);
+ assert (rv == CKR_OK);
+ assert_num_eq (0, count);
+
+ count = 8;
+ rv = (rpc_module->C_GetSlotList) (CK_FALSE, slot_list, &count);
+ assert (rv == CKR_OK);
+ assert_num_eq (0, count);
+
+ teardown_mock_module (rpc_module);
+}
+
+#include "test-mock.c"
+
+int
+main (int argc,
+ char *argv[])
+{
+ CK_MECHANISM_TYPE mechanisms[] = {
+ CKM_MOCK_CAPITALIZE,
+ CKM_MOCK_PREFIX,
+ CKM_MOCK_GENERATE,
+ CKM_MOCK_WRAP,
+ CKM_MOCK_DERIVE,
+ CKM_MOCK_COUNT,
+ 0,
+ };
+
+ mock_module_init ();
+ p11_library_init ();
+
+ /* Override the mechanisms that the RPC mechanism will handle */
+ p11_rpc_mechanisms_override_supported = mechanisms;
+
+ p11_test (test_new_free, "/rpc/new-free");
+ p11_test (test_uint16, "/rpc/uint16");
+ p11_test (test_uint16_static, "/rpc/uint16-static");
+ p11_test (test_uint32, "/rpc/uint32");
+ p11_test (test_uint32_static, "/rpc/uint32-static");
+ p11_test (test_uint64, "/rpc/uint64");
+ p11_test (test_uint64_static, "/rpc/uint64-static");
+ p11_test (test_byte_array, "/rpc/byte-array");
+ p11_test (test_byte_array_null, "/rpc/byte-array-null");
+ p11_test (test_byte_array_too_long, "/rpc/byte-array-too-long");
+ p11_test (test_byte_array_static, "/rpc/byte-array-static");
+
+ p11_test (test_initialize_fails_on_client, "/rpc/initialize-fails-on-client");
+ p11_test (test_initialize_fails_on_server, "/rpc/initialize-fails-on-server");
+ p11_test (test_initialize, "/rpc/initialize");
+ p11_test (test_not_initialized, "/rpc/not-initialized");
+ p11_test (test_transport_fails, "/rpc/transport-fails");
+ p11_test (test_transport_bad_parse, "/rpc/transport-bad-parse");
+ p11_test (test_transport_short_error, "/rpc/transport-short-error");
+ p11_test (test_transport_invalid_error, "/rpc/transport-invalid-error");
+ p11_test (test_transport_wrong_response, "/rpc/transport-wrong-response");
+ p11_test (test_transport_bad_contents, "/rpc/transport-bad-contents");
+ p11_test (test_get_info_stand_in, "/rpc/get-info-stand-in");
+ p11_test (test_get_slot_list_no_device, "/rpc/get-slot-list-no-device");
+
+ test_mock_add_tests ("/rpc");
+
+ return p11_test_run (argc, argv);
+}