From a104bd71c85b0a0bf836968c4a85d75bc86ac7c6 Mon Sep 17 00:00:00 2001 From: turly221 Date: Tue, 3 Dec 2024 03:24:47 +0000 Subject: [PATCH 1/3] commit patch 12160924 --- p11-kit/rpc-client.c | 63 +- p11-kit/rpc-message.c | 509 ++++++++- p11-kit/rpc-message.c.orig | 769 ++++++++++++++ p11-kit/rpc-message.h | 77 ++ p11-kit/rpc-server.c | 35 +- p11-kit/rpc-server.c.orig | 2004 ++++++++++++++++++++++++++++++++++++ p11-kit/test-rpc.c | 223 +++- 7 files changed, 3600 insertions(+), 80 deletions(-) create mode 100644 p11-kit/rpc-message.c.orig create mode 100644 p11-kit/rpc-server.c.orig diff --git a/p11-kit/rpc-client.c b/p11-kit/rpc-client.c index 8607bb5cd..5c70bb01c 100644 --- a/p11-kit/rpc-client.c +++ b/p11-kit/rpc-client.c @@ -196,11 +196,7 @@ 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 = NULL; - size_t attrlen = 0; - unsigned char validity; + uint32_t i, num; CK_RV ret; assert (len != 0); @@ -229,62 +225,49 @@ proto_read_attribute_array (p11_rpc_message *msg, /* We need to go ahead and read everything in all cases */ for (i = 0; i < num; ++i) { + size_t offset = msg->parsed; + CK_ATTRIBUTE temp; - /* 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; - } + memset (&temp, 0, sizeof (temp)); + if (!p11_rpc_buffer_get_attribute (msg->input, &offset, &temp)) { + msg->parsed = offset; + return PARSE_ERROR; } - /* 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) { + CK_ATTRIBUTE *attr = &(arr[i]); + + if (temp.type != attr->type) { p11_message ("returned attributes in invalid order"); + msg->parsed = offset; return PARSE_ERROR; } - if (validity) { + if (temp.ulValueLen != ((CK_ULONG)-1)) { /* Just requesting the attribute size */ if (!attr->pValue) { - attr->ulValueLen = attrlen; + attr->ulValueLen = temp.ulValueLen; /* Wants attribute data, but too small */ - } else if (attr->ulValueLen < attrlen) { - attr->ulValueLen = attrlen; + } else if (attr->ulValueLen < temp.ulValueLen) { + attr->ulValueLen = temp.ulValueLen; 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); + size_t offset2 = msg->parsed; + if (!p11_rpc_buffer_get_attribute (msg->input, &offset2, attr)) { + msg->parsed = offset2; + return PARSE_ERROR; + } } - - /* Not a valid attribute */ } else { - attr->ulValueLen = ((CK_ULONG)-1); + attr->ulValueLen = temp.ulValueLen; } } + + msg->parsed = offset; } if (p11_buffer_failed (msg->input)) diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c index b5ac52888..27f062cf3 100644 --- a/p11-kit/rpc-message.c +++ b/p11-kit/rpc-message.c @@ -35,6 +35,7 @@ #include "config.h" +#define P11_DEBUG_FLAG P11_DEBUG_RPC #include "debug.h" #include "library.h" #include "message.h" @@ -44,6 +45,8 @@ #include #include +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + void p11_rpc_message_init (p11_rpc_message *msg, p11_buffer *input, @@ -254,8 +257,6 @@ p11_rpc_message_write_attribute_array (p11_rpc_message *msg, CK_ULONG num) { CK_ULONG i; - CK_ATTRIBUTE_PTR attr; - unsigned char validity; assert (num == 0 || arr != NULL); assert (msg != NULL); @@ -267,22 +268,8 @@ p11_rpc_message_write_attribute_array (p11_rpc_message *msg, /* 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); - } - } + for (i = 0; i < num; ++i) + p11_rpc_buffer_add_attribute (msg->output, &(arr[i])); return !p11_buffer_failed (msg->output); } @@ -767,3 +754,489 @@ p11_rpc_buffer_get_byte_array (p11_buffer *buf, return true; } + +static p11_rpc_value_type +map_attribute_to_value_type (CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_TRUSTED: + case CKA_SENSITIVE: + case CKA_ENCRYPT: + case CKA_DECRYPT: + case CKA_WRAP: + case CKA_UNWRAP: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_DERIVE: + case CKA_EXTRACTABLE: + case CKA_LOCAL: + case CKA_NEVER_EXTRACTABLE: + case CKA_ALWAYS_SENSITIVE: + case CKA_MODIFIABLE: + case CKA_COPYABLE: + case CKA_SECONDARY_AUTH: /* Deprecated */ + case CKA_ALWAYS_AUTHENTICATE: + case CKA_WRAP_WITH_TRUSTED: + case CKA_RESET_ON_INIT: + case CKA_HAS_RESET: + case CKA_COLOR: + return P11_RPC_VALUE_BYTE; + case CKA_CLASS: + case CKA_CERTIFICATE_TYPE: + case CKA_CERTIFICATE_CATEGORY: + case CKA_JAVA_MIDP_SECURITY_DOMAIN: + case CKA_KEY_TYPE: + case CKA_MODULUS_BITS: + case CKA_PRIME_BITS: + case CKA_SUB_PRIME_BITS: + case CKA_VALUE_BITS: + case CKA_VALUE_LEN: + case CKA_KEY_GEN_MECHANISM: + case CKA_AUTH_PIN_FLAGS: /* Deprecated */ + case CKA_HW_FEATURE_TYPE: + case CKA_PIXEL_X: + case CKA_PIXEL_Y: + case CKA_RESOLUTION: + case CKA_CHAR_ROWS: + case CKA_CHAR_COLUMNS: + case CKA_BITS_PER_PIXEL: + case CKA_MECHANISM_TYPE: + return P11_RPC_VALUE_ULONG; + case CKA_WRAP_TEMPLATE: + case CKA_UNWRAP_TEMPLATE: + return P11_RPC_VALUE_ATTRIBUTE_ARRAY; + case CKA_ALLOWED_MECHANISMS: + return P11_RPC_VALUE_MECHANISM_TYPE_ARRAY; + case CKA_START_DATE: + case CKA_END_DATE: + return P11_RPC_VALUE_DATE; + default: + p11_debug ("cannot determine the type of attribute value for %lu; assuming byte array", + type); + /* fallthrough */ + case CKA_LABEL: + case CKA_APPLICATION: + case CKA_VALUE: + case CKA_OBJECT_ID: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + case CKA_AC_ISSUER: + case CKA_OWNER: + case CKA_ATTR_TYPES: + case CKA_URL: + case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: + case CKA_HASH_OF_ISSUER_PUBLIC_KEY: + case CKA_CHECK_VALUE: + case CKA_SUBJECT: + case CKA_ID: + case CKA_MODULUS: + case CKA_PUBLIC_EXPONENT: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + case CKA_EC_PARAMS: + /* same as CKA_ECDSA_PARAMS */ + case CKA_EC_POINT: + case CKA_CHAR_SETS: + case CKA_ENCODING_METHODS: + case CKA_MIME_TYPES: + case CKA_REQUIRED_CMS_ATTRIBUTES: + case CKA_DEFAULT_CMS_ATTRIBUTES: + case CKA_SUPPORTED_CMS_ATTRIBUTES: + return P11_RPC_VALUE_BYTE_ARRAY; + } +} + +void +p11_rpc_buffer_add_byte_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_BYTE byte_value; + + /* Check if value can be converted to CK_BYTE. */ + if (value_length > sizeof (CK_BYTE)) { + p11_buffer_fail (buffer); + return; + } + memcpy (&byte_value, value, value_length); + + /* Check if byte_value can be converted to uint8_t. */ + if (byte_value > UINT8_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_byte (buffer, byte_value); +} + +void +p11_rpc_buffer_add_ulong_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_ULONG ulong_value; + + /* Check if value can be converted to CK_ULONG. */ + if (value_length > sizeof (CK_ULONG)) { + p11_buffer_fail (buffer); + return; + } + memcpy (&ulong_value, value, value_length); + + /* Check if ulong_value can be converted to uint64_t. */ + if (ulong_value > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_uint64 (buffer, ulong_value); +} + +void +p11_rpc_buffer_add_attribute_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + const CK_ATTRIBUTE *attrs = value; + size_t count = value_length / sizeof (CK_ATTRIBUTE); + size_t i; + + /* Check if count can be converted to uint32_t. */ + if (count > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + /* Write the number of items */ + p11_rpc_buffer_add_uint32 (buffer, count); + + /* Actually write the attributes. */ + for (i = 0; i < count; i++) { + const CK_ATTRIBUTE *attr = &(attrs[i]); + p11_rpc_buffer_add_attribute (buffer, attr); + } +} + +void +p11_rpc_buffer_add_mechanism_type_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + const CK_MECHANISM_TYPE *mechs = value; + size_t count = value_length / sizeof (CK_MECHANISM_TYPE); + size_t i; + + /* Check if count can be converted to uint32_t. */ + if (count > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + /* Write the number of items */ + p11_rpc_buffer_add_uint32 (buffer, count); + + for (i = 0; i < count; i++) { + if (mechs[i] > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint64 (buffer, mechs[i]); + } +} + +void +p11_rpc_buffer_add_date_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_DATE date_value; + unsigned char array[8]; + + /* Check if value can be converted to CK_DATE. */ + if (value_length > sizeof (CK_DATE)) { + p11_buffer_fail (buffer); + return; + } + + memcpy (&date_value, value, value_length); + memcpy (array, date_value.year, 4); + memcpy (array + 4, date_value.month, 2); + memcpy (array + 6, date_value.day, 2); + + p11_rpc_buffer_add_byte_array (buffer, array, 8); +} + +void +p11_rpc_buffer_add_byte_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + /* Check if value length can be converted to uint32_t, as + * p11_rpc_buffer_add_byte_array expects. */ + if (value_length > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_byte_array (buffer, value, value_length); +} + +void +p11_rpc_buffer_add_attribute (p11_buffer *buffer, const CK_ATTRIBUTE *attr) +{ + unsigned char validity; + static const p11_rpc_value_encoder encoders[] = { + p11_rpc_buffer_add_byte_value, + p11_rpc_buffer_add_ulong_value, + p11_rpc_buffer_add_attribute_array_value, + p11_rpc_buffer_add_mechanism_type_array_value, + p11_rpc_buffer_add_date_value, + p11_rpc_buffer_add_byte_array_value + }; + p11_rpc_value_encoder encoder; + p11_rpc_value_type value_type; + + /* The attribute type */ + if (attr->type > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint32 (buffer, attr->type); + + /* Write out the attribute validity */ + validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1; + p11_rpc_buffer_add_byte (buffer, validity); + + if (!validity) + return; + + /* The attribute length */ + if (attr->ulValueLen > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint32 (buffer, attr->ulValueLen); + + /* The attribute value */ + value_type = map_attribute_to_value_type (attr->type); + assert (value_type < ELEMS (encoders)); + encoder = encoders[value_type]; + assert (encoder != NULL); + encoder (buffer, attr->pValue, attr->ulValueLen); +} + +bool +p11_rpc_buffer_get_byte_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + unsigned char val; + + if (!p11_rpc_buffer_get_byte (buffer, offset, &val)) + return false; + + if (value) { + CK_BYTE byte_value = val; + memcpy (value, &byte_value, sizeof (CK_BYTE)); + } + + if (value_length) + *value_length = sizeof (CK_BYTE); + + return true; +} + +bool +p11_rpc_buffer_get_ulong_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint64_t val; + + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val)) + return false; + + if (value) { + CK_ULONG ulong_value = val; + memcpy (value, &ulong_value, sizeof (CK_ULONG)); + } + + if (value_length) + *value_length = sizeof (CK_ULONG); + + return true; +} + +bool +p11_rpc_buffer_get_attribute_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint32_t count, i; + CK_ATTRIBUTE *attr, temp; + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &count)) + return false; + + if (!value) { + memset (&temp, 0, sizeof (CK_ATTRIBUTE)); + attr = &temp; + } else + attr = value; + + for (i = 0; i < count; i++) { + if (!p11_rpc_buffer_get_attribute (buffer, offset, attr)) + return false; + if (value) + attr++; + } + + if (value_length) + *value_length = count * sizeof (CK_ATTRIBUTE); + + return true; +} + +bool +p11_rpc_buffer_get_mechanism_type_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint32_t count, i; + CK_MECHANISM_TYPE *mech, temp; + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &count)) + return false; + + if (!value) { + memset (&temp, 0, sizeof (CK_MECHANISM_TYPE)); + mech = &temp; + } else + mech = value; + + for (i = 0; i < count; i++) { + CK_ULONG len; + if (!p11_rpc_buffer_get_ulong_value (buffer, offset, mech, &len)) + return false; + if (value) + mech++; + } + + if (value_length) + *value_length = count * sizeof (CK_MECHANISM_TYPE); + + return true; +} + +bool +p11_rpc_buffer_get_date_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + CK_DATE date_value; + const unsigned char *array; + size_t array_length; + + if (!p11_rpc_buffer_get_byte_array (buffer, offset, + &array, &array_length) || + array_length != 8) + return false; + + if (value) { + memcpy (date_value.year, array, 4); + memcpy (date_value.month, array + 4, 2); + memcpy (date_value.day, array + 6, 2); + memcpy (value, &date_value, sizeof (CK_DATE)); + } + + if (value_length) + *value_length = sizeof (CK_DATE); + + return true; +} + +bool +p11_rpc_buffer_get_byte_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + const unsigned char *val; + size_t len; + + if (!p11_rpc_buffer_get_byte_array (buffer, offset, &val, &len)) + return false; + + if (val && value) + memcpy (value, val, len); + + if (value_length) + *value_length = len; + + return true; +} + +bool +p11_rpc_buffer_get_attribute (p11_buffer *buffer, + size_t *offset, + CK_ATTRIBUTE *attr) +{ + uint32_t type, length; + unsigned char validity; + static const p11_rpc_value_decoder decoders[] = { + p11_rpc_buffer_get_byte_value, + p11_rpc_buffer_get_ulong_value, + p11_rpc_buffer_get_attribute_array_value, + p11_rpc_buffer_get_mechanism_type_array_value, + p11_rpc_buffer_get_date_value, + p11_rpc_buffer_get_byte_array_value + }; + p11_rpc_value_decoder decoder; + p11_rpc_value_type value_type; + + /* The attribute type */ + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &type)) + return false; + + /* Attribute validity */ + if (!p11_rpc_buffer_get_byte (buffer, offset, &validity)) + return false; + + /* Not a valid attribute */ + if (!validity) { + attr->ulValueLen = ((CK_ULONG)-1); + attr->type = type; + return true; + } + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &length)) + return false; + + /* Decode the attribute value */ + value_type = map_attribute_to_value_type (type); + assert (value_type < ELEMS (decoders)); + decoder = decoders[value_type]; + assert (decoder != NULL); + if (!decoder (buffer, offset, attr->pValue, &attr->ulValueLen)) + return false; + if (!attr->pValue) + attr->ulValueLen = length; + attr->type = type; + return true; +} diff --git a/p11-kit/rpc-message.c.orig b/p11-kit/rpc-message.c.orig new file mode 100644 index 000000000..b5ac52888 --- /dev/null +++ b/p11-kit/rpc-message.c.orig @@ -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 + */ + +#include "config.h" + +#include "debug.h" +#include "library.h" +#include "message.h" +#include "private.h" +#include "rpc-message.h" + +#include +#include + +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 >= 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 index fc4d06e63..93cb94e2a 100644 --- a/p11-kit/rpc-message.h +++ b/p11-kit/rpc-message.h @@ -216,6 +216,18 @@ static const p11_rpc_call p11_rpc_calls[] = { #define P11_RPC_HANDSHAKE_LEN \ (strlen ((char *)P11_RPC_HANDSHAKE)) +typedef enum _p11_rpc_value_type { + P11_RPC_VALUE_BYTE = 0, + P11_RPC_VALUE_ULONG, + P11_RPC_VALUE_ATTRIBUTE_ARRAY, + P11_RPC_VALUE_MECHANISM_TYPE_ARRAY, + P11_RPC_VALUE_DATE, + P11_RPC_VALUE_BYTE_ARRAY +} p11_rpc_value_type; + +typedef void (*p11_rpc_value_encoder) (p11_buffer *, const void *, CK_ULONG); +typedef bool (*p11_rpc_value_decoder) (p11_buffer *, size_t *, void *, CK_ULONG *); + typedef enum _p11_rpc_message_type { P11_RPC_REQUEST = 1, P11_RPC_RESPONSE @@ -367,4 +379,69 @@ bool p11_rpc_buffer_get_uint64 (p11_buffer *buf, size_t *offset, uint64_t *val); +void p11_rpc_buffer_add_attribute (p11_buffer *buffer, + const CK_ATTRIBUTE *attr); + +bool p11_rpc_buffer_get_attribute (p11_buffer *buffer, + size_t *offset, + CK_ATTRIBUTE *attr); + +void p11_rpc_buffer_add_byte_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_byte_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + +void p11_rpc_buffer_add_ulong_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_ulong_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + +void p11_rpc_buffer_add_attribute_array_value + (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_attribute_array_value + (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + +void p11_rpc_buffer_add_mechanism_type_array_value + (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_mechanism_type_array_value + (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + +void p11_rpc_buffer_add_date_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_date_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + +void p11_rpc_buffer_add_byte_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length); + +bool p11_rpc_buffer_get_byte_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length); + #endif /* _RPC_MESSAGE_H */ diff --git a/p11-kit/rpc-server.c b/p11-kit/rpc-server.c index a2562e9f0..0f01067b8 100644 --- a/p11-kit/rpc-server.c +++ b/p11-kit/rpc-server.c @@ -280,11 +280,7 @@ proto_read_attribute_array (p11_rpc_message *msg, 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); @@ -305,34 +301,31 @@ proto_read_attribute_array (p11_rpc_message *msg, /* Now go through and fill in each one */ for (i = 0; i < n_attrs; ++i) { + size_t offset = msg->parsed; + CK_ATTRIBUTE temp; - /* The attribute type */ - if (!p11_rpc_buffer_get_uint32 (msg->input, &msg->parsed, &value)) + memset (&temp, 0, sizeof (temp)); + if (!p11_rpc_buffer_get_attribute (msg->input, &offset, &temp)) { + msg->parsed = offset; return PARSE_ERROR; + } - attrs[i].type = value; + attrs[i].type = temp.type; /* 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"); + if (temp.ulValueLen != ((CK_ULONG)-1)) { + size_t offset2 = msg->parsed; + attrs[i].pValue = p11_rpc_message_alloc_extra (msg, temp.ulValueLen); + if (!p11_rpc_buffer_get_attribute (msg->input, &offset2, &attrs[i])) { + msg->parsed = offset2; return PARSE_ERROR; } - - attrs[i].pValue = (CK_VOID_PTR)data; - attrs[i].ulValueLen = value; } else { attrs[i].pValue = NULL; attrs[i].ulValueLen = -1; } + + msg->parsed = offset; } *result = attrs; diff --git a/p11-kit/rpc-server.c.orig b/p11-kit/rpc-server.c.orig new file mode 100644 index 000000000..a2562e9f0 --- /dev/null +++ b/p11-kit/rpc-server.c.orig @@ -0,0 +1,2004 @@ +/* + * 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 + */ + +#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 "remote.h" +#include "rpc.h" +#include "rpc-message.h" + +#include +#include +#include +#include +#include +#include +#include + +/* 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)); + } + + if (ret == CKR_OK) { + 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; +} + +int +p11_kit_remote_serve_module (CK_FUNCTION_LIST *module, + int in_fd, + int out_fd) +{ + p11_rpc_status status; + unsigned char version; + p11_virtual virt; + p11_buffer options; + p11_buffer buffer; + size_t state; + int ret = 1; + int code; + + return_val_if_fail (module != NULL, 1); + + p11_buffer_init (&options, 0); + p11_buffer_init (&buffer, 0); + + p11_virtual_init (&virt, &p11_virtual_base, module, NULL); + + switch (read (in_fd, &version, 1)) { + case 0: + goto out; + case 1: + if (version != 0) { + p11_message ("unspported version received: %d", (int)version); + goto out; + } + break; + default: + p11_message_err (errno, "couldn't read credential byte"); + goto out; + } + + version = 0; + switch (write (out_fd, &version, out_fd)) { + case 1: + break; + default: + p11_message_err (errno, "couldn't write credential byte"); + goto out; + } + + status = P11_RPC_OK; + while (status == P11_RPC_OK) { + state = 0; + code = 0; + + do { + status = p11_rpc_transport_read (in_fd, &state, &code, + &options, &buffer); + } while (status == P11_RPC_AGAIN); + + switch (status) { + case P11_RPC_OK: + break; + case P11_RPC_EOF: + ret = 0; + continue; + case P11_RPC_AGAIN: + assert_not_reached (); + case P11_RPC_ERROR: + p11_message_err (errno, "failed to read rpc message"); + goto out; + } + + if (!p11_rpc_server_handle (&virt.funcs, &buffer, &buffer)) { + p11_message ("unexpected error handling rpc message"); + goto out; + } + + state = 0; + options.len = 0; + do { + status = p11_rpc_transport_write (out_fd, &state, code, + &options, &buffer); + } while (status == P11_RPC_AGAIN); + + switch (status) { + case P11_RPC_OK: + break; + case P11_RPC_EOF: + case P11_RPC_AGAIN: + assert_not_reached (); + case P11_RPC_ERROR: + p11_message_err (errno, "failed to write rpc message"); + goto out; + } + } + +out: + p11_buffer_uninit (&buffer); + p11_buffer_uninit (&options); + + p11_virtual_uninit (&virt); + + return ret; +} diff --git a/p11-kit/test-rpc.c b/p11-kit/test-rpc.c index c9f8333f5..c6490bf51 100644 --- a/p11-kit/test-rpc.c +++ b/p11-kit/test-rpc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012 Stefan Walter - * Copyright (c) 2012 Red Hat Inc. + * Copyright (C) 2012-2017 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -352,6 +352,221 @@ test_byte_array_static (void) assert (memcmp (data + 8, val, 32) == 0); } +static void +test_byte_value (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 }; + + char val[16]; + size_t offset = 0; + CK_ULONG val_size; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_rpc_buffer_add_byte_value(&buffer, bytes, sizeof(bytes)); + assert (p11_buffer_failed (&buffer)); + + p11_buffer_reset (&buffer, 0); + + p11_rpc_buffer_add_byte_value(&buffer, bytes, 1); + assert (!p11_buffer_failed (&buffer)); + + ret = p11_rpc_buffer_get_byte_value(&buffer, &offset, val, &val_size); + assert_num_eq (true, ret); + + assert_num_eq (bytes[0], val[0]); + + /* Read out of bound */ + ret = p11_rpc_buffer_get_byte_value(&buffer, &offset, val, &val_size); + assert_num_eq (false, ret); + + p11_buffer_uninit (&buffer); +} + +static void +test_ulong_value (void) +{ + p11_buffer buffer; + p11_buffer buf = { (unsigned char *)"pad0\x00\x00\x00\x00\x23\x45\x67\x89", 12, }; + CK_ULONG val = 0xFFFFFFFF; + uint64_t val64 = 0xFFFFFFFFFFFFFFFF; + size_t offset = 0; + CK_ULONG val_size; + bool ret; + + offset = 4; + ret = p11_rpc_buffer_get_ulong_value(&buf, &offset, &val, &val_size); + assert_num_eq (true, ret); + assert_num_eq (12, offset); + assert_num_eq (sizeof(val), val_size); + assert_num_eq (0x23456789, val); + + p11_buffer_init (&buffer, 0); + + offset = 0; + val_size = 8; + ret = p11_rpc_buffer_get_ulong_value (&buffer, &offset, &val64, &val_size); + assert_num_eq (0, ret); + assert_num_eq (0, offset); + assert_num_eq (sizeof(val), val_size); + assert (0xFFFFFFFFFFFFFFFF == val64); + + p11_buffer_reset (&buffer, 0); + + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + val64 = 0x0123456708ABCDEF; + p11_rpc_buffer_add_ulong_value (&buffer, &val64, sizeof(val64)); + assert (!p11_buffer_failed (&buffer)); + + assert_num_eq (15, buffer.len); + + val64 = 0xFFFFFFFFFFFFFFFF; + offset = 7; + ret = p11_rpc_buffer_get_ulong_value (&buffer, &offset, &val64, &val_size); + assert_num_eq (true, ret); + assert_num_eq (15, offset); + assert (0x0123456708ABCDEF == val64); + + /* Read out of bound */ + val64 = 0xFFFFFFFFFFFFFFFF; + ret = p11_rpc_buffer_get_ulong_value (&buffer, &offset, &val64, &val_size); + assert_num_eq (false, ret); + + p11_buffer_uninit (&buffer); +} + +static void +test_attribute_array_value (void) +{ + p11_buffer buffer; + CK_BBOOL truev = CK_TRUE; + char labelv[] = "label"; + CK_ATTRIBUTE attrs[] = { + { CKA_MODIFIABLE, &truev, sizeof (truev) }, + { CKA_LABEL, labelv, sizeof (labelv) } + }; + CK_BBOOL boolv = CK_FALSE; + char strv[] = "\0\0\0\0\0"; + CK_ATTRIBUTE val[] = { + { CKA_MODIFIABLE, &boolv, sizeof (boolv) }, + { CKA_LABEL, strv, sizeof (strv) } + }; + CK_ULONG val_size; + size_t offset = 0, offset2; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_rpc_buffer_add_attribute_array_value(&buffer, attrs, sizeof(attrs)); + assert (!p11_buffer_failed (&buffer)); + + offset2 = offset; + ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, NULL, &val_size); + assert_num_eq (true, ret); + + offset = offset2; + ret = p11_rpc_buffer_get_attribute_array_value(&buffer, &offset, val, &val_size); + assert_num_eq (true, ret); + assert_num_eq (val[0].type, CKA_MODIFIABLE); + assert_num_eq (*(CK_BBOOL *)val[0].pValue, CK_TRUE); + assert_num_eq (val[0].ulValueLen, sizeof (truev)); + assert_num_eq (val[1].type, CKA_LABEL); + assert_str_eq (val[1].pValue, "label"); + assert_num_eq (val[1].ulValueLen, sizeof (labelv)); + + p11_buffer_uninit (&buffer); +} + +static void +test_mechanism_type_array_value (void) +{ + p11_buffer buffer; + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_DSA, CKM_SHA256_RSA_PKCS }; + CK_MECHANISM_TYPE val[3]; + CK_ULONG val_size; + size_t offset = 0, offset2; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_rpc_buffer_add_mechanism_type_array_value(&buffer, mechs, sizeof(mechs)); + assert (!p11_buffer_failed (&buffer)); + + offset2 = offset; + ret = p11_rpc_buffer_get_mechanism_type_array_value(&buffer, &offset, NULL, &val_size); + assert_num_eq (true, ret); + + offset = offset2; + ret = p11_rpc_buffer_get_mechanism_type_array_value(&buffer, &offset, val, &val_size); + assert_num_eq (true, ret); + assert_num_eq (val[0], CKM_RSA_PKCS); + assert_num_eq (val[1], CKM_DSA); + assert_num_eq (val[2], CKM_SHA256_RSA_PKCS); + + p11_buffer_uninit (&buffer); +} + +static void +test_date_value (void) +{ + p11_buffer buffer; + CK_DATE date, val; + size_t offset = 0; + CK_ULONG val_size; + bool ret; + + memcpy (date.year, "2017", 4); + memcpy (date.month, "05", 2); + memcpy (date.day, "16", 2); + + p11_buffer_init (&buffer, 0); + + p11_rpc_buffer_add_date_value(&buffer, &date, sizeof(date)); + assert (!p11_buffer_failed (&buffer)); + + ret = p11_rpc_buffer_get_date_value(&buffer, &offset, &val, &val_size); + assert_num_eq (true, ret); + + assert (memcmp (val.year, date.year, 4) == 0); + assert (memcmp (val.month, date.month, 2) == 0); + assert (memcmp (val.day, date.day, 2) == 0); + + p11_buffer_uninit (&buffer); +} + +static void +test_byte_array_value (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 }; + + unsigned char val[32]; + size_t offset = 0; + CK_ULONG val_size; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_rpc_buffer_add_byte_array_value(&buffer, bytes, sizeof(bytes)); + assert (!p11_buffer_failed (&buffer)); + + ret = p11_rpc_buffer_get_byte_array_value(&buffer, &offset, val, &val_size); + assert_num_eq (true, ret); + + assert_num_eq (bytes[0], val[0]); + + p11_buffer_uninit (&buffer); +} + static p11_virtual base; static unsigned int rpc_initialized = 0; @@ -1036,6 +1251,12 @@ main (int argc, 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_byte_value, "/rpc/byte-value"); + p11_test (test_ulong_value, "/rpc/ulong-value"); + p11_test (test_attribute_array_value, "/rpc/attribute-array-value"); + p11_test (test_mechanism_type_array_value, "/rpc/mechanism-type-array-value"); + p11_test (test_date_value, "/rpc/date-value"); + p11_test (test_byte_array_value, "/rpc/byte-array-value"); p11_test (test_initialize_fails_on_client, "/rpc/initialize-fails-on-client"); p11_test (test_initialize_fails_on_server, "/rpc/initialize-fails-on-server"); From 34cdae5984d43000681d8e681ae9af5a03f61e8c Mon Sep 17 00:00:00 2001 From: turly221 Date: Tue, 3 Dec 2024 03:24:48 +0000 Subject: [PATCH 2/3] commit patch 12092441 --- p11-kit/rpc-message.c | 2 +- p11-kit/rpc-message.c.orig | 509 +++++++++++++++++++++++++++++++++++-- 2 files changed, 492 insertions(+), 19 deletions(-) diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c index 27f062cf3..a7e5167ee 100644 --- a/p11-kit/rpc-message.c +++ b/p11-kit/rpc-message.c @@ -741,7 +741,7 @@ p11_rpc_buffer_get_byte_array (p11_buffer *buf, return false; } - if (buf->len < len || *offset > buf->len - len) { + if (buf->len < len || off > buf->len - len) { p11_buffer_fail (buf); return false; } diff --git a/p11-kit/rpc-message.c.orig b/p11-kit/rpc-message.c.orig index b5ac52888..27f062cf3 100644 --- a/p11-kit/rpc-message.c.orig +++ b/p11-kit/rpc-message.c.orig @@ -35,6 +35,7 @@ #include "config.h" +#define P11_DEBUG_FLAG P11_DEBUG_RPC #include "debug.h" #include "library.h" #include "message.h" @@ -44,6 +45,8 @@ #include #include +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + void p11_rpc_message_init (p11_rpc_message *msg, p11_buffer *input, @@ -254,8 +257,6 @@ p11_rpc_message_write_attribute_array (p11_rpc_message *msg, CK_ULONG num) { CK_ULONG i; - CK_ATTRIBUTE_PTR attr; - unsigned char validity; assert (num == 0 || arr != NULL); assert (msg != NULL); @@ -267,22 +268,8 @@ p11_rpc_message_write_attribute_array (p11_rpc_message *msg, /* 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); - } - } + for (i = 0; i < num; ++i) + p11_rpc_buffer_add_attribute (msg->output, &(arr[i])); return !p11_buffer_failed (msg->output); } @@ -767,3 +754,489 @@ p11_rpc_buffer_get_byte_array (p11_buffer *buf, return true; } + +static p11_rpc_value_type +map_attribute_to_value_type (CK_ATTRIBUTE_TYPE type) +{ + switch (type) { + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_TRUSTED: + case CKA_SENSITIVE: + case CKA_ENCRYPT: + case CKA_DECRYPT: + case CKA_WRAP: + case CKA_UNWRAP: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_DERIVE: + case CKA_EXTRACTABLE: + case CKA_LOCAL: + case CKA_NEVER_EXTRACTABLE: + case CKA_ALWAYS_SENSITIVE: + case CKA_MODIFIABLE: + case CKA_COPYABLE: + case CKA_SECONDARY_AUTH: /* Deprecated */ + case CKA_ALWAYS_AUTHENTICATE: + case CKA_WRAP_WITH_TRUSTED: + case CKA_RESET_ON_INIT: + case CKA_HAS_RESET: + case CKA_COLOR: + return P11_RPC_VALUE_BYTE; + case CKA_CLASS: + case CKA_CERTIFICATE_TYPE: + case CKA_CERTIFICATE_CATEGORY: + case CKA_JAVA_MIDP_SECURITY_DOMAIN: + case CKA_KEY_TYPE: + case CKA_MODULUS_BITS: + case CKA_PRIME_BITS: + case CKA_SUB_PRIME_BITS: + case CKA_VALUE_BITS: + case CKA_VALUE_LEN: + case CKA_KEY_GEN_MECHANISM: + case CKA_AUTH_PIN_FLAGS: /* Deprecated */ + case CKA_HW_FEATURE_TYPE: + case CKA_PIXEL_X: + case CKA_PIXEL_Y: + case CKA_RESOLUTION: + case CKA_CHAR_ROWS: + case CKA_CHAR_COLUMNS: + case CKA_BITS_PER_PIXEL: + case CKA_MECHANISM_TYPE: + return P11_RPC_VALUE_ULONG; + case CKA_WRAP_TEMPLATE: + case CKA_UNWRAP_TEMPLATE: + return P11_RPC_VALUE_ATTRIBUTE_ARRAY; + case CKA_ALLOWED_MECHANISMS: + return P11_RPC_VALUE_MECHANISM_TYPE_ARRAY; + case CKA_START_DATE: + case CKA_END_DATE: + return P11_RPC_VALUE_DATE; + default: + p11_debug ("cannot determine the type of attribute value for %lu; assuming byte array", + type); + /* fallthrough */ + case CKA_LABEL: + case CKA_APPLICATION: + case CKA_VALUE: + case CKA_OBJECT_ID: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + case CKA_AC_ISSUER: + case CKA_OWNER: + case CKA_ATTR_TYPES: + case CKA_URL: + case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: + case CKA_HASH_OF_ISSUER_PUBLIC_KEY: + case CKA_CHECK_VALUE: + case CKA_SUBJECT: + case CKA_ID: + case CKA_MODULUS: + case CKA_PUBLIC_EXPONENT: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + case CKA_PRIME: + case CKA_SUBPRIME: + case CKA_BASE: + case CKA_EC_PARAMS: + /* same as CKA_ECDSA_PARAMS */ + case CKA_EC_POINT: + case CKA_CHAR_SETS: + case CKA_ENCODING_METHODS: + case CKA_MIME_TYPES: + case CKA_REQUIRED_CMS_ATTRIBUTES: + case CKA_DEFAULT_CMS_ATTRIBUTES: + case CKA_SUPPORTED_CMS_ATTRIBUTES: + return P11_RPC_VALUE_BYTE_ARRAY; + } +} + +void +p11_rpc_buffer_add_byte_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_BYTE byte_value; + + /* Check if value can be converted to CK_BYTE. */ + if (value_length > sizeof (CK_BYTE)) { + p11_buffer_fail (buffer); + return; + } + memcpy (&byte_value, value, value_length); + + /* Check if byte_value can be converted to uint8_t. */ + if (byte_value > UINT8_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_byte (buffer, byte_value); +} + +void +p11_rpc_buffer_add_ulong_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_ULONG ulong_value; + + /* Check if value can be converted to CK_ULONG. */ + if (value_length > sizeof (CK_ULONG)) { + p11_buffer_fail (buffer); + return; + } + memcpy (&ulong_value, value, value_length); + + /* Check if ulong_value can be converted to uint64_t. */ + if (ulong_value > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_uint64 (buffer, ulong_value); +} + +void +p11_rpc_buffer_add_attribute_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + const CK_ATTRIBUTE *attrs = value; + size_t count = value_length / sizeof (CK_ATTRIBUTE); + size_t i; + + /* Check if count can be converted to uint32_t. */ + if (count > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + /* Write the number of items */ + p11_rpc_buffer_add_uint32 (buffer, count); + + /* Actually write the attributes. */ + for (i = 0; i < count; i++) { + const CK_ATTRIBUTE *attr = &(attrs[i]); + p11_rpc_buffer_add_attribute (buffer, attr); + } +} + +void +p11_rpc_buffer_add_mechanism_type_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + const CK_MECHANISM_TYPE *mechs = value; + size_t count = value_length / sizeof (CK_MECHANISM_TYPE); + size_t i; + + /* Check if count can be converted to uint32_t. */ + if (count > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + /* Write the number of items */ + p11_rpc_buffer_add_uint32 (buffer, count); + + for (i = 0; i < count; i++) { + if (mechs[i] > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint64 (buffer, mechs[i]); + } +} + +void +p11_rpc_buffer_add_date_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_DATE date_value; + unsigned char array[8]; + + /* Check if value can be converted to CK_DATE. */ + if (value_length > sizeof (CK_DATE)) { + p11_buffer_fail (buffer); + return; + } + + memcpy (&date_value, value, value_length); + memcpy (array, date_value.year, 4); + memcpy (array + 4, date_value.month, 2); + memcpy (array + 6, date_value.day, 2); + + p11_rpc_buffer_add_byte_array (buffer, array, 8); +} + +void +p11_rpc_buffer_add_byte_array_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + /* Check if value length can be converted to uint32_t, as + * p11_rpc_buffer_add_byte_array expects. */ + if (value_length > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_byte_array (buffer, value, value_length); +} + +void +p11_rpc_buffer_add_attribute (p11_buffer *buffer, const CK_ATTRIBUTE *attr) +{ + unsigned char validity; + static const p11_rpc_value_encoder encoders[] = { + p11_rpc_buffer_add_byte_value, + p11_rpc_buffer_add_ulong_value, + p11_rpc_buffer_add_attribute_array_value, + p11_rpc_buffer_add_mechanism_type_array_value, + p11_rpc_buffer_add_date_value, + p11_rpc_buffer_add_byte_array_value + }; + p11_rpc_value_encoder encoder; + p11_rpc_value_type value_type; + + /* The attribute type */ + if (attr->type > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint32 (buffer, attr->type); + + /* Write out the attribute validity */ + validity = (((CK_LONG)attr->ulValueLen) == -1) ? 0 : 1; + p11_rpc_buffer_add_byte (buffer, validity); + + if (!validity) + return; + + /* The attribute length */ + if (attr->ulValueLen > UINT32_MAX) { + p11_buffer_fail (buffer); + return; + } + p11_rpc_buffer_add_uint32 (buffer, attr->ulValueLen); + + /* The attribute value */ + value_type = map_attribute_to_value_type (attr->type); + assert (value_type < ELEMS (encoders)); + encoder = encoders[value_type]; + assert (encoder != NULL); + encoder (buffer, attr->pValue, attr->ulValueLen); +} + +bool +p11_rpc_buffer_get_byte_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + unsigned char val; + + if (!p11_rpc_buffer_get_byte (buffer, offset, &val)) + return false; + + if (value) { + CK_BYTE byte_value = val; + memcpy (value, &byte_value, sizeof (CK_BYTE)); + } + + if (value_length) + *value_length = sizeof (CK_BYTE); + + return true; +} + +bool +p11_rpc_buffer_get_ulong_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint64_t val; + + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val)) + return false; + + if (value) { + CK_ULONG ulong_value = val; + memcpy (value, &ulong_value, sizeof (CK_ULONG)); + } + + if (value_length) + *value_length = sizeof (CK_ULONG); + + return true; +} + +bool +p11_rpc_buffer_get_attribute_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint32_t count, i; + CK_ATTRIBUTE *attr, temp; + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &count)) + return false; + + if (!value) { + memset (&temp, 0, sizeof (CK_ATTRIBUTE)); + attr = &temp; + } else + attr = value; + + for (i = 0; i < count; i++) { + if (!p11_rpc_buffer_get_attribute (buffer, offset, attr)) + return false; + if (value) + attr++; + } + + if (value_length) + *value_length = count * sizeof (CK_ATTRIBUTE); + + return true; +} + +bool +p11_rpc_buffer_get_mechanism_type_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint32_t count, i; + CK_MECHANISM_TYPE *mech, temp; + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &count)) + return false; + + if (!value) { + memset (&temp, 0, sizeof (CK_MECHANISM_TYPE)); + mech = &temp; + } else + mech = value; + + for (i = 0; i < count; i++) { + CK_ULONG len; + if (!p11_rpc_buffer_get_ulong_value (buffer, offset, mech, &len)) + return false; + if (value) + mech++; + } + + if (value_length) + *value_length = count * sizeof (CK_MECHANISM_TYPE); + + return true; +} + +bool +p11_rpc_buffer_get_date_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + CK_DATE date_value; + const unsigned char *array; + size_t array_length; + + if (!p11_rpc_buffer_get_byte_array (buffer, offset, + &array, &array_length) || + array_length != 8) + return false; + + if (value) { + memcpy (date_value.year, array, 4); + memcpy (date_value.month, array + 4, 2); + memcpy (date_value.day, array + 6, 2); + memcpy (value, &date_value, sizeof (CK_DATE)); + } + + if (value_length) + *value_length = sizeof (CK_DATE); + + return true; +} + +bool +p11_rpc_buffer_get_byte_array_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + const unsigned char *val; + size_t len; + + if (!p11_rpc_buffer_get_byte_array (buffer, offset, &val, &len)) + return false; + + if (val && value) + memcpy (value, val, len); + + if (value_length) + *value_length = len; + + return true; +} + +bool +p11_rpc_buffer_get_attribute (p11_buffer *buffer, + size_t *offset, + CK_ATTRIBUTE *attr) +{ + uint32_t type, length; + unsigned char validity; + static const p11_rpc_value_decoder decoders[] = { + p11_rpc_buffer_get_byte_value, + p11_rpc_buffer_get_ulong_value, + p11_rpc_buffer_get_attribute_array_value, + p11_rpc_buffer_get_mechanism_type_array_value, + p11_rpc_buffer_get_date_value, + p11_rpc_buffer_get_byte_array_value + }; + p11_rpc_value_decoder decoder; + p11_rpc_value_type value_type; + + /* The attribute type */ + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &type)) + return false; + + /* Attribute validity */ + if (!p11_rpc_buffer_get_byte (buffer, offset, &validity)) + return false; + + /* Not a valid attribute */ + if (!validity) { + attr->ulValueLen = ((CK_ULONG)-1); + attr->type = type; + return true; + } + + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &length)) + return false; + + /* Decode the attribute value */ + value_type = map_attribute_to_value_type (type); + assert (value_type < ELEMS (decoders)); + decoder = decoders[value_type]; + assert (decoder != NULL); + if (!decoder (buffer, offset, attr->pValue, &attr->ulValueLen)) + return false; + if (!attr->pValue) + attr->ulValueLen = length; + attr->type = type; + return true; +} From 89b083c98d6ef454c4bd2f7a556e54b432131c83 Mon Sep 17 00:00:00 2001 From: turly221 Date: Tue, 3 Dec 2024 03:24:50 +0000 Subject: [PATCH 3/3] commit patch 12160923 --- p11-kit/rpc-message.c | 9 +++++++-- p11-kit/rpc-message.c.orig | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c index a7e5167ee..828218188 100644 --- a/p11-kit/rpc-message.c +++ b/p11-kit/rpc-message.c @@ -1197,7 +1197,7 @@ p11_rpc_buffer_get_attribute (p11_buffer *buffer, size_t *offset, CK_ATTRIBUTE *attr) { - uint32_t type, length; + uint32_t type, length, decode_length; unsigned char validity; static const p11_rpc_value_decoder decoders[] = { p11_rpc_buffer_get_byte_value, @@ -1235,8 +1235,13 @@ p11_rpc_buffer_get_attribute (p11_buffer *buffer, assert (decoder != NULL); if (!decoder (buffer, offset, attr->pValue, &attr->ulValueLen)) return false; - if (!attr->pValue) + if (!attr->pValue) { + decode_length = attr->ulValueLen; attr->ulValueLen = length; + if (decode_length > length) { + return false; + } + } attr->type = type; return true; } diff --git a/p11-kit/rpc-message.c.orig b/p11-kit/rpc-message.c.orig index 27f062cf3..a7e5167ee 100644 --- a/p11-kit/rpc-message.c.orig +++ b/p11-kit/rpc-message.c.orig @@ -741,7 +741,7 @@ p11_rpc_buffer_get_byte_array (p11_buffer *buf, return false; } - if (buf->len < len || *offset > buf->len - len) { + if (buf->len < len || off > buf->len - len) { p11_buffer_fail (buf); return false; }