gnome-keyring r1429 - in trunk: . pkcs11 pkcs11/rpc pkcs11/rpc-layer
- From: nnielsen svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-keyring r1429 - in trunk: . pkcs11 pkcs11/rpc pkcs11/rpc-layer
- Date: Sun, 4 Jan 2009 23:07:19 +0000 (UTC)
Author: nnielsen
Date: Sun Jan 4 23:07:18 2009
New Revision: 1429
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1429&view=rev
Log:
* configure.in:
* pkcs11/Makefile.am:
* pkcs11/rpc-layer/: (renamed from rpc/)
* pkcs11/rpc-layer/gck-rpc-daemon-standalone.c:
* pkcs11/rpc-layer/gck-rpc-dispatch.c:
* pkcs11/rpc-layer/gck-rpc-layer.h:
* pkcs11/rpc-layer/gck-rpc-message.c:
* pkcs11/rpc-layer/gck-rpc-module.c:
* pkcs11/rpc-layer/gck-rpc-private.h:
* pkcs11/rpc-layer/gck-rpc-util.c:
* pkcs11/rpc-layer/Makefile.am: Rename 'rpc' to 'rpc-layer' component, and
reorganize how the files are installed.
Added:
trunk/pkcs11/rpc-layer/ (props changed)
- copied from r1425, /trunk/pkcs11/rpc/
trunk/pkcs11/rpc-layer/gck-rpc-daemon-standalone.c
trunk/pkcs11/rpc-layer/gck-rpc-dispatch.c
trunk/pkcs11/rpc-layer/gck-rpc-layer.h
trunk/pkcs11/rpc-layer/gck-rpc-message.c
trunk/pkcs11/rpc-layer/gck-rpc-module.c
trunk/pkcs11/rpc-layer/gck-rpc-private.h
trunk/pkcs11/rpc-layer/gck-rpc-util.c
Removed:
trunk/pkcs11/rpc/
Modified:
trunk/ChangeLog
trunk/configure.in
trunk/pkcs11/Makefile.am
trunk/pkcs11/rpc-layer/Makefile.am
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Sun Jan 4 23:07:18 2009
@@ -520,7 +520,7 @@
pkcs11/ssh-agent/Makefile
pkcs11/ssh-store/Makefile
pkcs11/ssh-store/tests/Makefile
-pkcs11/rpc/Makefile
+pkcs11/rpc-layer/Makefile
pkcs11/tests/Makefile
po/Makefile.in
tests/Makefile
Modified: trunk/pkcs11/Makefile.am
==============================================================================
--- trunk/pkcs11/Makefile.am (original)
+++ trunk/pkcs11/Makefile.am Sun Jan 4 23:07:18 2009
@@ -47,5 +47,5 @@
TESTS_DIR =
endif
-SUBDIRS = . rpc gck ssh-agent ssh-store $(ROOTS_DIR) $(TESTS_DIR)
+SUBDIRS = . gck ssh-agent ssh-store rpc-layer $(ROOTS_DIR) $(TESTS_DIR)
Modified: trunk/pkcs11/rpc-layer/Makefile.am
==============================================================================
--- /trunk/pkcs11/rpc/Makefile.am (original)
+++ trunk/pkcs11/rpc-layer/Makefile.am Sun Jan 4 23:07:18 2009
@@ -1,17 +1,9 @@
noinst_LTLIBRARIES = \
- libp11-rpc-daemon.la \
- libp11-rpc-module.la
-
-# Have to install this somewhere to get libtool to actually
-# build the library. Strange stuff.
-moduledir = /tmp
-
-module_LTLIBRARIES = \
- p11-rpc-test-module.la
+ libgck-rpc-layer.la
noinst_PROGRAMS = \
- p11-rpc-test-daemon
+ gck-rpc-daemon-standalone
INCLUDES = -I. \
-I$(top_srcdir) \
@@ -20,47 +12,50 @@
# ------------------------------------------------------------------------------
# The dispatch code
-libp11_rpc_daemon_la_SOURCES = \
- p11-rpc-private.h \
- p11-rpc-dispatch.c \
- p11-rpc-message.c \
- p11-rpc-util.c
-
-libp11_rpc_daemon_la_LIBADD = \
- $(top_builddir)/common/libgkr-common-buffer.la
+libgck_rpc_layer_la_SOURCES = \
+ gck-rpc-private.h \
+ gck-rpc-dispatch.c \
+ gck-rpc-message.c \
+ gck-rpc-util.c
+
+libgck_rpc_layer_la_LIBADD = \
+ $(top_builddir)/common/libgkr-common-buffer.la \
+ $(GOBJECT_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(GLIB_LIBS)
+
+libgck_rpc_layer_la_CFLAGS = \
+ $(GOBJECT_CFLAGS) \
+ $(GTHREAD_CFLAGS) \
+ $(GLIB_CFLAGS)
# ------------------------------------------------------------------------------
# The module code
-libp11_rpc_module_la_SOURCES = \
- p11-rpc-private.h \
- p11-rpc-module.c \
- p11-rpc-message.c \
- p11-rpc-util.c
+moduledir = $(libdir)/gnome-keyring/devel/
-libp11_rpc_module_la_LIBADD = \
- $(top_builddir)/common/libgkr-common-buffer.la
+module_LTLIBRARIES = \
+ gck-rpc-layer-standalone.la
-# ------------------------------------------------------------------------------
-# The test module
+gck_rpc_layer_standalone_la_SOURCES = \
+ gck-rpc-private.h \
+ gck-rpc-module.c \
+ gck-rpc-message.c \
+ gck-rpc-util.c
+
+gck_rpc_layer_standalone_la_LIBADD = \
+ $(top_builddir)/common/libgkr-common-buffer.la
-p11_rpc_test_module_la_LDFLAGS = \
+gck_rpc_layer_standalone_la_LDFLAGS = \
-module -avoid-version \
-no-undefined -export-symbols-regex 'C_GetFunctionList'
-p11_rpc_test_module_la_SOURCES = \
- p11-rpc-test-module.c
-
-p11_rpc_test_module_la_LIBADD = \
- libp11-rpc-module.la
-
# -----------------------------------------------------------------------------
# The test daemon
-p11_rpc_test_daemon_SOURCES = \
- p11-rpc-test-daemon.c
+gck_rpc_daemon_standalone_SOURCES = \
+ gck-rpc-daemon-standalone.c
-p11_rpc_test_daemon_LDADD = \
- -ldl -lpthread \
- libp11-rpc-daemon.la
+gck_rpc_daemon_standalone_LDADD = \
+ -ldl -lpthread libgck-rpc-layer.la
\ No newline at end of file
Added: trunk/pkcs11/rpc-layer/gck-rpc-daemon-standalone.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-daemon-standalone.c Sun Jan 4 23:07:18 2009
@@ -0,0 +1,116 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-rpc-daemon-standalone.c - A sample daemon.
+
+ Copyright (C) 2008, Stef Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include "gck-rpc-layer.h"
+
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dlfcn.h>
+#include <pthread.h>
+
+#define SOCKET_PATH "/tmp/gck-rpc-daemon.sock"
+
+/* Sample configuration for loading NSS remotely */
+static CK_C_INITIALIZE_ARGS p11_init_args = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CKF_OS_LOCKING_OK,
+ "init-string = configdir='/tmp' certPrefix='' keyPrefix='' secmod='/tmp/secmod.db' flags="
+};
+
+static int is_running = 1;
+
+static int
+usage (void)
+{
+ fprintf (stderr, "usage: gck-rpc-daemon pkcs11-module");
+ exit (2);
+}
+
+int
+main (int argc, char *argv[])
+{
+ CK_C_GetFunctionList func_get_list;
+ CK_FUNCTION_LIST_PTR funcs;
+ void *module;
+ fd_set read_fds;
+ int sock, ret;
+ CK_RV rv;
+
+ /* The module to load is the argument */
+ if (argc != 2)
+ usage();
+
+ /* Load the library */
+ module = dlopen(argv[1], RTLD_NOW);
+ if(!module)
+ errx (1, "couldn't open library: %s: %s", argv[1], dlerror());
+
+ /* Lookup the appropriate function in library */
+ func_get_list = (CK_C_GetFunctionList)dlsym (module, "C_GetFunctionList");
+ if (!func_get_list)
+ errx (1, "couldn't find C_GetFunctionList in library: %s: %s",
+ argv[1], dlerror());
+
+ /* Get the function list */
+ rv = (func_get_list) (&funcs);
+ if (rv != CKR_OK || !funcs)
+ errx (1, "couldn't get function list from C_GetFunctionList in libary: %s: 0x%08x",
+ argv[1], (int)rv);
+
+ unlink (SOCKET_PATH);
+ sock = gck_rpc_dispatch_init (SOCKET_PATH, funcs, &p11_init_args);
+ if (sock == -1)
+ exit (1);
+
+ is_running = 1;
+ while (is_running) {
+ FD_ZERO (&read_fds);
+ FD_SET (sock, &read_fds);
+ ret = select (sock + 1, &read_fds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ err (1, "error watching socket");
+ }
+
+ if (FD_ISSET (sock, &read_fds))
+ gck_rpc_dispatch_accept ();
+ }
+
+ gck_rpc_dispatch_uninit ();
+ dlclose(module);
+
+ return 0;
+}
\ No newline at end of file
Added: trunk/pkcs11/rpc-layer/gck-rpc-dispatch.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-dispatch.c Sun Jan 4 23:07:18 2009
@@ -0,0 +1,2219 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-rpc-dispatch.h - receiver of our PKCS#11 protocol.
+
+ Copyright (C) 2008, Stef Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-rpc-layer.h"
+#include "gck-rpc-private.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+/* Where we dispatch the calls to */
+static CK_FUNCTION_LIST_PTR pkcs11_module = NULL;
+
+/* Argument to pass to C_Initialize */
+static CK_C_INITIALIZE_ARGS *pkcs11_initialize_args = NULL;
+
+/* Mutex for guarding initialization variable */
+static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* The number of times we've initialized */
+static int pkcs11_initialized = 0;
+
+/* The error returned on protocol failures */
+#define PARSE_ERROR CKR_DEVICE_ERROR
+#define PREP_ERROR CKR_DEVICE_MEMORY
+
+/* -----------------------------------------------------------------------------
+ * LOGGING and DEBUGGING
+ */
+
+#if DEBUG_OUTPUT
+#define debug(x) gck_rpc_debug x
+#else
+#define debug(x)
+#endif
+
+#define warning(x) gck_rpc_warn x
+
+#define return_val_if_fail(x, v) \
+ if (!(x)) { rpc_warn ("'%s' not true at %s", #x, __func__); return v; }
+
+void
+gck_rpc_log (const char *line)
+{
+ g_message ("%s", line);
+}
+
+/* -------------------------------------------------------------------------------
+ * CALL STRUCTURES
+ */
+
+typedef struct _CallState {
+ GckRpcMessage *req;
+ GckRpcMessage *resp;
+ void *allocated;
+} CallState;
+
+static int
+call_init (CallState *cs)
+{
+ assert (cs);
+
+ cs->req = gck_rpc_message_new ((GkrBufferAllocator)realloc);
+ cs->resp = gck_rpc_message_new ((GkrBufferAllocator)realloc);
+ if (!cs->req || !cs->resp) {
+ gck_rpc_message_free (cs->req);
+ gck_rpc_message_free (cs->resp);
+ return 0;
+ }
+
+ cs->allocated = NULL;
+ return 1;
+}
+
+static void*
+call_alloc (CallState *cs, size_t length)
+{
+ void **data;
+
+ assert (cs);
+
+ if (length > 0x7fffffff)
+ return NULL;
+
+ data = malloc (sizeof (void*) + length);
+ if (!data)
+ 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 = cs->allocated;
+ cs->allocated = data;
+
+ /* Data starts after first pointer */
+ return (void*)(data + 1);
+}
+
+static void
+call_reset (CallState *cs)
+{
+ void *allocated;
+ void **data;
+
+ assert (cs);
+
+ allocated = cs->allocated;
+ while (allocated) {
+ data = (void**)allocated;
+
+ /* Pointer to the next allocation */
+ allocated = *data;
+ free (data);
+ }
+
+ cs->allocated = NULL;
+ gck_rpc_message_reset (cs->req);
+ gck_rpc_message_reset (cs->resp);
+}
+
+static void
+call_uninit (CallState *cs)
+{
+ assert (cs);
+
+ call_reset (cs);
+
+ gck_rpc_message_free (cs->req);
+ gck_rpc_message_free (cs->resp);
+}
+
+/* -------------------------------------------------------------------
+ * PROTOCOL CODE
+ */
+
+static CK_RV
+proto_read_byte_buffer (CallState *cs, CK_BYTE_PTR* buffer, CK_ULONG* n_buffer)
+{
+ GckRpcMessage *msg;
+ uint32_t length;
+
+ assert (cs);
+ assert (buffer);
+ assert (n_buffer);
+
+ msg = cs->req;
+
+ /* Check that we're supposed to be reading this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "ay"));
+
+ /* The number of ulongs there's room for on the other end */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &length))
+ return PARSE_ERROR;
+
+ *n_buffer = length;
+ *buffer = NULL;
+
+ /* If set to zero, then they just want the length */
+ if (!length)
+ return CKR_OK;
+
+ *buffer = call_alloc (cs, length * sizeof (CK_BYTE));
+ if (!*buffer)
+ return CKR_DEVICE_MEMORY;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_byte_array (CallState *cs, CK_BYTE_PTR* array, CK_ULONG* n_array)
+{
+ GckRpcMessage *msg;
+ const unsigned char *data;
+ unsigned char valid;
+ uint32_t n_data;
+
+ assert (cs);
+
+ msg = cs->req;
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "ay"));
+
+ /* Read out the byte which says whether data is present or not */
+ if (!gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ /* Module should always send us valid arrays */
+ if (!valid)
+ return PARSE_ERROR;
+
+ /* Point our arguments into the buffer */
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed,
+ &data, &n_data))
+ return PARSE_ERROR;
+
+ *array = (CK_BYTE_PTR)data;
+ *n_array = n_data;
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_ulong_buffer (CallState *cs, CK_ULONG_PTR* buffer, CK_ULONG* n_buffer)
+{
+ GckRpcMessage *msg;
+ uint32_t length;
+
+ assert (cs);
+ assert (buffer);
+ assert (n_buffer);
+
+ msg = cs->req;
+
+ /* Check that we're supposed to be reading this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "fu"));
+
+ /* The number of ulongs there's room for on the other end */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &length))
+ return PARSE_ERROR;
+
+ *n_buffer = length;
+ *buffer = NULL;
+
+ /* If set to zero, then they just want the length */
+ if (!length)
+ return CKR_OK;
+
+ *buffer = call_alloc (cs, length * sizeof (CK_ULONG));
+ if (!*buffer)
+ return CKR_DEVICE_MEMORY;
+
+ return CKR_OK;
+}
+
+
+static CK_RV
+proto_read_attribute_buffer (CallState *cs, CK_ATTRIBUTE_PTR* result, CK_ULONG* n_result)
+{
+ CK_ATTRIBUTE_PTR attrs;
+ GckRpcMessage *msg;
+ uint32_t n_attrs, i;
+ uint32_t value;
+
+ assert (cs);
+ assert (result);
+ assert (n_result);
+
+ msg = cs->req;
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "fA"));
+
+ /* Read the number of attributes */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &n_attrs))
+ return PARSE_ERROR;
+
+ /* Allocate memory for the attribute structures */
+ attrs = call_alloc (cs, n_attrs * sizeof (CK_ATTRIBUTE));
+ if (!attrs)
+ return CKR_DEVICE_MEMORY;
+
+ /* Now go through and fill in each one */
+ for (i = 0; i < n_attrs; ++i) {
+
+ /* The attribute type */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ attrs[i].type = value;
+
+ /* The number of bytes to allocate */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ if (value == 0) {
+ attrs[i].pValue = NULL;
+ attrs[i].ulValueLen = 0;
+ } else {
+ attrs[i].pValue = call_alloc (cs, 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 (CallState *cs, CK_ATTRIBUTE_PTR* result, CK_ULONG* n_result)
+{
+ CK_ATTRIBUTE_PTR attrs;
+ const unsigned char *data;
+ unsigned char valid;
+ GckRpcMessage *msg;
+ uint32_t n_attrs, i;
+ uint32_t value;
+ size_t n_data;
+
+ assert (cs);
+ assert (result);
+ assert (n_result);
+
+ msg = cs->req;
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "aA"));
+
+ /* Read the number of attributes */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &n_attrs))
+ return PARSE_ERROR;
+
+ /* Allocate memory for the attribute structures */
+ attrs = call_alloc (cs, n_attrs * sizeof (CK_ATTRIBUTE));
+ if (!attrs)
+ return CKR_DEVICE_MEMORY;
+
+ /* Now go through and fill in each one */
+ for (i = 0; i < n_attrs; ++i) {
+
+ /* The attribute type */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ attrs[i].type = value;
+
+ /* Whether this one is valid or not */
+ if (!gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ if (valid) {
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+ attrs[i].pValue = (CK_VOID_PTR)data;
+ attrs[i].ulValueLen = n_data;
+ } 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 (CallState *cs, CK_ATTRIBUTE_PTR array, CK_ULONG len, CK_RV ret)
+{
+ assert (cs);
+
+ /*
+ * 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 (!gck_rpc_message_write_attribute_array (cs->resp, array, len) ||
+ !gck_rpc_message_write_ulong (cs->resp, ret))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_null_string (CallState *cs, CK_UTF8CHAR_PTR* val)
+{
+ GckRpcMessage *msg;
+ const unsigned char *data;
+ size_t n_data;
+
+ assert (cs);
+ assert (val);
+
+ msg = cs->req;
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "z"));
+
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data))
+ return PARSE_ERROR;
+
+ /* Allocate a block of memory for it */
+ *val = call_alloc (cs, n_data);
+ if (!*val)
+ return CKR_DEVICE_MEMORY;
+
+ memcpy (*val, data, n_data);
+ (*val)[n_data] = 0;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_mechanism (CallState *cs, CK_MECHANISM_PTR mech)
+{
+ GckRpcMessage *msg;
+ const unsigned char *data;
+ uint32_t value;
+ size_t n_data;
+
+ assert (cs);
+ assert (mech);
+
+ msg = cs->req;
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "M"));
+
+ /* The mechanism type */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &value))
+ return PARSE_ERROR;
+
+ /* The mechanism data */
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &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 (CallState *cs, CK_INFO_PTR info)
+{
+ GckRpcMessage *msg;
+
+ assert (cs);
+ assert (info);
+
+ msg = cs->resp;
+
+ if (!gck_rpc_message_write_version (msg, &info->cryptokiVersion) ||
+ !gck_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_write_ulong (msg, info->flags) ||
+ !gck_rpc_message_write_space_string (msg, info->libraryDescription, 32) ||
+ !gck_rpc_message_write_version (msg, &info->libraryVersion))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_slot_info (CallState *cs, CK_SLOT_INFO_PTR info)
+{
+ GckRpcMessage *msg;
+
+ assert (cs);
+ assert (info);
+
+ msg = cs->resp;
+
+ if (!gck_rpc_message_write_space_string (msg, info->slotDescription, 64) ||
+ !gck_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_write_ulong (msg, info->flags) ||
+ !gck_rpc_message_write_version (msg, &info->hardwareVersion) ||
+ !gck_rpc_message_write_version (msg, &info->firmwareVersion))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_token_info (CallState *cs, CK_TOKEN_INFO_PTR info)
+{
+ GckRpcMessage *msg;
+
+ assert (cs);
+ assert (info);
+
+ msg = cs->resp;
+
+ if (!gck_rpc_message_write_space_string (msg, info->label, 32) ||
+ !gck_rpc_message_write_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_write_space_string (msg, info->model, 16) ||
+ !gck_rpc_message_write_space_string (msg, info->serialNumber, 16) ||
+ !gck_rpc_message_write_ulong (msg, info->flags) ||
+ !gck_rpc_message_write_ulong (msg, info->ulMaxSessionCount) ||
+ !gck_rpc_message_write_ulong (msg, info->ulSessionCount) ||
+ !gck_rpc_message_write_ulong (msg, info->ulMaxRwSessionCount) ||
+ !gck_rpc_message_write_ulong (msg, info->ulRwSessionCount) ||
+ !gck_rpc_message_write_ulong (msg, info->ulMaxPinLen) ||
+ !gck_rpc_message_write_ulong (msg, info->ulMinPinLen) ||
+ !gck_rpc_message_write_ulong (msg, info->ulTotalPublicMemory) ||
+ !gck_rpc_message_write_ulong (msg, info->ulFreePublicMemory) ||
+ !gck_rpc_message_write_ulong (msg, info->ulTotalPrivateMemory) ||
+ !gck_rpc_message_write_ulong (msg, info->ulFreePrivateMemory) ||
+ !gck_rpc_message_write_version (msg, &info->hardwareVersion) ||
+ !gck_rpc_message_write_version (msg, &info->firmwareVersion) ||
+ !gck_rpc_message_write_space_string (msg, info->utcTime, 16))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_mechanism_info (CallState *cs, CK_MECHANISM_INFO_PTR info)
+{
+ GckRpcMessage *msg;
+
+ assert (cs);
+ assert (info);
+
+ msg = cs->resp;
+
+ if (!gck_rpc_message_write_ulong (msg, info->ulMinKeySize) ||
+ !gck_rpc_message_write_ulong (msg, info->ulMaxKeySize) ||
+ !gck_rpc_message_write_ulong (msg, info->flags))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_write_session_info (CallState *cs, CK_SESSION_INFO_PTR info)
+{
+ GckRpcMessage *msg;
+
+ assert (cs);
+ assert (info);
+
+ msg = cs->resp;
+
+ if (!gck_rpc_message_write_ulong (msg, info->slotID) ||
+ !gck_rpc_message_write_ulong (msg, info->state) ||
+ !gck_rpc_message_write_ulong (msg, info->flags) ||
+ !gck_rpc_message_write_ulong (msg, info->ulDeviceError))
+ return PREP_ERROR;
+
+ return CKR_OK;
+}
+
+/* -------------------------------------------------------------------
+ * CALL MACROS
+ */
+
+#define BEGIN_CALL(call_id) \
+ debug ((#call_id ": enter")); \
+ assert (cs); \
+ assert (pkcs11_module); \
+ { \
+ CK_ ## call_id _func = pkcs11_module-> call_id; \
+ CK_RV _ret = CKR_OK; \
+ if (!_func) { _ret = CKR_GENERAL_ERROR; goto _cleanup; }
+
+#define PROCESS_CALL(args)\
+ assert (gck_rpc_message_is_verified (cs->req)); \
+ _ret = _func args
+
+#define END_CALL \
+ _cleanup: \
+ debug (("ret: %d", _ret)); \
+ return _ret; \
+ }
+
+#define IN_BYTE(val) \
+ if (!gck_rpc_message_read_byte (cs->req, &val)) \
+ { _ret = PARSE_ERROR; goto _cleanup; }
+
+#define IN_ULONG(val) \
+ if (!gck_rpc_message_read_ulong (cs->req, &val)) \
+ { _ret = PARSE_ERROR; goto _cleanup; }
+
+#define IN_STRING(val) \
+ _ret = proto_read_null_string (cs, &val); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_BYTE_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_byte_buffer (cs, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_BYTE_ARRAY(buffer, buffer_len) \
+ _ret = proto_read_byte_array (cs, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ULONG_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_ulong_buffer (cs, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ATTRIBUTE_BUFFER(buffer, buffer_len) \
+ _ret = proto_read_attribute_buffer (cs, &buffer, &buffer_len); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_ATTRIBUTE_ARRAY(attrs, n_attrs) \
+ _ret = proto_read_attribute_array (cs, &attrs, &n_attrs); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define IN_MECHANISM(mech) \
+ _ret = proto_read_mechanism (cs, &mech); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+
+#define OUT_ULONG(val) \
+ if (_ret == CKR_OK && !gck_rpc_message_write_ulong (cs->resp, val)) \
+ _ret = PREP_ERROR;
+
+#define OUT_BYTE_ARRAY(array, len) \
+ if (_ret == CKR_OK && !gck_rpc_message_write_byte_array (cs->resp, array, len)) \
+ _ret = PREP_ERROR;
+
+#define OUT_ULONG_ARRAY(array, len) \
+ if (_ret == CKR_OK && !gck_rpc_message_write_ulong_array (cs->resp, array, len)) \
+ _ret = PREP_ERROR;
+
+#define OUT_ATTRIBUTE_ARRAY(array, len) \
+ /* Note how we filter return codes */ \
+ _ret = proto_write_attribute_array (cs, array, len, _ret);
+
+#define OUT_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_info (cs, &val);
+
+#define OUT_SLOT_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_slot_info (cs, &val);
+
+#define OUT_TOKEN_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_token_info (cs, &val);
+
+#define OUT_MECHANISM_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_mechanism_info (cs, &val);
+
+#define OUT_SESSION_INFO(val) \
+ if (_ret == CKR_OK) \
+ _ret = proto_write_session_info (cs, &val);
+
+/* ---------------------------------------------------------------------------
+ * DISPATCH SPECIFIC CALLS
+ */
+
+static CK_RV
+rpc_C_Initialize (CallState *cs)
+{
+ CK_BYTE_PTR handshake;
+ CK_ULONG n_handshake;
+ CK_RV ret = CKR_OK;
+
+ debug (("C_Initialize: enter"));
+
+ assert (cs);
+ assert (pkcs11_module);
+
+ ret = proto_read_byte_array (cs, &handshake, &n_handshake);
+ if (ret == CKR_OK) {
+
+ /* Check to make sure the header matches */
+ if (n_handshake != GCK_RPC_HANDSHAKE_LEN ||
+ memcmp (handshake, GCK_RPC_HANDSHAKE, n_handshake) != 0) {
+ gck_rpc_warn ("invalid handshake received from connecting module");
+ ret = CKR_GENERAL_ERROR;
+ }
+
+ assert (gck_rpc_message_is_verified (cs->req));
+ }
+
+ if (ret == CKR_OK) {
+
+ pthread_mutex_lock (&init_mutex);
+
+ if (pkcs11_initialized == 0)
+ ret = pkcs11_module->C_Initialize (pkcs11_initialize_args);
+
+ if (ret == CKR_OK)
+ ++pkcs11_initialized;
+
+ pthread_mutex_unlock (&init_mutex);
+ }
+
+ debug (("ret: %d", ret));
+ return ret;
+}
+
+static CK_RV
+rpc_C_Finalize (CallState *cs)
+{
+ CK_RV ret;
+
+ debug (("C_Finalize: enter"));
+
+ assert (cs);
+ assert (pkcs11_module);
+
+ pthread_mutex_lock (&init_mutex);
+
+ if (pkcs11_initialized == 1)
+ ret = pkcs11_module->C_Finalize (NULL);
+
+ if (ret == CKR_OK)
+ --pkcs11_initialized;
+
+ pthread_mutex_unlock (&init_mutex);
+
+ debug (("ret: %d", ret));
+ return ret;
+}
+
+static CK_RV
+rpc_C_GetInfo (CallState *cs)
+{
+ CK_INFO info;
+
+ BEGIN_CALL (C_GetInfo);
+ PROCESS_CALL ((&info));
+ OUT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotList (CallState *cs)
+{
+ CK_BBOOL token_present;
+ CK_SLOT_ID_PTR slot_list;
+ CK_ULONG count;
+
+ BEGIN_CALL (C_GetSlotList);
+ IN_BYTE (token_present);
+ IN_ULONG_BUFFER (slot_list, count);
+ PROCESS_CALL ((token_present, slot_list, &count));
+ OUT_ULONG_ARRAY (slot_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSlotInfo (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_SLOT_INFO info;
+
+ BEGIN_CALL (C_GetSlotInfo);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((slot_id, &info));
+ OUT_SLOT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetTokenInfo (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_TOKEN_INFO info;
+
+ BEGIN_CALL (C_GetTokenInfo);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((slot_id, &info));
+ OUT_TOKEN_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismList (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_MECHANISM_TYPE_PTR mechanism_list;
+ CK_ULONG count;
+
+ BEGIN_CALL (C_GetMechanismList);
+ IN_ULONG (slot_id);
+ IN_ULONG_BUFFER (mechanism_list, count);
+ PROCESS_CALL ((slot_id, mechanism_list, &count));
+ OUT_ULONG_ARRAY (mechanism_list, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismInfo (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_MECHANISM_TYPE type;
+ CK_MECHANISM_INFO info;
+
+ BEGIN_CALL (C_GetMechanismInfo);
+ IN_ULONG (slot_id);
+ IN_ULONG (type);
+ PROCESS_CALL ((slot_id, type, &info));
+ OUT_MECHANISM_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitToken (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+ CK_UTF8CHAR_PTR label;
+
+ BEGIN_CALL (C_InitToken);
+ IN_ULONG (slot_id);
+ IN_BYTE_ARRAY (pin, pin_len);
+ IN_STRING (label);
+ PROCESS_CALL ((slot_id, pin, pin_len, label));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WaitForSlotEvent (CallState *cs)
+{
+ CK_FLAGS flags;
+ CK_SLOT_ID slot_id;
+
+ BEGIN_CALL (C_WaitForSlotEvent);
+ IN_ULONG (flags);
+ PROCESS_CALL ((flags, &slot_id, NULL));
+ OUT_ULONG (slot_id);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_OpenSession (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+ CK_FLAGS flags;
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_OpenSession);
+ IN_ULONG (slot_id);
+ IN_ULONG (flags);
+ PROCESS_CALL ((slot_id, flags, NULL, NULL, &session));
+ OUT_ULONG (session);
+ END_CALL;
+}
+
+
+static CK_RV
+rpc_C_CloseSession (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_CloseSession);
+ IN_ULONG (session);
+ PROCESS_CALL ((session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseAllSessions (CallState *cs)
+{
+ CK_SLOT_ID slot_id;
+
+ BEGIN_CALL (C_CloseAllSessions);
+ IN_ULONG (slot_id);
+ PROCESS_CALL ((slot_id));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetFunctionStatus (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_GetFunctionStatus);
+ IN_ULONG (session);
+ PROCESS_CALL ((session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CancelFunction (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_CancelFunction);
+ IN_ULONG (session);
+ PROCESS_CALL ((session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSessionInfo (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_SESSION_INFO info;
+
+ BEGIN_CALL (C_GetSessionInfo);
+ IN_ULONG (session);
+ PROCESS_CALL ((session, &info));
+ OUT_SESSION_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitPIN (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+
+ BEGIN_CALL (C_InitPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL ((session, pin, pin_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetPIN (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_UTF8CHAR_PTR old_pin;
+ CK_ULONG old_len;
+ CK_UTF8CHAR_PTR new_pin;
+ CK_ULONG new_len;
+
+ BEGIN_CALL (C_SetPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (old_pin, old_len);
+ IN_BYTE_ARRAY (new_pin, new_len);
+ PROCESS_CALL ((session, old_pin, old_len, new_pin, new_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetOperationState (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR operation_state;
+ CK_ULONG operation_state_len;
+
+ BEGIN_CALL (C_GetOperationState);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (operation_state, operation_state_len);
+ PROCESS_CALL ((session, operation_state, &operation_state_len));
+ OUT_BYTE_ARRAY (operation_state, operation_state_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetOperationState (CallState *cs)
+{
+ 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 (C_SetOperationState);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (operation_state, operation_state_len);
+ IN_ULONG (encryption_key);
+ IN_ULONG (authentication_key);
+ PROCESS_CALL ((session, operation_state, operation_state_len, encryption_key, authentication_key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Login (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_USER_TYPE user_type;
+ CK_UTF8CHAR_PTR pin;
+ CK_ULONG pin_len;
+
+ BEGIN_CALL (C_Login);
+ IN_ULONG (session);
+ IN_ULONG (user_type);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL ((session, user_type, pin, pin_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Logout (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_Logout);
+ IN_ULONG (session);
+ PROCESS_CALL ((session));
+ END_CALL;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT OPERATIONS
+ */
+
+static CK_RV
+rpc_C_CreateObject (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE new_object;
+
+ BEGIN_CALL (C_CreateObject);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((session, template, count, &new_object));
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CopyObject (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE new_object;
+
+ BEGIN_CALL (C_CopyObject);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((session, object, template, count, &new_object));
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DestroyObject (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+
+ BEGIN_CALL (C_DestroyObject);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL ((session, object));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetObjectSize (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ULONG size;
+
+ BEGIN_CALL (C_GetObjectSize);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL ((session, object, &size));
+ OUT_ULONG (size);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetAttributeValue (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (C_GetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_BUFFER (template, count);
+ PROCESS_CALL ((session, object, template, count));
+ OUT_ATTRIBUTE_ARRAY (template, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetAttributeValue (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (C_SetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((session, object, template, count));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+
+ BEGIN_CALL (C_FindObjectsInit);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((session, template, count));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjects (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE_PTR objects;
+ CK_ULONG max_object_count;
+ CK_ULONG object_count;
+
+ BEGIN_CALL (C_FindObjects);
+ IN_ULONG (session);
+ IN_ULONG_BUFFER (objects, max_object_count);
+ PROCESS_CALL ((session, objects, max_object_count, &object_count));
+ OUT_ULONG_ARRAY (objects, object_count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsFinal (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+
+ BEGIN_CALL (C_FindObjectsFinal);
+ IN_ULONG (session);
+ PROCESS_CALL ((session));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_EncryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+
+}
+
+static CK_RV
+rpc_C_Encrypt (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR encrypted_data;
+ CK_ULONG encrypted_data_len;
+
+ BEGIN_CALL (C_Encrypt);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (encrypted_data, encrypted_data_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (C_EncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR last_encrypted_part;
+ CK_ULONG last_encrypted_part_len;
+
+ BEGIN_CALL (C_EncryptFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_encrypted_part, last_encrypted_part_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_DecryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Decrypt (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_data;
+ CK_ULONG encrypted_data_len;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+
+ BEGIN_CALL (C_Decrypt);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_data, encrypted_data_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL ((session, encrypted_data, encrypted_data_len, data, &data_len));
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_DecryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DecryptFinal (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR last_part;
+ CK_ULONG last_part_len;
+
+ BEGIN_CALL (C_DecryptFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (last_part, last_part_len);
+ PROCESS_CALL ((session, last_part, &last_part_len));
+ OUT_BYTE_ARRAY (last_part, last_part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+
+ BEGIN_CALL (C_DigestInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ PROCESS_CALL ((session, &mechanism));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Digest (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR digest;
+ CK_ULONG digest_len;
+
+ BEGIN_CALL (C_Digest);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL ((session, data, data_len, digest, &digest_len));
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_DigestUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestKey (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_DigestKey);
+ IN_ULONG (session);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestFinal (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR digest;
+ CK_ULONG digest_len;
+
+ BEGIN_CALL (C_DigestFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (digest, digest_len);
+ PROCESS_CALL ((session, digest, &digest_len));
+ OUT_BYTE_ARRAY (digest, digest_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_SignInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Sign (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (C_Sign);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((session, part, part_len, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+
+}
+
+static CK_RV
+rpc_C_SignUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_SignUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignFinal (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (C_SignFinal);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((session, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecoverInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_SignRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecover (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (C_SignRecover);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_BUFFER (signature, signature_len);
+ PROCESS_CALL ((session, data, data_len, signature, &signature_len));
+ OUT_BYTE_ARRAY (signature, signature_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_VerifyInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Verify (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (C_Verify);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (data, data_len);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL ((session, data, data_len, signature, signature_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_VerifyUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL ((session, part, part_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyFinal (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+
+ BEGIN_CALL (C_VerifyFinal);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL ((session, signature, signature_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecoverInit (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_VerifyRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL ((session, &mechanism, key));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecover (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR signature;
+ CK_ULONG signature_len;
+ CK_BYTE_PTR data;
+ CK_ULONG data_len;
+
+ BEGIN_CALL (C_VerifyRecover);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ IN_BYTE_BUFFER (data, data_len);
+ PROCESS_CALL ((session, signature, signature_len, data, &data_len));
+ OUT_BYTE_ARRAY (data, data_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestEncryptUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (C_DigestEncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_DecryptDigestUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignEncryptUpdate (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+
+ BEGIN_CALL (C_SignEncryptUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ IN_BYTE_BUFFER (encrypted_part, encrypted_part_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR encrypted_part;
+ CK_ULONG encrypted_part_len;
+ CK_BYTE_PTR part;
+ CK_ULONG part_len;
+
+ BEGIN_CALL (C_DecryptVerifyUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (encrypted_part, encrypted_part_len);
+ IN_BYTE_BUFFER (part, part_len);
+ PROCESS_CALL ((session, encrypted_part, encrypted_part_len, part, &part_len));
+ OUT_BYTE_ARRAY (part, part_len);
+ END_CALL;
+}
+
+/* -----------------------------------------------------------------------------
+ * KEY OPERATIONS
+ */
+
+static CK_RV
+rpc_C_GenerateKey (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_ATTRIBUTE_PTR template;
+ CK_ULONG count;
+ CK_OBJECT_HANDLE key;
+
+ BEGIN_CALL (C_GenerateKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL ((session, &mechanism, template, count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateKeyPair (CallState *cs)
+{
+ 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 (C_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 ((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 (CallState *cs)
+{
+ 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 (C_WrapKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (wrapping_key);
+ IN_ULONG (key);
+ IN_BYTE_BUFFER (wrapped_key, wrapped_key_len);
+ PROCESS_CALL ((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 (CallState *cs)
+{
+ 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 (C_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 ((session, &mechanism, unwrapping_key, wrapped_key, wrapped_key_len, template, attribute_count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DeriveKey (CallState *cs)
+{
+ 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 (C_DeriveKey);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (base_key);
+ IN_ATTRIBUTE_ARRAY (template, attribute_count);
+ PROCESS_CALL ((session, &mechanism, base_key, template, attribute_count, &key));
+ OUT_ULONG (key);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SeedRandom (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR seed;
+ CK_ULONG seed_len;
+
+ BEGIN_CALL (C_SeedRandom);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (seed, seed_len);
+ PROCESS_CALL ((session, seed, seed_len));
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateRandom (CallState *cs)
+{
+ CK_SESSION_HANDLE session;
+ CK_BYTE_PTR random_data;
+ CK_ULONG random_len;
+
+ BEGIN_CALL (C_GenerateRandom);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (random_data, random_len);
+ PROCESS_CALL ((session, random_data, random_len));
+ OUT_BYTE_ARRAY (random_data, random_len);
+ END_CALL;
+}
+
+/* ---------------------------------------------------------------------------
+ * DISPATCH THREAD HANDLING
+ */
+
+static int
+dispatch_call (CallState *cs)
+{
+ GckRpcMessage *req, *resp;
+ CK_RV ret = CKR_OK;
+
+ assert (cs);
+
+ req = cs->req;
+ resp = cs->resp;
+
+ /* This should have been checked by the parsing code */
+ assert (req->call_id > GCK_RPC_CALL_ERROR);
+ assert (req->call_id < GCK_RPC_CALL_MAX);
+
+ /* Prepare a response for the function to fill in */
+ if (!gck_rpc_message_prep (resp, req->call_id, GCK_RPC_RESPONSE)) {
+ gck_rpc_warn ("couldn't prepare message");
+ return 0;
+ }
+
+ switch(req->call_id) {
+
+ #define CASE_CALL(name) \
+ case GCK_RPC_CALL_##name: \
+ ret = rpc_##name (cs); \
+ 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_WaitForSlotEvent)
+ CASE_CALL(C_OpenSession)
+ CASE_CALL(C_CloseSession)
+ CASE_CALL(C_CloseAllSessions)
+ CASE_CALL(C_GetFunctionStatus)
+ CASE_CALL(C_CancelFunction)
+ 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)
+ #undef CASE_CALL
+
+ default:
+ /* This should have been caught by the parse code */
+ assert (0 && "Unchecked call");
+ break;
+ };
+
+ if (ret == CKR_OK) {
+
+ /* Parsing errors? */
+ if (gck_rpc_message_buffer_error (req)) {
+ gck_rpc_warn ("invalid request from module, probably too short");
+ ret = PARSE_ERROR;
+ }
+
+ /* Out of memory errors? */
+ if (gck_rpc_message_buffer_error (resp)) {
+ gck_rpc_warn ("out of memory error putting together message");
+ ret = PREP_ERROR;
+ }
+ }
+
+ /* 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 (gck_rpc_message_is_verified (resp));
+ assert (resp->call_type == GCK_RPC_RESPONSE);
+ assert (resp->call_id == req->call_id);
+ assert (gck_rpc_calls[resp->call_id].response);
+ assert (strcmp (gck_rpc_calls[resp->call_id].response,
+ resp->signature) == 0);
+
+ /* Fill in an error respnose */
+ } else {
+ if (!gck_rpc_message_prep (resp, GCK_RPC_CALL_ERROR, GCK_RPC_RESPONSE) ||
+ !gck_rpc_message_write_ulong (resp, (uint32_t)ret) ||
+ gck_rpc_message_buffer_error (resp)) {
+ gck_rpc_warn ("out of memory responding with error");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+read_all (int sock, unsigned char* data, size_t len)
+{
+ int r;
+
+ assert (sock >= 0);
+ assert (data);
+ assert (len > 0);
+
+ while (len > 0) {
+
+ r = read (sock, data, len);
+
+ if (r == 0) {
+ /* Connection was closed on client */
+ return 0;
+ } else if (r == -1) {
+ if (errno != EAGAIN && errno != EINTR) {
+ gck_rpc_warn ("couldn't receive data: %s", strerror (errno));
+ return 0;
+ }
+ } else {
+ data += r;
+ len -= r;
+ }
+ }
+
+ return 1;
+}
+
+static int
+write_all (int sock, unsigned char* data, size_t len)
+{
+ int r;
+
+ assert (sock >= 0);
+ assert (data);
+ assert (len > 0);
+
+ while (len > 0) {
+
+ r = write (sock, data, len);
+
+ if (r == -1) {
+ if (errno == EPIPE) {
+ /* Connection closed from client */
+ return 0;
+ } else if (errno != EAGAIN && errno != EINTR) {
+ gck_rpc_warn ("couldn't send data: %s", strerror (errno));
+ return 0;
+ }
+ } else {
+ data += r;
+ len -= r;
+ }
+ }
+
+ return 1;
+}
+
+static void
+run_dispatch_loop (int sock)
+{
+ CallState cs;
+ unsigned char buf[4];
+ uint32_t len;
+
+ assert (sock != -1);
+
+ /* TODO: Read credentials */
+
+ /* Setup our buffers */
+ if (!call_init (&cs)) {
+ gck_rpc_warn ("out of memory");
+ return;
+ }
+
+ /* The main thread loop */
+ while (TRUE) {
+
+ call_reset (&cs);
+
+ /* Read the number of bytes ... */
+ if (!read_all (sock, buf, 4))
+ break;
+
+ /* Calculate the number of bytes */
+ len = gkr_buffer_decode_uint32 (buf);
+ if (len >= 0x0FFFFFFF) {
+ gck_rpc_warn ("invalid message size from module: %u bytes", len);
+ break;
+ }
+
+ /* Allocate memory */
+ gkr_buffer_reserve (&cs.req->buffer, cs.req->buffer.len + len);
+ if (gkr_buffer_has_error (&cs.req->buffer)) {
+ gck_rpc_warn ("error allocating buffer for message");
+ break;
+ }
+
+ /* ... and read/parse in the actual message */
+ if (!read_all (sock, cs.req->buffer.buf, len))
+ break;
+
+ gkr_buffer_add_empty (&cs.req->buffer, len);
+
+ if (!gck_rpc_message_parse (cs.req, GCK_RPC_REQUEST))
+ break;
+
+ /* ... send for processing ... */
+ if (!dispatch_call (&cs))
+ break;
+
+ /* .. send back response length, and then response data */
+ gkr_buffer_encode_uint32 (buf, cs.resp->buffer.len);
+ if(!write_all (sock, buf, 4) ||
+ !write_all (sock, cs.resp->buffer.buf, cs.resp->buffer.len))
+ break;
+ }
+
+ call_uninit (&cs);
+}
+
+static void*
+run_dispatch_thread (void *arg)
+{
+ int *sock = arg;
+ assert (*sock != -1);
+
+ /* Try and initialize the PKCS#11 module */
+ if (!pkcs11_initialized) {
+
+ }
+
+ run_dispatch_loop (*sock);
+
+ /* The thread closes the socket and marks as done */
+ assert (*sock != -1);
+ close (*sock);
+ *sock = -1;
+
+ return NULL;
+}
+
+/* ---------------------------------------------------------------------------
+ * MAIN THREAD
+ */
+
+typedef struct _DispatchState {
+ struct _DispatchState *next;
+ GThread *thread;
+ int socket;
+} DispatchState;
+
+/* The main daemon socket that we're listening on */
+static int pkcs11_socket = -1;
+
+/* The unix socket path, that we listen on */
+static char pkcs11_socket_path[MAXPATHLEN] = { 0, };
+
+/* A linked list of dispatcher threads */
+static DispatchState *pkcs11_dispatchers = NULL;
+
+
+void
+gck_rpc_dispatch_accept (void)
+{
+ struct sockaddr_un addr;
+ DispatchState *ds, **here;
+ GError *error = NULL;
+ socklen_t addrlen;
+ int new_fd;
+
+ assert (pkcs11_socket != -1);
+
+ /* Cleanup any completed dispatch threads */
+ for (here = &pkcs11_dispatchers, ds = *here; ds != NULL; ds = *here) {
+ if (ds->socket == -1) {
+ g_thread_join (ds->thread);
+ *here = ds->next;
+ free (ds);
+ } else {
+ here = &ds->next;
+ }
+ }
+
+ addrlen = sizeof (addr);
+ new_fd = accept (pkcs11_socket, (struct sockaddr*) &addr, &addrlen);
+ if (new_fd < 0) {
+ gck_rpc_warn ("cannot accept pkcs11 connection: %s", strerror (errno));
+ return;
+ }
+
+ ds = calloc (1, sizeof (DispatchState));
+ if (ds == NULL) {
+ gck_rpc_warn ("out of memory");
+ close (new_fd);
+ return;
+ }
+
+ ds->socket = new_fd;
+
+ ds->thread = g_thread_create (run_dispatch_thread, &(ds->socket), TRUE, &error);
+ if (!ds->thread) {
+ gck_rpc_warn ("couldn't start thread: %s", error && error->message ? error->message : "");
+ close (new_fd);
+ free (ds);
+ return;
+ }
+
+ ds->next = pkcs11_dispatchers;
+ pkcs11_dispatchers = ds;
+}
+
+int
+gck_rpc_dispatch_init (const char *socket_path, CK_FUNCTION_LIST_PTR module,
+ CK_C_INITIALIZE_ARGS_PTR init_args)
+{
+ struct sockaddr_un addr;
+ int sock;
+
+#ifdef _DEBUG
+ GCK_RPC_CHECK_CALLS ();
+#endif
+
+ assert (module);
+ assert (socket_path);
+
+ /* cannot be called more than once */
+ assert (!pkcs11_module);
+ assert (pkcs11_socket == -1);
+ assert (pkcs11_dispatchers == NULL);
+
+ snprintf (pkcs11_socket_path, sizeof (pkcs11_socket_path),
+ "%s", socket_path);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ gck_rpc_warn ("couldn't create pkcs11 socket: %s", strerror (errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, pkcs11_socket_path, sizeof (addr.sun_path));
+ if (bind (sock, (struct sockaddr*)&addr, sizeof (addr)) < 0) {
+ gck_rpc_warn ("couldn't bind to pkcs11 socket: %s: %s",
+ pkcs11_socket_path, strerror (errno));
+ return -1;
+ }
+
+ if (listen (sock, 128) < 0) {
+ gck_rpc_warn ("couldn't listen on pkcs11 socket: %s: %s",
+ pkcs11_socket_path, strerror (errno));
+ return -1;
+ }
+
+ pkcs11_module = module;
+ pkcs11_initialize_args = init_args;
+ pkcs11_socket = sock;
+ pkcs11_dispatchers = NULL;
+
+ return sock;
+}
+
+void
+gck_rpc_dispatch_uninit (void)
+{
+ DispatchState *ds, *next;
+
+ if (!pkcs11_module)
+ return;
+
+ /* Close our main listening socket */
+ if (pkcs11_socket != -1)
+ close (pkcs11_socket);
+ pkcs11_socket = -1;
+
+ /* Delete our unix socket */
+ if(pkcs11_socket_path[0])
+ unlink (pkcs11_socket_path);
+ pkcs11_socket_path[0] = 0;
+
+ /* Stop all of the dispatch threads */
+ for (ds = pkcs11_dispatchers; ds; ds = next) {
+ next = ds->next;
+
+ /* Forcibly shutdown the connection */
+ if (ds->socket)
+ shutdown (ds->socket, SHUT_RDWR);
+ g_thread_join (ds->thread);
+
+ /* This is always closed by dispatch thread */
+ assert (ds->socket == -1);
+ free (ds);
+ }
+
+ pkcs11_module = NULL;
+ pkcs11_initialize_args = NULL;
+}
Added: trunk/pkcs11/rpc-layer/gck-rpc-layer.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-layer.h Sun Jan 4 23:07:18 2009
@@ -0,0 +1,21 @@
+#ifndef GCKRPC_H_
+#define GCKRPC_H_
+
+#include "pkcs11/pkcs11.h"
+
+/* ------------------------------------------------------------------
+ * DISPATCHER
+ */
+
+/* Call to initialize the module and start listening, returns socket or -1 */
+int gck_rpc_dispatch_init (const char *socket_prefix,
+ CK_FUNCTION_LIST_PTR module,
+ CK_C_INITIALIZE_ARGS_PTR init_args);
+
+/* Should be called to cleanup dispatcher */
+void gck_rpc_dispatch_uninit (void);
+
+/* Accept a new connection. Should be called when above fd has read */
+void gck_rpc_dispatch_accept (void);
+
+#endif /* GCKRPC_H_ */
Added: trunk/pkcs11/rpc-layer/gck-rpc-message.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-message.c Sun Jan 4 23:07:18 2009
@@ -0,0 +1,469 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* p11-rpc-message.c - our marshalled PKCS#11 protocol.
+
+ Copyright (C) 2008, Stef Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-rpc-layer.h"
+#include "gck-rpc-private.h"
+
+#include <string.h>
+
+#ifdef G_DISABLE_ASSERT
+#define assert(x)
+#else
+#include <assert.h>
+#endif
+
+GckRpcMessage*
+gck_rpc_message_new (GkrBufferAllocator allocator)
+{
+ GckRpcMessage *msg;
+
+ assert (allocator);
+
+ msg = (GckRpcMessage*) (allocator)(NULL, sizeof (GckRpcMessage));
+ if (!msg)
+ return NULL;
+ memset (msg, 0, sizeof (*msg));
+
+ if (!gkr_buffer_init_full (&msg->buffer, 64, allocator)) {
+ (allocator) (msg, 0); /* Frees allocation */
+ return NULL;
+ }
+
+ gck_rpc_message_reset (msg);
+
+ return msg;
+}
+
+void
+gck_rpc_message_free (GckRpcMessage *msg)
+{
+ GkrBufferAllocator allocator;
+
+ if (msg) {
+ assert (msg->buffer.allocator);
+ allocator = msg->buffer.allocator;
+ gkr_buffer_uninit (&msg->buffer);
+
+ /* frees data buffer */
+ (allocator) (msg, 0);
+ }
+}
+
+void
+gck_rpc_message_reset (GckRpcMessage *msg)
+{
+ assert (msg);
+
+ msg->call_id = 0;
+ msg->call_type = 0;
+ msg->signature = NULL;
+ msg->sigverify = NULL;
+ msg->parsed = 0;
+
+ gkr_buffer_reset (&msg->buffer);
+}
+
+int
+gck_rpc_message_prep (GckRpcMessage *msg, int call_id, GckRpcMessageType type)
+{
+ int len;
+
+ assert (type);
+ assert (call_id >= GCK_RPC_CALL_ERROR);
+ assert (call_id < GCK_RPC_CALL_MAX);
+
+ gck_rpc_message_reset (msg);
+
+ if (call_id != GCK_RPC_CALL_ERROR) {
+
+ /* The call id and signature */
+ if (type == GCK_RPC_REQUEST)
+ msg->signature = gck_rpc_calls[call_id].request;
+ else if (type == GCK_RPC_RESPONSE)
+ msg->signature = gck_rpc_calls[call_id].response;
+ else
+ assert (0 && "invalid message type");
+ msg->sigverify = msg->signature;
+ }
+
+ msg->call_id = call_id;
+ msg->call_type = type;
+
+ /* Encode the two of them */
+ gkr_buffer_add_uint32 (&msg->buffer, call_id);
+ if (msg->signature) {
+ len = strlen (msg->signature);
+ gkr_buffer_add_byte_array (&msg->buffer, (unsigned char*)msg->signature, len);
+ }
+
+ msg->parsed = 0;
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_parse (GckRpcMessage *msg, GckRpcMessageType type)
+{
+ const unsigned char *val;
+ size_t len;
+ uint32_t call_id;
+
+ msg->parsed = 0;
+
+ /* Pull out the call identifier */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &(msg->parsed), &call_id)) {
+ gck_rpc_warn ("invalid message: couldn't read call identifier");
+ return 0;
+ }
+
+ msg->signature = msg->sigverify = NULL;
+
+ /* If it's an error code then no more processing */
+ if (call_id == GCK_RPC_CALL_ERROR) {
+ if (type == GCK_RPC_REQUEST) {
+ gck_rpc_warn ("invalid message: error code in request");
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* The call id and signature */
+ if (call_id <= 0 || call_id >= GCK_RPC_CALL_MAX) {
+ gck_rpc_warn ("invalid message: bad call id: %d", call_id);
+ return 0;
+ }
+ if (type == GCK_RPC_REQUEST)
+ msg->signature = gck_rpc_calls[call_id].request;
+ else if (type == GCK_RPC_RESPONSE)
+ msg->signature = gck_rpc_calls[call_id].response;
+ else
+ assert (0 && "invalid message type");
+ msg->call_id = call_id;
+ msg->call_type = type;
+ msg->sigverify = msg->signature;
+
+ /* Verify the incoming signature */
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &(msg->parsed), &val, &len)) {
+ gck_rpc_warn ("invalid message: couldn't read signature");
+ return 0;
+ }
+
+ if ((strlen (msg->signature) != len) || (memcmp (val, msg->signature, len) != 0)) {
+ gck_rpc_warn ("invalid message: signature doesn't match");
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+gck_rpc_message_equals (GckRpcMessage *m1, GckRpcMessage *m2)
+{
+ assert (m1 && m2);
+
+ /* Any errors and messages are never equal */
+ if (gkr_buffer_has_error (&m1->buffer) ||
+ gkr_buffer_has_error (&m2->buffer))
+ return 0;
+
+ /* Calls and signatures must be identical */
+ if (m1->call_id != m2->call_id)
+ return 0;
+ if (m1->call_type != m2->call_type)
+ return 0;
+ if (m1->signature && m2->signature) {
+ if (strcmp (m1->signature, m2->signature) != 0)
+ return 0;
+ } else if (m1->signature != m2->signature) {
+ return 0;
+ }
+
+ /* Data in buffer must be identical */
+ return gkr_buffer_equal (&m1->buffer, &m2->buffer);
+}
+
+int
+gck_rpc_message_verify_part (GckRpcMessage *msg, const char* part)
+{
+ int len, ok;
+
+ if (!msg->sigverify)
+ return 1;
+
+ len = strlen (part);
+ ok = (strncmp (msg->sigverify, part, len) == 0);
+ if (ok)
+ msg->sigverify += len;
+ return ok;
+}
+
+int
+gck_rpc_message_write_attribute_buffer (GckRpcMessage *msg, CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num)
+{
+ CK_ATTRIBUTE_PTR attr;
+ CK_ULONG i;
+
+ assert (!num || arr);
+ assert (msg);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "fA"));
+
+ /* Write the number of items */
+ gkr_buffer_add_uint32 (&msg->buffer, num);
+
+ for (i = 0; i < num; ++i) {
+ attr = &(arr[i]);
+
+ /* The attribute type */
+ gkr_buffer_add_uint32 (&msg->buffer, attr->type);
+
+ /* And the attribute buffer length */
+ gkr_buffer_add_uint32 (&msg->buffer, attr->pValue ? attr->ulValueLen : 0);
+ }
+
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_write_attribute_array (GckRpcMessage *msg,
+ CK_ATTRIBUTE_PTR arr, CK_ULONG num)
+{
+ CK_ULONG i;
+ CK_ATTRIBUTE_PTR attr;
+ unsigned char validity;
+
+ assert (!num || arr);
+ assert (msg);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "aA"));
+
+ /* Write the number of items */
+ gkr_buffer_add_uint32 (&msg->buffer, num);
+
+ for (i = 0; i < num; ++i) {
+ attr = &(arr[i]);
+
+ /* The attribute type */
+ gkr_buffer_add_uint32 (&msg->buffer, attr->type);
+
+ /* Write out the attribute validity */
+ validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1;
+ gkr_buffer_add_byte (&msg->buffer, validity);
+
+ /* The attribute value */
+ if (validity)
+ gkr_buffer_add_byte_array (&msg->buffer, attr->pValue, attr->ulValueLen);
+ }
+
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_read_byte (GckRpcMessage *msg, CK_BYTE *val)
+{
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "y"));
+ return gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, val);
+}
+
+int
+gck_rpc_message_write_byte (GckRpcMessage *msg, CK_BYTE val)
+{
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "y"));
+ return gkr_buffer_add_byte (&msg->buffer, val);
+}
+
+int
+gck_rpc_message_read_ulong (GckRpcMessage *msg, CK_ULONG *val)
+{
+ uint32_t v;
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "u"));
+
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &v))
+ return 0;
+ if (val)
+ *val = v;
+ return 1;
+}
+
+int
+gck_rpc_message_write_ulong (GckRpcMessage *msg, CK_ULONG val)
+{
+ assert (msg);
+
+ /* Make sure this is in the rigth order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "u"));
+ return gkr_buffer_add_uint32 (&msg->buffer, val);
+}
+
+int
+gck_rpc_message_write_byte_buffer (GckRpcMessage *msg, CK_ULONG count)
+{
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "fy"));
+ return gkr_buffer_add_uint32 (&msg->buffer, count);
+}
+
+int
+gck_rpc_message_write_byte_array (GckRpcMessage *msg, CK_BYTE_PTR arr, CK_ULONG num)
+{
+ assert (msg);
+ assert (!num || arr);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "ay"));
+
+ /* No array, no data, just length */
+ if (!arr) {
+ gkr_buffer_add_byte (&msg->buffer, 0);
+ gkr_buffer_add_uint32 (&msg->buffer, num);
+ } else {
+ gkr_buffer_add_byte (&msg->buffer, 1);
+ gkr_buffer_add_byte_array (&msg->buffer, arr, num);
+ }
+
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_write_ulong_buffer (GckRpcMessage *msg, CK_ULONG count)
+{
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "fu"));
+ return gkr_buffer_add_uint32 (&msg->buffer, count);
+}
+
+int
+gck_rpc_message_write_ulong_array (GckRpcMessage *msg, CK_ULONG_PTR array, CK_ULONG n_array)
+{
+ CK_ULONG i;
+
+ assert (msg);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "au"));
+
+ /* We send a byte which determines whether there's actual data present or not */
+ gkr_buffer_add_byte (&msg->buffer, array ? 1 : 0);
+ gkr_buffer_add_uint32 (&msg->buffer, n_array);
+
+ /* Now send the data if valid */
+ if (array) {
+ for (i = 0; i < n_array; ++i)
+ gkr_buffer_add_uint32 (&msg->buffer, array[i]);
+ }
+
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_read_version (GckRpcMessage *msg, CK_VERSION* version)
+{
+ assert (msg);
+ assert (version);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "v"));
+
+ return gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &version->major) &&
+ gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &version->minor);
+}
+
+int
+gck_rpc_message_write_version (GckRpcMessage *msg, CK_VERSION* version)
+{
+ assert (msg);
+ assert (version);
+
+ /* Check that we're supposed to have this at this point */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "v"));
+
+ gkr_buffer_add_byte (&msg->buffer, version->major);
+ gkr_buffer_add_byte (&msg->buffer, version->minor);
+
+ return !gkr_buffer_has_error (&msg->buffer);
+}
+
+int
+gck_rpc_message_read_space_string (GckRpcMessage *msg, CK_UTF8CHAR* buffer, CK_ULONG length)
+{
+ const unsigned char *data;
+ size_t n_data;
+
+ assert (msg);
+ assert (buffer);
+ assert (length);
+
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "s"));
+
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &msg->parsed, &data, &n_data))
+ return 0;
+
+ if (n_data != length) {
+ gck_rpc_warn ("invalid length space padded string received: %d != %d", length, n_data);
+ return 0;
+ }
+
+ memcpy (buffer, data, length);
+ return 1;
+}
+
+int
+gck_rpc_message_write_space_string (GckRpcMessage *msg, CK_UTF8CHAR* buffer, CK_ULONG length)
+{
+ assert (msg);
+ assert (buffer);
+ assert (length);
+
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "s"));
+
+ return gkr_buffer_add_byte_array (&msg->buffer, buffer, length);
+}
+
+int
+gck_rpc_message_write_zero_string (GckRpcMessage *msg, CK_UTF8CHAR* string)
+{
+ assert (msg);
+ assert (string);
+
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "z"));
+
+ return gkr_buffer_add_string (&msg->buffer, (const char*)string);
+}
Added: trunk/pkcs11/rpc-layer/gck-rpc-module.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-module.c Sun Jan 4 23:07:18 2009
@@ -0,0 +1,2103 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pkcs11-rpc-module.c - a PKCS#11 module which communicates with another process
+
+ Copyright (C) 2008, Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-rpc-layer.h"
+#include "gck-rpc-private.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+/* -------------------------------------------------------------------
+ * GLOBALS / DEFINES
+ */
+
+/* Various mutexes */
+static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Our per thread key */
+static pthread_key_t pkcs11_per_thread = 0;
+
+/* Whether we've been initialized, and on what process id it happened */
+static int pkcs11_initialized = 0;
+static pid_t pkcs11_initialized_pid = 0;
+
+/* The socket to connect to */
+static char pkcs11_socket_path[MAXPATHLEN] = { 0, };
+
+/* The error used by us when parsing of rpc message fails */
+#define PARSE_ERROR CKR_DEVICE_ERROR
+
+/* -----------------------------------------------------------------------------
+ * LOGGING and DEBUGGING
+ */
+
+#if DEBUG_OUTPUT
+#define debug(x) gck_rpc_debug x
+#else
+#define debug(x)
+#endif
+#define warning(x) gck_rpc_warn x
+
+#define return_val_if_fail(x, v) \
+ if (!(x)) { gck_rpc_warn ("'%s' not true at %s", #x, __func__); return v; }
+
+void
+gck_rpc_log (const char *line)
+{
+ fprintf (stderr, "%s\n", line);
+}
+
+/* -----------------------------------------------------------------------------
+ * CALL SESSION
+ */
+
+enum CallStatus {
+ CALL_INVALID,
+ CALL_READY,
+ CALL_PREP,
+ CALL_TRANSIT,
+ CALL_PARSE
+};
+
+typedef struct _CallState {
+ int socket; /* The connection we're sending on */
+ GckRpcMessage *req; /* The current request */
+ GckRpcMessage *resp; /* The current response */
+ int call_status;
+} CallState;
+
+/* Allocator for call session buffers */
+static void*
+call_allocator (void* p, unsigned long sz)
+{
+ void* res = realloc (p, (size_t)sz);
+ if (!res && sz)
+ warning (("memory allocation of %lu bytes failed", sz));
+ return res;
+}
+
+static CK_RV
+call_connect (CallState *cs)
+{
+ struct sockaddr_un addr;
+ int sock;
+
+ assert (cs);
+ assert (cs->socket == -1);
+ assert (cs->call_status == CALL_INVALID);
+ assert (pkcs11_socket_path[0]);
+
+ debug (("connecting to: %s", pkcs11_socket_path));
+
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, pkcs11_socket_path, sizeof (addr.sun_path));
+
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ warning (("couldn't open socket: %s", strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+
+ /* close on exec */
+ if (fcntl (sock, F_SETFD, 1) == -1) {
+ close (sock);
+ warning (("couldn't secure socket: %s", strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+
+ if (connect (sock, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
+ close (sock);
+ warning (("couldn't connect to: %s: %s", pkcs11_socket_path, strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+
+ /* TODO: Write credentials */
+#if 0
+ if (!gck_rpc_write_credentials (sock)) {
+ close (sock);
+ warning (("couldn't send socket credentials: %s", strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+#endif
+
+ cs->socket = sock;
+ cs->call_status = CALL_READY;
+ debug (("connected socket"));
+
+ return CKR_OK;
+}
+
+static void
+call_disconnect (CallState *cs)
+{
+ assert (cs);
+
+ if (cs->socket != -1) {
+ debug (("disconnected socket"));
+ close (cs->socket);
+ cs->socket = -1;
+ }
+}
+
+static void
+call_destroy (void *value)
+{
+ CallState *cs = value;
+
+ if (value) {
+ call_disconnect (cs);
+ assert (cs->socket == -1);
+
+ gck_rpc_message_free (cs->req);
+ gck_rpc_message_free (cs->resp);
+
+ free (cs);
+
+ debug (("destroyed state"));
+ }
+}
+
+static CK_RV
+call_create (void)
+{
+ CallState *cs;
+
+ assert (pkcs11_per_thread);
+
+ cs = calloc(1, sizeof (CallState));
+ if (!cs)
+ return CKR_HOST_MEMORY;
+ cs->socket = -1;
+ cs->call_status = CALL_INVALID;
+
+ assert (!pthread_getspecific (pkcs11_per_thread));
+ pthread_setspecific (pkcs11_per_thread, cs);
+
+ return CKR_OK;
+}
+
+static CK_RV
+call_lookup (CallState **ret)
+{
+ CallState *cs;
+ CK_RV rv;
+
+ assert (ret);
+ assert (pkcs11_per_thread);
+
+ cs = pthread_getspecific (pkcs11_per_thread);
+ if (cs == NULL) {
+ rv = call_create ();
+ if (rv != CKR_OK)
+ return rv;
+
+ cs = pthread_getspecific (pkcs11_per_thread);
+ assert (cs);
+ }
+
+ if (cs->call_status == CALL_INVALID) {
+ rv = call_connect (cs);
+ if (rv != CKR_OK)
+ return rv;
+ }
+
+ assert (cs->call_status == CALL_READY);
+ assert (cs->socket != -1);
+ *ret = cs;
+ return CKR_OK;
+}
+
+/* Perform the initial setup for a new call. */
+static CK_RV
+call_prepare (CallState *cs, int call_id)
+{
+ assert (cs);
+ assert (cs->call_status == CALL_READY);
+
+ /* Allocate a new request if we've lost the old one */
+ if (!cs->req) {
+ cs->req = gck_rpc_message_new (call_allocator);
+ if (!cs->req) {
+ warning (("cannot allocate request buffer: out of memory"));
+ return CKR_HOST_MEMORY;
+ }
+ }
+
+ /* Put in the Call ID and signature */
+ gck_rpc_message_reset (cs->req);
+ if (!gck_rpc_message_prep (cs->req, call_id, GCK_RPC_REQUEST))
+ return CKR_HOST_MEMORY;
+
+ debug (("prepared call: %d", call_id));
+
+ /* Ready to fill in arguments */
+ cs->call_status = CALL_PREP;
+ return CKR_OK;
+}
+
+/* Write all data to session socket. */
+static CK_RV
+call_write (CallState *cs, unsigned char* data, size_t len)
+{
+ int fd, r;
+
+ assert (cs);
+ assert (data);
+ assert (len > 0);
+
+ while (len > 0) {
+
+ fd = cs->socket;
+ if (fd == -1) {
+ warning (("couldn't send data: socket has been closed"));
+ return CKR_DEVICE_ERROR;
+ }
+
+ r = write (fd, data, len);
+
+ if (r == -1) {
+ if (errno == EPIPE) {
+ warning (("couldn't send data: daemon closed connection"));
+ call_disconnect (cs);
+ return CKR_DEVICE_ERROR;
+ } else if (errno != EAGAIN && errno != EINTR) {
+ warning (("couldn't send data: %s", strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+ } else {
+ debug (("wrote %d bytes", r));
+ data += r;
+ len -= r;
+ }
+ }
+
+ return CKR_OK;
+}
+
+/* Read a certain amount of data from session socket. */
+static CK_RV
+call_read (CallState *cs, unsigned char* data, size_t len)
+{
+ int fd, r;
+
+ assert (cs);
+ assert (data);
+ assert (len > 0);
+
+ while (len > 0) {
+
+ fd = cs->socket;
+ if (fd == -1) {
+ warning (("couldn't receive data: session socket has been closed"));
+ return CKR_DEVICE_ERROR;
+ }
+
+ r = read (fd, data, len);
+
+ if (r == 0) {
+ warning (("couldn't receive data: daemon closed connection"));
+ call_disconnect (cs);
+ return CKR_DEVICE_ERROR;
+ } else if (r == -1) {
+ if (errno != EAGAIN && errno != EINTR) {
+ warning (("couldn't receive data: %s", strerror (errno)));
+ return CKR_DEVICE_ERROR;
+ }
+ } else {
+ debug (("read %d bytes", r));
+ data += r;
+ len -= r;
+ }
+ }
+
+ return CKR_OK;
+}
+
+/*
+ * Used by call_session_do_call() to actually send the message to the daemon.
+ * Note how we unlock and relock the session during the call.
+ */
+static CK_RV
+call_send_recv (CallState *cs)
+{
+ GckRpcMessage *req, *resp;
+ unsigned char buf[4];
+ uint32_t len;
+ CK_RV ret;
+
+ assert (cs);
+ assert (cs->req);
+ assert (cs->call_status == CALL_PREP);
+
+ cs->call_status = CALL_TRANSIT;
+
+ /* Setup the response buffer properly */
+ if (!cs->resp) {
+ /* TODO: Do secrets or passwords ever flow through here? */
+ cs->resp = gck_rpc_message_new (call_allocator);
+ if (!cs->resp) {
+ warning (("couldn't allocate response buffer: out of memory"));
+ return CKR_HOST_MEMORY;
+ }
+ }
+ gck_rpc_message_reset (cs->resp);
+
+ /*
+ * Now as an additional check to make sure nothing nasty will
+ * happen while we are unlocked, we remove the request and
+ * response from the session during the action.
+ */
+ req = cs->req;
+ resp = cs->resp;
+ cs->req = cs->resp = NULL;
+
+ /* Send the number of bytes, and then the data */
+ gkr_buffer_encode_uint32 (buf, req->buffer.len);
+ ret = call_write (cs, buf, 4);
+ if (ret != CKR_OK)
+ goto cleanup;
+ ret = call_write (cs, req->buffer.buf, req->buffer.len);
+ if (ret != CKR_OK)
+ goto cleanup;
+
+ /* Now read out the number of bytes, and then the data */
+ ret = call_read (cs, buf, 4);
+ if (ret != CKR_OK)
+ goto cleanup;
+ len = gkr_buffer_decode_uint32 (buf);
+ if (!gkr_buffer_reserve (&resp->buffer, len + resp->buffer.len)) {
+ warning (("couldn't allocate %u byte response area: out of memory", len));
+ ret = CKR_HOST_MEMORY;
+ goto cleanup;
+ }
+ ret = call_read (cs, resp->buffer.buf, len);
+ if (ret != CKR_OK)
+ goto cleanup;
+
+ gkr_buffer_add_empty (&resp->buffer, len);
+ if (!gck_rpc_message_parse (resp, GCK_RPC_RESPONSE))
+ goto cleanup;
+
+ debug (("received response from daemon"));
+
+cleanup:
+ /* Make sure nobody else used this thread while unlocked */
+ assert (cs->call_status == CALL_TRANSIT);
+ assert (cs->resp == NULL);
+ cs->resp = resp;
+ assert (cs->req == NULL);
+ cs->req = req;
+
+ return ret;
+}
+
+/*
+ * At this point the request is ready. So we validate it, and we send it to
+ * the daemon for a response.
+ */
+static CK_RV
+call_run (CallState *cs)
+{
+ CK_RV ret = CKR_OK;
+ CK_ULONG ckerr;
+
+ assert (cs);
+ assert (cs->req);
+ assert (cs->call_status == CALL_PREP);
+ assert (cs->socket != -1);
+
+ /* Did building the call fail? */
+ if (gck_rpc_message_buffer_error (cs->req)) {
+ warning (("couldn't allocate request area: out of memory"));
+ return CKR_HOST_MEMORY;
+ }
+
+ /* Make sure that the signature is valid */
+ assert (gck_rpc_message_is_verified (cs->req));
+
+ /* Do the dialog with daemon */
+ ret = call_send_recv (cs);
+
+ cs->call_status = CALL_PARSE;
+
+ if (ret != CKR_OK)
+ return ret;
+
+ /* If it's an error code then return it */
+ if (cs->resp->call_id == GCK_RPC_CALL_ERROR) {
+
+ if (!gck_rpc_message_read_ulong (cs->resp, &ckerr)) {
+ warning (("invalid error response from gnome-keyring-daemon: too short"));
+ return CKR_DEVICE_ERROR;
+ }
+
+ if (ckerr <= CKR_OK) {
+ warning (("invalid error response from gnome-keyring-daemon: bad error code"));
+ return CKR_DEVICE_ERROR;
+ }
+
+ /* An error code from the daemon */
+ return (CK_RV)ckerr;
+ }
+
+ /* Make sure daemon answered the right call */
+ if (cs->req->call_id != cs->resp->call_id) {
+ warning (("invalid response from gnome-keyring-daemon: call mismatch"));
+ return CKR_DEVICE_ERROR;
+ }
+
+ assert (!gck_rpc_message_buffer_error (cs->resp));
+ debug (("parsing response values"));
+
+ return CKR_OK;
+}
+
+static CK_RV
+call_done (CallState *cs, CK_RV ret)
+{
+ assert (cs);
+ assert (cs->call_status > CALL_INVALID);
+
+ if (cs->call_status == CALL_PARSE && cs->req && cs->resp) {
+
+ /* Check for parsing errors that were not caught elsewhere */
+ if (ret == CKR_OK) {
+
+ if (gck_rpc_message_buffer_error (cs->resp)) {
+ warning (("invalid response from gnome-keyring-daemon: bad argument data"));
+ return CKR_GENERAL_ERROR;
+ }
+
+ /* Double check that the signature matched our decoding */
+ assert (gck_rpc_message_is_verified (cs->resp));
+ }
+ }
+
+ /* Some cleanup */
+ if (cs->socket == -1)
+ cs->call_status = CALL_INVALID;
+ else
+ cs->call_status = CALL_READY;
+
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * MODULE SPECIFIC PROTOCOL CODE
+ */
+
+static CK_RV
+proto_read_attribute_array (GckRpcMessage *msg, CK_ATTRIBUTE_PTR arr, CK_ULONG len)
+{
+ uint32_t i, num, val;
+ CK_ATTRIBUTE_PTR attr;
+ const unsigned char *attrval;
+ size_t attrlen;
+ unsigned char validity;
+ CK_RV ret;
+
+ assert (len);
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "aA"));
+
+ /* Get the number of items. We need this value to be correct */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &num))
+ return PARSE_ERROR;
+
+ if (len != num) {
+
+ /*
+ * 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.
+ */
+
+ warning (("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 */
+ gkr_buffer_get_uint32 (&msg->buffer, msg->parsed,
+ &msg->parsed, &val);
+
+ /* Attribute validity */
+ gkr_buffer_get_byte (&msg->buffer, msg->parsed,
+ &msg->parsed, &validity);
+
+ /* And the data itself */
+ if (validity)
+ gkr_buffer_get_byte_array (&msg->buffer, msg->parsed,
+ &msg->parsed, &attrval, &attrlen);
+
+ /* Don't act on this data unless no errors */
+ if (gkr_buffer_has_error (&msg->buffer))
+ break;
+
+ /* Try and stuff it in the output data */
+ if (arr) {
+ attr = &(arr[i]);
+ attr->type = val;
+
+ 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);
+ }
+ }
+ }
+
+ return gkr_buffer_has_error (&msg->buffer) ? PARSE_ERROR : ret;
+}
+
+static CK_RV
+proto_read_byte_array (GckRpcMessage *msg, CK_BYTE_PTR arr,
+ CK_ULONG_PTR len, CK_ULONG max)
+{
+ const unsigned char *val;
+ unsigned char valid;
+ size_t vlen;
+
+ assert (len);
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "ay"));
+
+ /* A single byte which determines whether valid or not */
+ if (!gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ /* If not valid, then just the length is encoded */
+ if (!valid) {
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &vlen))
+ return PARSE_ERROR;
+
+ if (arr) {
+
+ /*
+ * This should never happen in normal operation. It denotes a goof up
+ * on the other side of our RPC. We should be sending an empty buffer
+ * only in the case where there's no array to be filled, which is what
+ * indicates the other side to reply with an invalid array.
+ */
+
+ warning (("received an invalid array, but caller expected filled"));
+ return PARSE_ERROR;
+ }
+
+ /* Just return the length */
+ *len = vlen;
+ return CKR_OK;
+ }
+
+ /* Get the actual bytes */
+ if (!gkr_buffer_get_byte_array (&msg->buffer, msg->parsed, &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 (GckRpcMessage *msg, CK_ULONG_PTR arr,
+ CK_ULONG_PTR len, CK_ULONG max)
+{
+ uint32_t i, num, val;
+ unsigned char valid;
+
+ assert (len);
+ assert (msg);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "au"));
+
+ /* A single byte which determines whether valid or not */
+ if (!gkr_buffer_get_byte (&msg->buffer, msg->parsed, &msg->parsed, &valid))
+ return PARSE_ERROR;
+
+ /* Get the number of items. */
+ if (!gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &num))
+ return PARSE_ERROR;
+
+ *len = num;
+
+ if (!valid) {
+
+ if (arr) {
+
+ /*
+ * This should never happen in normal operation. It denotes a goof up
+ * on the other side of our RPC. We should be sending an empty buffer
+ * only in the case where there's no array to be filled, which is what
+ * indicates the other side to reply with an invalid array.
+ */
+
+ warning (("received an invalid array, but caller expected filled"));
+ return PARSE_ERROR;
+ }
+
+ 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) {
+ gkr_buffer_get_uint32 (&msg->buffer, msg->parsed, &msg->parsed, &val);
+ if (arr)
+ arr[i] = val;
+ }
+
+ return gkr_buffer_has_error (&msg->buffer) ? PARSE_ERROR : CKR_OK;
+}
+
+static CK_RV
+proto_write_mechanism (GckRpcMessage *msg, CK_MECHANISM_PTR mech)
+{
+ assert (msg);
+ assert (mech);
+
+ /* Make sure this is in the right order */
+ assert (!msg->signature || gck_rpc_message_verify_part (msg, "M"));
+
+ /* The mechanism type */
+ gkr_buffer_add_uint32 (&msg->buffer, 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 (gck_rpc_mechanism_has_no_parameters (mech->mechanism))
+ gkr_buffer_add_byte_array (&msg->buffer, NULL, 0);
+ else if (gck_rpc_mechanism_has_sane_parameters (mech->mechanism))
+ gkr_buffer_add_byte_array (&msg->buffer, mech->pParameter,
+ mech->ulParameterLen);
+ else
+ return CKR_MECHANISM_INVALID;
+
+ return gkr_buffer_has_error (&msg->buffer) ? CKR_HOST_MEMORY : CKR_OK;
+}
+
+static CK_RV
+proto_read_info (GckRpcMessage *msg, CK_INFO_PTR info)
+{
+ assert (msg);
+ assert (info);
+
+ if (!gck_rpc_message_read_version (msg, &info->cryptokiVersion) ||
+ !gck_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_read_ulong (msg, &info->flags) ||
+ !gck_rpc_message_read_space_string (msg, info->libraryDescription, 32) ||
+ !gck_rpc_message_read_version (msg, &info->libraryVersion))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_slot_info (GckRpcMessage *msg, CK_SLOT_INFO_PTR info)
+{
+ assert (msg);
+ assert (info);
+
+ if (!gck_rpc_message_read_space_string (msg, info->slotDescription, 64) ||
+ !gck_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_read_ulong (msg, &info->flags) ||
+ !gck_rpc_message_read_version (msg, &info->hardwareVersion) ||
+ !gck_rpc_message_read_version (msg, &info->firmwareVersion))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_token_info (GckRpcMessage *msg, CK_TOKEN_INFO_PTR info)
+{
+ assert (msg);
+ assert (info);
+
+ if (!gck_rpc_message_read_space_string (msg, info->label, 32) ||
+ !gck_rpc_message_read_space_string (msg, info->manufacturerID, 32) ||
+ !gck_rpc_message_read_space_string (msg, info->model, 16) ||
+ !gck_rpc_message_read_space_string (msg, info->serialNumber, 16) ||
+ !gck_rpc_message_read_ulong (msg, &info->flags) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulMaxSessionCount) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulSessionCount) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulMaxRwSessionCount) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulRwSessionCount) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulMaxPinLen) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulMinPinLen) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulTotalPublicMemory) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulFreePublicMemory) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulTotalPrivateMemory) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulFreePrivateMemory) ||
+ !gck_rpc_message_read_version (msg, &info->hardwareVersion) ||
+ !gck_rpc_message_read_version (msg, &info->firmwareVersion) ||
+ !gck_rpc_message_read_space_string (msg, info->utcTime, 16))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_mechanism_info (GckRpcMessage *msg, CK_MECHANISM_INFO_PTR info)
+{
+ assert (msg);
+ assert (info);
+
+ if (!gck_rpc_message_read_ulong (msg, &info->ulMinKeySize) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulMaxKeySize) ||
+ !gck_rpc_message_read_ulong (msg, &info->flags))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+static CK_RV
+proto_read_sesssion_info (GckRpcMessage *msg, CK_SESSION_INFO_PTR info)
+{
+ assert (msg);
+ assert (info);
+
+ if (!gck_rpc_message_read_ulong (msg, &info->slotID) ||
+ !gck_rpc_message_read_ulong (msg, &info->state) ||
+ !gck_rpc_message_read_ulong (msg, &info->flags) ||
+ !gck_rpc_message_read_ulong (msg, &info->ulDeviceError))
+ return PARSE_ERROR;
+
+ return CKR_OK;
+}
+
+/* -------------------------------------------------------------------
+ * CALL MACROS
+ */
+
+#define BEGIN_CALL(call_id) \
+ debug ((#call_id ": enter")); \
+ return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); \
+ { \
+ CallState *_cs; \
+ CK_RV _ret = CKR_OK; \
+ _ret = call_lookup (&_cs); \
+ if (_ret != CKR_OK) return _ret; \
+ _ret = call_prepare (_cs, GCK_RPC_CALL_##call_id); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define PROCESS_CALL \
+ _ret = call_run (_cs); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+#define RETURN(ret) \
+ _ret = ret; \
+ goto _cleanup;
+
+#define END_CALL \
+ _cleanup: \
+ _ret = call_done (_cs, _ret); \
+ debug (("ret: %d", _ret)); \
+ return _ret; \
+ }
+
+#define IN_BYTE(val) \
+ if (!gck_rpc_message_write_byte (_cs->req, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG(val) \
+ if (!gck_rpc_message_write_ulong (_cs->req, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_STRING(val) \
+ if (!gck_rpc_message_write_zero_string (_cs->req, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_BYTE_BUFFER(arr, len) \
+ if (len == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!gck_rpc_message_write_byte_buffer (_cs->req, arr ? *len : 0)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_BYTE_ARRAY(arr, len) \
+ if (len != 0 && arr == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (!gck_rpc_message_write_byte_array (_cs->req, arr, len)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG_BUFFER(arr, len) \
+ if (len == NULL) \
+ { _ret = CKR_ARGUMENTS_BAD; goto _cleanup; } \
+ if (!gck_rpc_message_write_ulong_buffer (_cs->req, arr ? *len : 0)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_ULONG_ARRAY(arr, len) \
+ if (len != 0 && arr == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (!gck_rpc_message_write_ulong_array (_cs->req, 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 (!gck_rpc_message_write_attribute_buffer (_cs->req, (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 (!gck_rpc_message_write_attribute_array (_cs->req, (arr), (num))) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_MECHANISM_TYPE(val) \
+ if(!gck_rpc_mechanism_is_supported (val)) \
+ { _ret = CKR_MECHANISM_INVALID; goto _cleanup; } \
+ if (!gck_rpc_message_write_ulong (_cs->req, val)) \
+ { _ret = CKR_HOST_MEMORY; goto _cleanup; }
+
+#define IN_MECHANISM(val) \
+ if (val == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ _ret = proto_write_mechanism (_cs->req, val); \
+ if (_ret != CKR_OK) goto _cleanup;
+
+
+
+#define OUT_ULONG(val) \
+ if (val == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK && !gck_rpc_message_read_ulong (_cs->resp, val)) \
+ _ret = PARSE_ERROR;
+
+#define OUT_RETURN_CODE() { \
+ CK_RV r; \
+ _ret = gck_rpc_message_read_ulong (_cs->resp, (_ret == CKR_OK) ? &r : NULL); \
+ if (_ret == CKR_OK) _ret = r; \
+ if (_ret != CKR_OK) goto _cleanup; \
+ }
+
+#define OUT_BYTE_ARRAY(arr, len) \
+ if (len == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_byte_array (_cs->resp, (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 (_cs->resp, (a), (len), *(len));
+
+#define OUT_ATTRIBUTE_ARRAY(arr, num) \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_attribute_array (_cs->resp, (arr), (num));
+
+#define OUT_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_info (_cs->resp, info);
+
+#define OUT_SLOT_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_slot_info (_cs->resp, info);
+
+#define OUT_TOKEN_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_token_info (_cs->resp, info);
+
+#define OUT_SESSION_INFO(info) \
+ if (info == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_sesssion_info (_cs->resp, info);
+
+#define OUT_MECHANISM_TYPE_ARRAY(arr, len) \
+ if (len == NULL) \
+ _ret = CKR_ARGUMENTS_BAD; \
+ if (_ret == CKR_OK) \
+ _ret = proto_read_ulong_array (_cs->resp, (arr), (len), *(len)); \
+ if (_ret == CKR_OK && arr) \
+ gck_rpc_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 (_cs->resp, info);
+
+
+/* -------------------------------------------------------------------
+ * INITIALIZATION and 'GLOBAL' CALLS
+ */
+
+static CK_RV
+rpc_C_Initialize (CK_VOID_PTR init_args)
+{
+ CK_C_INITIALIZE_ARGS_PTR args = NULL;
+ CK_RV ret = CKR_OK;
+ const char *path;
+ CallState *cs;
+ pid_t pid;
+ int err;
+
+ debug (("C_Initialize: enter"));
+
+#ifdef _DEBUG
+ GCK_RPC_CHECK_CALLS();
+#endif
+
+ pthread_mutex_lock (&init_mutex);
+
+ 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) {
+ warning (("invalid set of mutex calls supplied"));
+ ret = CKR_ARGUMENTS_BAD;
+ goto done;
+ }
+
+ /*
+ * When the CKF_OS_LOCKING_OK flag isn't set return an error.
+ * We must be able to use our pthread functionality.
+ */
+ if (!(args->flags & CKF_OS_LOCKING_OK)) {
+ warning (("can't do without os locking"));
+ ret = CKR_CANT_LOCK;
+ goto done;
+ }
+ }
+
+ pid = getpid ();
+ if (pkcs11_initialized) {
+
+ /* This process has called C_Initialize already */
+ if (pid == pkcs11_initialized_pid) {
+ warning (("C_Initialize called twice for same process"));
+ ret = CKR_CRYPTOKI_ALREADY_INITIALIZED;
+ goto done;
+ }
+ }
+
+ /* Create the necessary per thread key */
+ if (pkcs11_per_thread == 0) {
+ err = pthread_key_create (&pkcs11_per_thread, call_destroy);
+ if (err != 0) {
+ ret = CKR_GENERAL_ERROR;
+ goto done;
+ }
+ }
+
+ path = gck_rpc_module_init (args);
+ if (!path || !path[0]) {
+ warning (("missing pkcs11 socket path in environment"));
+ ret = CKR_GENERAL_ERROR;
+ goto done;
+ }
+
+ /* Make a copy of the socket path */
+ snprintf (pkcs11_socket_path, sizeof (pkcs11_socket_path), "%s", path);
+
+ /* Call through and initialize the daemon */
+ ret = call_lookup (&cs);
+ if (ret == CKR_OK) {
+ ret = call_prepare (cs, GCK_RPC_CALL_C_Initialize);
+ if (ret == CKR_OK)
+ if (!gck_rpc_message_write_byte_array (cs->req, GCK_RPC_HANDSHAKE, GCK_RPC_HANDSHAKE_LEN))
+ ret = CKR_HOST_MEMORY;
+ if (ret == CKR_OK) {
+ ret = call_run (cs);
+ if (ret == CKR_CRYPTOKI_ALREADY_INITIALIZED)
+ ret = CKR_OK;
+ }
+ call_done (cs, ret);
+ }
+
+done:
+ /* Mark us as officially initialized */
+ if (ret == CKR_OK) {
+ pkcs11_initialized = 1;
+ pkcs11_initialized_pid = pid;
+ } else if (ret != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+ pkcs11_initialized = 0;
+ pkcs11_initialized_pid = 0;
+ pkcs11_socket_path[0] = 0;
+ }
+
+ pthread_mutex_unlock (&init_mutex);
+
+ debug (("C_Initialize: %d", ret));
+ return ret;
+}
+
+static CK_RV
+rpc_C_Finalize (CK_VOID_PTR reserved)
+{
+ CallState *cs;
+ CK_RV ret;
+
+ debug (("C_Finalize: enter"));
+ return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ return_val_if_fail (!reserved, CKR_ARGUMENTS_BAD);
+
+ pthread_mutex_lock (&init_mutex);
+
+ ret = call_lookup (&cs);
+ if (ret == CKR_OK) {
+ ret = call_prepare (cs, GCK_RPC_CALL_C_Finalize);
+ if (ret == CKR_OK) {
+ ret = call_run (cs);
+ }
+ call_done (cs, ret);
+ }
+
+ if (ret != CKR_OK)
+ warning (("finalizing the daemon returned an error: %d", ret));
+
+ /* This should stop all other calls in */
+ pkcs11_initialized = 0;
+ pkcs11_initialized_pid = 0;
+ pkcs11_socket_path[0] = 0;
+
+ pthread_mutex_unlock (&init_mutex);
+
+ debug (("C_Finalize: %d", CKR_OK));
+ return CKR_OK;
+}
+
+static CK_RV
+rpc_C_GetInfo (CK_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetInfo);
+ PROCESS_CALL;
+ OUT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
+{
+ /* This would be a strange call to receive */
+ return C_GetFunctionList (list);
+}
+
+static CK_RV
+rpc_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count)
+{
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetSlotList);
+ 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_SLOT_ID id, CK_SLOT_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetSlotInfo);
+ IN_ULONG (id);
+ PROCESS_CALL;
+ OUT_SLOT_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetTokenInfo (CK_SLOT_ID id, CK_TOKEN_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetTokenInfo);
+ IN_ULONG (id);
+ PROCESS_CALL;
+ OUT_TOKEN_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetMechanismList (CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list,
+ CK_ULONG_PTR count)
+{
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetMechanismList);
+ IN_ULONG (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_SLOT_ID id, CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetMechanismInfo);
+ IN_ULONG (id);
+ IN_MECHANISM_TYPE (type);
+ PROCESS_CALL;
+ OUT_MECHANISM_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitToken (CK_SLOT_ID id, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len,
+ CK_UTF8CHAR_PTR label)
+{
+ BEGIN_CALL (C_InitToken);
+ IN_ULONG (id);
+ IN_BYTE_ARRAY (pin, pin_len);
+ IN_STRING (label);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_WaitForSlotEvent (CK_FLAGS flags, CK_SLOT_ID_PTR slot, CK_VOID_PTR reserved)
+{
+ return_val_if_fail (slot, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_WaitForSlotEvent);
+ IN_ULONG (flags);
+ PROCESS_CALL;
+ OUT_ULONG (slot);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_OpenSession (CK_SLOT_ID 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 (C_OpenSession);
+ IN_ULONG (id);
+ IN_ULONG (flags);
+ PROCESS_CALL;
+ OUT_ULONG (session);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseSession (CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL (C_CloseSession);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CloseAllSessions (CK_SLOT_ID id)
+{
+ BEGIN_CALL (C_CloseAllSessions);
+ IN_ULONG (id);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetFunctionStatus (CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL (C_GetFunctionStatus);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CancelFunction (CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL (C_CancelFunction);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info)
+{
+ return_val_if_fail (info, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetSessionInfo);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ OUT_SESSION_INFO (info);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_InitPIN (CK_SESSION_HANDLE session, CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ BEGIN_CALL (C_InitPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetPIN (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 (C_SetPIN);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (old_pin, old_pin_len);
+ IN_BYTE_ARRAY (new_pin, old_pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetOperationState (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 (C_GetOperationState);
+ 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_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 (C_SetOperationState);
+ 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_SESSION_HANDLE session, CK_USER_TYPE user_type,
+ CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
+{
+ BEGIN_CALL (C_Login);
+ IN_ULONG (session);
+ IN_ULONG (user_type);
+ IN_BYTE_ARRAY (pin, pin_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Logout (CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL (C_Logout);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CreateObject (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 (C_CreateObject);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ OUT_ULONG (new_object);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_CopyObject (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 (C_CopyObject);
+ 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_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
+{
+ BEGIN_CALL (C_DestroyObject);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetObjectSize (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ULONG_PTR size)
+{
+ return_val_if_fail (size, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_GetObjectSize);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ PROCESS_CALL;
+ OUT_ULONG (size);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GetAttributeValue (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template, CK_ULONG count)
+{
+ BEGIN_CALL (C_GetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_BUFFER (template, count);
+ PROCESS_CALL;
+ OUT_ATTRIBUTE_ARRAY (template, count);
+ OUT_RETURN_CODE ();
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SetAttributeValue (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template, CK_ULONG count)
+{
+ BEGIN_CALL (C_SetAttributeValue);
+ IN_ULONG (session);
+ IN_ULONG (object);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsInit (CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ BEGIN_CALL (C_FindObjectsInit);
+ IN_ULONG (session);
+ IN_ATTRIBUTE_ARRAY (template, count);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjects (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_count, CK_ULONG_PTR count)
+{
+ return_val_if_fail (count, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_FindObjects);
+ IN_ULONG (session);
+ IN_ULONG_BUFFER (objects, &max_count);
+ PROCESS_CALL;
+ *count = max_count;
+ OUT_ULONG_ARRAY (objects, count);
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_FindObjectsFinal (CK_SESSION_HANDLE session)
+{
+ BEGIN_CALL (C_FindObjectsFinal);
+ IN_ULONG (session);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_EncryptInit (CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_EncryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Encrypt (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 (C_Encrypt);
+ 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_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 (C_EncryptUpdate);
+ 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_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 (C_EncryptFinal);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_DecryptInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Decrypt (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 (C_Decrypt);
+ 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_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 (C_DecryptUpdate);
+ 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_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 (C_DecryptFinal);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism)
+{
+ BEGIN_CALL (C_DigestInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Digest (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 (C_Digest);
+ 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_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ BEGIN_CALL (C_DigestUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestKey (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_DigestKey);
+ IN_ULONG (session);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_DigestFinal (CK_SESSION_HANDLE session, CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ return_val_if_fail (digest_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_DigestFinal);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_SignInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Sign (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 (C_Sign);
+ 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_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ return_val_if_fail (part_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_SignUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignFinal (CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_fail (signature_len, CKR_ARGUMENTS_BAD);
+
+ BEGIN_CALL (C_SignFinal);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_SignRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_SignRecover (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 (C_SignRecover);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_VerifyInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_Verify (CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG signature_len)
+{
+ BEGIN_CALL (C_Verify);
+ 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_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
+{
+ BEGIN_CALL (C_VerifyUpdate);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (part, part_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyFinal (CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ BEGIN_CALL (C_VerifyFinal);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (signature, signature_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecoverInit (CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ BEGIN_CALL (C_VerifyRecoverInit);
+ IN_ULONG (session);
+ IN_MECHANISM (mechanism);
+ IN_ULONG (key);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_VerifyRecover (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 (C_VerifyRecover);
+ 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_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 (C_DigestEncryptUpdate);
+ 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_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 (C_DecryptDigestUpdate);
+ 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_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 (C_SignEncryptUpdate);
+ 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_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 (C_DecryptVerifyUpdate);
+ 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_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR template, CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ BEGIN_CALL (C_GenerateKey);
+ 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_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 (C_GenerateKeyPair);
+ 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_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 (C_WrapKey);
+ 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_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 (C_UnwrapKey);
+ 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_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 (C_DeriveKey);
+ 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_SESSION_HANDLE session, CK_BYTE_PTR seed, CK_ULONG seed_len)
+{
+ BEGIN_CALL (C_SeedRandom);
+ IN_ULONG (session);
+ IN_BYTE_ARRAY (seed, seed_len);
+ PROCESS_CALL;
+ END_CALL;
+}
+
+static CK_RV
+rpc_C_GenerateRandom (CK_SESSION_HANDLE session, CK_BYTE_PTR random_data,
+ CK_ULONG random_len)
+{
+ BEGIN_CALL (C_GenerateRandom);
+ IN_ULONG (session);
+ IN_BYTE_BUFFER (random_data, &random_len);
+ PROCESS_CALL;
+ OUT_BYTE_ARRAY (random_data, &random_len);
+ END_CALL;
+}
+
+/* --------------------------------------------------------------------
+ * MODULE ENTRY POINT
+ */
+
+/*
+ * PKCS#11 is broken here. It states that Unix compilers automatically byte
+ * pack structures. This is wrong. GCC on Linux aligns to 4 by default.
+ *
+ * This results in incompatibilities. Where this structure's first version
+ * members take up too much or too little space depending on how this module
+ * is compiled.
+ */
+
+static CK_FUNCTION_LIST functionList = {
+ { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR }, /* version */
+ rpc_C_Initialize,
+ rpc_C_Finalize,
+ rpc_C_GetInfo,
+ rpc_C_GetFunctionList,
+ 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_GetFunctionStatus,
+ rpc_C_CancelFunction,
+ rpc_C_WaitForSlotEvent
+};
+
+CK_RV
+C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
+{
+ return_val_if_fail (list, CKR_ARGUMENTS_BAD);
+
+ *list = &functionList;
+ return CKR_OK;
+}
Added: trunk/pkcs11/rpc-layer/gck-rpc-private.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-private.h Sun Jan 4 23:07:18 2009
@@ -0,0 +1,342 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* p11-rpc-private.h - various ids and signatures for our protocol
+
+ Copyright (C) 2008, Stef Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef GCK_RPC_CALLS_H
+#define GCK_RPC_CALLS_H
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "common/gkr-buffer.h"
+
+#include "pkcs11/pkcs11.h"
+
+
+/* Whether to print debug output or not */
+#define DEBUG_OUTPUT 1
+
+
+/* The calls, must be in sync with array below */
+enum {
+ GCK_RPC_CALL_ERROR = 0,
+
+ GCK_RPC_CALL_C_Initialize,
+ GCK_RPC_CALL_C_Finalize,
+ GCK_RPC_CALL_C_GetInfo,
+ GCK_RPC_CALL_C_GetSlotList,
+ GCK_RPC_CALL_C_GetSlotInfo,
+ GCK_RPC_CALL_C_GetTokenInfo,
+ GCK_RPC_CALL_C_GetMechanismList,
+ GCK_RPC_CALL_C_GetMechanismInfo,
+ GCK_RPC_CALL_C_InitToken,
+ GCK_RPC_CALL_C_WaitForSlotEvent,
+
+ GCK_RPC_CALL_C_OpenSession,
+
+ GCK_RPC_CALL_C_CloseSession,
+ GCK_RPC_CALL_C_CloseAllSessions,
+ GCK_RPC_CALL_C_GetFunctionStatus,
+ GCK_RPC_CALL_C_CancelFunction,
+
+ GCK_RPC_CALL_C_GetSessionInfo,
+ GCK_RPC_CALL_C_InitPIN,
+ GCK_RPC_CALL_C_SetPIN,
+ GCK_RPC_CALL_C_GetOperationState,
+ GCK_RPC_CALL_C_SetOperationState,
+ GCK_RPC_CALL_C_Login,
+ GCK_RPC_CALL_C_Logout,
+ GCK_RPC_CALL_C_CreateObject,
+ GCK_RPC_CALL_C_CopyObject,
+ GCK_RPC_CALL_C_DestroyObject,
+ GCK_RPC_CALL_C_GetObjectSize,
+ GCK_RPC_CALL_C_GetAttributeValue,
+ GCK_RPC_CALL_C_SetAttributeValue,
+ GCK_RPC_CALL_C_FindObjectsInit,
+ GCK_RPC_CALL_C_FindObjects,
+ GCK_RPC_CALL_C_FindObjectsFinal,
+ GCK_RPC_CALL_C_EncryptInit,
+ GCK_RPC_CALL_C_Encrypt,
+ GCK_RPC_CALL_C_EncryptUpdate,
+ GCK_RPC_CALL_C_EncryptFinal,
+ GCK_RPC_CALL_C_DecryptInit,
+ GCK_RPC_CALL_C_Decrypt,
+ GCK_RPC_CALL_C_DecryptUpdate,
+ GCK_RPC_CALL_C_DecryptFinal,
+ GCK_RPC_CALL_C_DigestInit,
+ GCK_RPC_CALL_C_Digest,
+ GCK_RPC_CALL_C_DigestUpdate,
+ GCK_RPC_CALL_C_DigestKey,
+ GCK_RPC_CALL_C_DigestFinal,
+ GCK_RPC_CALL_C_SignInit,
+ GCK_RPC_CALL_C_Sign,
+ GCK_RPC_CALL_C_SignUpdate,
+ GCK_RPC_CALL_C_SignFinal,
+ GCK_RPC_CALL_C_SignRecoverInit,
+ GCK_RPC_CALL_C_SignRecover,
+ GCK_RPC_CALL_C_VerifyInit,
+ GCK_RPC_CALL_C_Verify,
+ GCK_RPC_CALL_C_VerifyUpdate,
+ GCK_RPC_CALL_C_VerifyFinal,
+ GCK_RPC_CALL_C_VerifyRecoverInit,
+ GCK_RPC_CALL_C_VerifyRecover,
+ GCK_RPC_CALL_C_DigestEncryptUpdate,
+ GCK_RPC_CALL_C_DecryptDigestUpdate,
+ GCK_RPC_CALL_C_SignEncryptUpdate,
+ GCK_RPC_CALL_C_DecryptVerifyUpdate,
+ GCK_RPC_CALL_C_GenerateKey,
+ GCK_RPC_CALL_C_GenerateKeyPair,
+ GCK_RPC_CALL_C_WrapKey,
+ GCK_RPC_CALL_C_UnwrapKey,
+ GCK_RPC_CALL_C_DeriveKey,
+ GCK_RPC_CALL_C_SeedRandom,
+ GCK_RPC_CALL_C_GenerateRandom,
+
+ GCK_RPC_CALL_MAX
+};
+
+typedef struct _GckRpcCall {
+ int call_id;
+ const char* name;
+ const char* request;
+ const char* response;
+} GckRpcCall;
+
+/*
+ * 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
+ */
+
+const static GckRpcCall gck_rpc_calls[] = {
+ { GCK_RPC_CALL_ERROR, "ERROR", NULL, NULL },
+ { GCK_RPC_CALL_C_Initialize, "C_Initialize", "ay", "" },
+ { GCK_RPC_CALL_C_Finalize, "C_Finalize", "", "" },
+ { GCK_RPC_CALL_C_GetInfo, "C_GetInfo", "", "vsusv" },
+ { GCK_RPC_CALL_C_GetSlotList, "C_GetSlotList", "yfu", "au" },
+ { GCK_RPC_CALL_C_GetSlotInfo, "C_GetSlotInfo", "u", "ssuvv" },
+ { GCK_RPC_CALL_C_GetTokenInfo, "C_GetTokenInfo", "u", "ssssuuuuuuuuuuuvvs" },
+ { GCK_RPC_CALL_C_GetMechanismList, "C_GetMechanismList", "ufu", "au" },
+ { GCK_RPC_CALL_C_GetMechanismInfo, "C_GetMechanismInfo", "uu", "uuu" },
+ { GCK_RPC_CALL_C_InitToken, "C_InitToken", "uayz", "" },
+ { GCK_RPC_CALL_C_WaitForSlotEvent, "C_WaitForSlotEvent", "u", "u" },
+ { GCK_RPC_CALL_C_OpenSession, "C_OpenSession", "uu", "u" },
+ { GCK_RPC_CALL_C_CloseSession, "C_CloseSession", "u", "" },
+ { GCK_RPC_CALL_C_CloseAllSessions, "C_CloseAllSessions", "u", "" },
+ { GCK_RPC_CALL_C_GetFunctionStatus, "C_GetFunctionStatus", "u", "" },
+ { GCK_RPC_CALL_C_CancelFunction, "C_CancelFunction", "u", "" },
+ { GCK_RPC_CALL_C_GetSessionInfo, "C_GetSessionInfo", "u", "uuuu" },
+ { GCK_RPC_CALL_C_InitPIN, "C_InitPIN", "uay", "" },
+ { GCK_RPC_CALL_C_SetPIN, "C_SetPIN", "uayay", "" },
+ { GCK_RPC_CALL_C_GetOperationState, "C_GetOperationState", "ufy", "ay" },
+ { GCK_RPC_CALL_C_SetOperationState, "C_SetOperationState", "uayuu", "" },
+ { GCK_RPC_CALL_C_Login, "C_Login", "uuay", "" },
+ { GCK_RPC_CALL_C_Logout, "C_Logout", "u", "" },
+ { GCK_RPC_CALL_C_CreateObject, "C_CreateObject", "uaA", "u" },
+ { GCK_RPC_CALL_C_CopyObject, "C_CopyObject", "uuaA", "u" },
+ { GCK_RPC_CALL_C_DestroyObject, "C_DestroyObject", "uu", "" },
+ { GCK_RPC_CALL_C_GetObjectSize, "C_GetObjectSize", "uu", "u" },
+ { GCK_RPC_CALL_C_GetAttributeValue, "C_GetAttributeValue", "uufA", "aAu" },
+ { GCK_RPC_CALL_C_SetAttributeValue, "C_SetAttributeValue", "uuaA", "" },
+ { GCK_RPC_CALL_C_FindObjectsInit, "C_FindObjectsInit", "uaA", "" },
+ { GCK_RPC_CALL_C_FindObjects, "C_FindObjects", "ufu", "au" },
+ { GCK_RPC_CALL_C_FindObjectsFinal, "C_FindObjectsFinal", "u", "" },
+ { GCK_RPC_CALL_C_EncryptInit, "C_EncryptInit", "uMu" "" },
+ { GCK_RPC_CALL_C_Encrypt, "C_Encrypt", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_EncryptUpdate, "C_EncryptUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_EncryptFinal, "C_EncryptFinal", "ufy", "ay" },
+ { GCK_RPC_CALL_C_DecryptInit, "C_DecryptInit", "uMu", "" },
+ { GCK_RPC_CALL_C_Decrypt, "C_Decrypt", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DecryptUpdate, "C_DecryptUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DecryptFinal, "C_DecryptFinal", "ufy", "ay" },
+ { GCK_RPC_CALL_C_DigestInit, "C_DigestInit", "uM", "" },
+ { GCK_RPC_CALL_C_Digest, "C_Digest", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DigestUpdate, "C_DigestUpdate", "uay", "" },
+ { GCK_RPC_CALL_C_DigestKey, "C_DigestKey", "uu", "" },
+ { GCK_RPC_CALL_C_DigestFinal, "C_DigestFinal", "ufy", "ay" },
+ { GCK_RPC_CALL_C_SignInit, "C_SignInit", "uMu", "" },
+ { GCK_RPC_CALL_C_Sign, "C_Sign", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_SignUpdate, "C_SignUpdate", "uay", "" },
+ { GCK_RPC_CALL_C_SignFinal, "C_SignFinal", "ufy", "ay" },
+ { GCK_RPC_CALL_C_SignRecoverInit, "C_SignRecoverInit", "uMu", "" },
+ { GCK_RPC_CALL_C_SignRecover, "C_SignRecover", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_VerifyInit, "C_VerifyInit", "uMu", "" },
+ { GCK_RPC_CALL_C_Verify, "C_Verify", "uayay", "" },
+ { GCK_RPC_CALL_C_VerifyUpdate, "C_VerifyUpdate", "uay", "" },
+ { GCK_RPC_CALL_C_VerifyFinal, "C_VerifyFinal", "uay", "" },
+ { GCK_RPC_CALL_C_VerifyRecoverInit, "C_VerifyRecoverInit", "uMu", "" },
+ { GCK_RPC_CALL_C_VerifyRecover, "C_VerifyRecover", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DigestEncryptUpdate, "C_DigestEncryptUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DecryptDigestUpdate, "C_DecryptDigestUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_SignEncryptUpdate, "C_SignEncryptUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_DecryptVerifyUpdate, "C_DecryptVerifyUpdate", "uayfy", "ay" },
+ { GCK_RPC_CALL_C_GenerateKey, "C_GenerateKey", "uMaA", "u" },
+ { GCK_RPC_CALL_C_GenerateKeyPair, "C_GenerateKeyPair", "uMaAaA", "uu" },
+ { GCK_RPC_CALL_C_WrapKey, "C_WrapKey", "uMuufy", "ay" },
+ { GCK_RPC_CALL_C_UnwrapKey, "C_UnwrapKey", "uMuayaA", "u" },
+ { GCK_RPC_CALL_C_DeriveKey, "C_DeriveKey", "uMuaA", "u" },
+ { GCK_RPC_CALL_C_SeedRandom, "C_SeedRandom", "uay", "" },
+ { GCK_RPC_CALL_C_GenerateRandom, "C_GenerateRandom", "ufy", "ay" },
+};
+
+#ifdef _DEBUG
+#define GCK_RPC_CHECK_CALLS() \
+ { int i; for (i = 0; i < GCK_RPC_CALL_MAX; ++i) assert (gck_rpc_calls[i].call_id == i); }
+#endif
+
+#define GCK_RPC_HANDSHAKE \
+ ((unsigned char*)"PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-1")
+#define GCK_RPC_HANDSHAKE_LEN \
+ (sizeof (GCK_RPC_HANDSHAKE) - 1)
+
+#define GCK_RPC_SOCKET_EXT "pkcs11"
+
+typedef enum _GckRpcMessageType {
+ GCK_RPC_REQUEST = 1,
+ GCK_RPC_RESPONSE
+} GckRpcMessageType;
+
+typedef struct _GckRpcMessage {
+ int call_id;
+ GckRpcMessageType call_type;
+ const char *signature;
+ GkrBuffer buffer;
+
+ size_t parsed;
+ const char *sigverify;
+} GckRpcMessage;
+
+GckRpcMessage* gck_rpc_message_new (GkrBufferAllocator allocator);
+
+void gck_rpc_message_free (GckRpcMessage *msg);
+
+void gck_rpc_message_reset (GckRpcMessage *msg);
+
+int gck_rpc_message_equals (GckRpcMessage *m1,
+ GckRpcMessage *m2);
+
+#define gck_rpc_message_is_verified(msg) ((msg)->sigverify[0] == 0)
+
+#define gck_rpc_message_buffer_error(msg) (gkr_buffer_has_error(&(msg)->buffer))
+
+int gck_rpc_message_prep (GckRpcMessage *msg,
+ int call_id,
+ GckRpcMessageType type);
+
+int gck_rpc_message_parse (GckRpcMessage *msg,
+ GckRpcMessageType type);
+
+int gck_rpc_message_verify_part (GckRpcMessage *msg,
+ const char* part);
+
+int gck_rpc_message_write_byte (GckRpcMessage *msg,
+ CK_BYTE val);
+
+int gck_rpc_message_write_ulong (GckRpcMessage *msg,
+ CK_ULONG val);
+
+int gck_rpc_message_write_zero_string (GckRpcMessage *msg,
+ CK_UTF8CHAR* string);
+
+int gck_rpc_message_write_space_string (GckRpcMessage *msg,
+ CK_UTF8CHAR* buffer,
+ CK_ULONG length);
+
+int gck_rpc_message_write_byte_buffer (GckRpcMessage *msg,
+ CK_ULONG count);
+
+int gck_rpc_message_write_byte_array (GckRpcMessage *msg,
+ CK_BYTE_PTR arr,
+ CK_ULONG num);
+
+int gck_rpc_message_write_ulong_buffer (GckRpcMessage *msg,
+ CK_ULONG count);
+
+int gck_rpc_message_write_ulong_array (GckRpcMessage *msg,
+ CK_ULONG_PTR arr,
+ CK_ULONG num);
+
+int gck_rpc_message_write_attribute_buffer (GckRpcMessage *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num);
+
+int gck_rpc_message_write_attribute_array (GckRpcMessage *msg,
+ CK_ATTRIBUTE_PTR arr,
+ CK_ULONG num);
+
+int gck_rpc_message_write_version (GckRpcMessage *msg,
+ CK_VERSION* version);
+
+
+int gck_rpc_message_read_byte (GckRpcMessage *msg,
+ CK_BYTE* val);
+
+int gck_rpc_message_read_ulong (GckRpcMessage *msg,
+ CK_ULONG* val);
+
+int gck_rpc_message_read_space_string (GckRpcMessage *msg,
+ CK_UTF8CHAR* buffer,
+ CK_ULONG length);
+
+int gck_rpc_message_read_version (GckRpcMessage *msg,
+ CK_VERSION* version);
+
+
+
+void gck_rpc_log (const char *line);
+
+void gck_rpc_warn (const char* msg, ...);
+
+void gck_rpc_debug (const char* msg, ...);
+
+#ifdef G_DISABLE_ASSERT
+#define assert(x)
+#else
+#include <assert.h>
+#endif
+
+/*
+ * 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.
+ */
+
+int gck_rpc_mechanism_is_supported (CK_MECHANISM_TYPE mech);
+void gck_rpc_mechanism_list_purge (CK_MECHANISM_TYPE_PTR mechs, CK_ULONG_PTR n_mechs);
+int gck_rpc_mechanism_has_sane_parameters (CK_MECHANISM_TYPE type);
+int gck_rpc_mechanism_has_no_parameters (CK_MECHANISM_TYPE mech);
+
+#endif /* GCK_RPC_CALLS_H */
Added: trunk/pkcs11/rpc-layer/gck-rpc-util.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/rpc-layer/gck-rpc-util.c Sun Jan 4 23:07:18 2009
@@ -0,0 +1,207 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* p11-rpc-util.c - utilities for module and dispatcher
+
+ Copyright (C) 2008, Stef Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-rpc-layer.h"
+#include "gck-rpc-private.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+static void
+do_log (const char *pref, const char *msg, va_list va)
+{
+ char buffer[1024];
+ size_t len = 0;
+
+ if (pref) {
+ snprintf (buffer, sizeof (buffer), "%s: ", pref);
+ len = strlen (buffer);
+ }
+
+ vsnprintf (buffer + len, sizeof (buffer) - len, msg, va);
+ gck_rpc_log (buffer);
+}
+
+void
+gck_rpc_warn (const char* msg, ...)
+{
+ va_list va;
+ va_start (va, msg);
+ do_log ("WARNING", msg, va);
+ va_end (va);
+}
+
+void
+gck_rpc_debug (const char* msg, ...)
+{
+ va_list va;
+ va_start (va, msg);
+ do_log ("DEBUG", msg, va);
+ va_end (va);
+}
+
+int
+gck_rpc_mechanism_is_supported (CK_MECHANISM_TYPE mech)
+{
+ if (gck_rpc_mechanism_has_no_parameters (mech) ||
+ gck_rpc_mechanism_has_sane_parameters (mech))
+ return 1;
+ return 0;
+}
+void
+gck_rpc_mechanism_list_purge (CK_MECHANISM_TYPE_PTR mechs, CK_ULONG* n_mechs)
+{
+ int i;
+
+ assert (mechs);
+ assert (n_mechs);
+
+ for (i = 0; i < (int)(*mechs); ++i) {
+ if (!gck_rpc_mechanism_has_no_parameters (mechs[i]) &&
+ !gck_rpc_mechanism_has_sane_parameters (mechs[i])) {
+
+ /* Remove the mechanism from the list */
+ memmove (&mechs[i], &mechs[i + 1], (*n_mechs - i) * sizeof (CK_MECHANISM_TYPE));
+
+ --(*n_mechs);
+ --i;
+ }
+ }
+}
+
+int
+gck_rpc_mechanism_has_sane_parameters (CK_MECHANISM_TYPE type)
+{
+ /* This list is incomplete */
+ switch (type) {
+ case CKM_RSA_PKCS_OAEP:
+ case CKM_RSA_PKCS_PSS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int
+gck_rpc_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 1;
+ default:
+ return 0;
+ };
+}
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]