diff options
Diffstat (limited to 'p11-kit/rpc-client.c')
-rw-r--r-- | p11-kit/rpc-client.c | 2092 |
1 files changed, 2092 insertions, 0 deletions
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; +} |