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