From 614202485fe0fc8b581468e5419d8251568d6608 Mon Sep 17 00:00:00 2001 From: turly221 Date: Tue, 3 Dec 2024 03:24:18 +0000 Subject: [PATCH 1/2] commit patch 12092471 --- p11-kit/rpc-message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c index bccfd2ac1..345a038e0 100644 --- a/p11-kit/rpc-message.c +++ b/p11-kit/rpc-message.c @@ -744,7 +744,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; } From f1193df4815cb8b709f11a959e4c50e86b6baa1c Mon Sep 17 00:00:00 2001 From: turly221 Date: Tue, 3 Dec 2024 03:24:19 +0000 Subject: [PATCH 2/2] commit patch 12160961 --- p11-kit/rpc-message.c | 9 +- p11-kit/rpc-message.c.orig | 1588 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1595 insertions(+), 2 deletions(-) create mode 100644 p11-kit/rpc-message.c.orig diff --git a/p11-kit/rpc-message.c b/p11-kit/rpc-message.c index 345a038e0..9edf6ec55 100644 --- a/p11-kit/rpc-message.c +++ b/p11-kit/rpc-message.c @@ -1209,7 +1209,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; p11_rpc_attribute_serializer *serializer; p11_rpc_value_type value_type; @@ -1239,8 +1239,13 @@ p11_rpc_buffer_get_attribute (p11_buffer *buffer, assert (serializer != NULL); if (!serializer->decode (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 new file mode 100644 index 000000000..345a038e0 --- /dev/null +++ b/p11-kit/rpc-message.c.orig @@ -0,0 +1,1588 @@ +/* + * 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 "library.h" +#include "message.h" +#include "private.h" +#include "rpc-message.h" + +#include +#include + +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + +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 || + (type == P11_RPC_REQUEST && call_id == P11_RPC_CALL_ERROR)) { + 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) || + /* This can happen if the length header == 0xffffffff */ + val == NULL) { + 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; + + 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) + p11_rpc_buffer_add_attribute (msg->output, &(arr[i])); + + 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 || off > 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; +} + +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; + } +} + +typedef struct { + p11_rpc_value_type type; + p11_rpc_value_encoder encode; + p11_rpc_value_decoder decode; +} p11_rpc_attribute_serializer; + +static p11_rpc_attribute_serializer p11_rpc_attribute_serializers[] = { + { P11_RPC_VALUE_BYTE, p11_rpc_buffer_add_byte_value, p11_rpc_buffer_get_byte_value }, + { P11_RPC_VALUE_ULONG, p11_rpc_buffer_add_ulong_value, p11_rpc_buffer_get_ulong_value }, + { P11_RPC_VALUE_ATTRIBUTE_ARRAY, p11_rpc_buffer_add_attribute_array_value, p11_rpc_buffer_get_attribute_array_value }, + { P11_RPC_VALUE_MECHANISM_TYPE_ARRAY, p11_rpc_buffer_add_mechanism_type_array_value, p11_rpc_buffer_get_mechanism_type_array_value }, + { P11_RPC_VALUE_DATE, p11_rpc_buffer_add_date_value, p11_rpc_buffer_get_date_value }, + { P11_RPC_VALUE_BYTE_ARRAY, p11_rpc_buffer_add_byte_array_value, p11_rpc_buffer_get_byte_array_value } +}; + +void +p11_rpc_buffer_add_byte_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_BYTE byte_value = 0; + + /* Check if value can be converted to CK_BYTE. */ + if (value_length > sizeof (CK_BYTE)) { + p11_buffer_fail (buffer); + return; + } + if (value) + 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 = 0; + + /* Check if value can be converted to CK_ULONG. */ + if (value_length > sizeof (CK_ULONG)) { + p11_buffer_fail (buffer); + return; + } + if (value) + 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; + p11_rpc_attribute_serializer *serializer; + 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 (p11_rpc_attribute_serializers)); + serializer = &p11_rpc_attribute_serializers[value_type]; + assert (serializer != NULL); + serializer->encode (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; + p11_rpc_attribute_serializer *serializer; + 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 (p11_rpc_attribute_serializers)); + serializer = &p11_rpc_attribute_serializers[value_type]; + assert (serializer != NULL); + if (!serializer->decode (buffer, offset, attr->pValue, &attr->ulValueLen)) + return false; + if (!attr->pValue) + attr->ulValueLen = length; + attr->type = type; + return true; +} + +/* Used to override the supported mechanisms in tests */ +CK_MECHANISM_TYPE *p11_rpc_mechanisms_override_supported = NULL; + +typedef struct { + CK_MECHANISM_TYPE type; + p11_rpc_value_encoder encode; + p11_rpc_value_decoder decode; +} p11_rpc_mechanism_serializer; + +void +p11_rpc_buffer_add_rsa_pkcs_pss_mechanism_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_RSA_PKCS_PSS_PARAMS params; + + /* Check if value can be converted to CK_RSA_PKCS_PSS_PARAMS. */ + if (value_length != sizeof (CK_RSA_PKCS_PSS_PARAMS)) { + p11_buffer_fail (buffer); + return; + } + + memcpy (¶ms, value, value_length); + + /* Check if params.hashAlg, params.mgf, and params.sLen can be + * converted to uint64_t. */ + if (params.hashAlg > UINT64_MAX || params.mgf > UINT64_MAX || + params.sLen > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_uint64 (buffer, params.hashAlg); + p11_rpc_buffer_add_uint64 (buffer, params.mgf); + p11_rpc_buffer_add_uint64 (buffer, params.sLen); +} + +bool +p11_rpc_buffer_get_rsa_pkcs_pss_mechanism_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint64_t val[3]; + + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[0])) + return false; + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[1])) + return false; + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[2])) + return false; + + if (value) { + CK_RSA_PKCS_PSS_PARAMS params; + + params.hashAlg = val[0]; + params.mgf = val[1]; + params.sLen = val[2]; + + memcpy (value, ¶ms, sizeof (CK_RSA_PKCS_PSS_PARAMS)); + } + + if (value_length) + *value_length = sizeof (CK_RSA_PKCS_PSS_PARAMS); + + return true; +} + +void +p11_rpc_buffer_add_rsa_pkcs_oaep_mechanism_value (p11_buffer *buffer, + const void *value, + CK_ULONG value_length) +{ + CK_RSA_PKCS_OAEP_PARAMS params; + + /* Check if value can be converted to CK_RSA_PKCS_OAEP_PARAMS. */ + if (value_length != sizeof (CK_RSA_PKCS_OAEP_PARAMS)) { + p11_buffer_fail (buffer); + return; + } + + memcpy (¶ms, value, value_length); + + /* Check if params.hashAlg, params.mgf, and params.source can be + * converted to uint64_t. */ + if (params.hashAlg > UINT64_MAX || params.mgf > UINT64_MAX || + params.source > UINT64_MAX) { + p11_buffer_fail (buffer); + return; + } + + p11_rpc_buffer_add_uint64 (buffer, params.hashAlg); + p11_rpc_buffer_add_uint64 (buffer, params.mgf); + p11_rpc_buffer_add_uint64 (buffer, params.source); + + /* parmas.pSourceData can only be an array of CK_BYTE or + * NULL */ + p11_rpc_buffer_add_byte_array (buffer, + (unsigned char *)params.pSourceData, + params.ulSourceDataLen); +} + +bool +p11_rpc_buffer_get_rsa_pkcs_oaep_mechanism_value (p11_buffer *buffer, + size_t *offset, + void *value, + CK_ULONG *value_length) +{ + uint64_t val[3]; + const unsigned char *data; + size_t len; + + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[0])) + return false; + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[1])) + return false; + if (!p11_rpc_buffer_get_uint64 (buffer, offset, &val[2])) + return false; + if (!p11_rpc_buffer_get_byte_array (buffer, offset, &data, &len)) + return false; + + if (value) { + CK_RSA_PKCS_OAEP_PARAMS params; + + params.hashAlg = val[0]; + params.mgf = val[1]; + params.source = val[2]; + params.pSourceData = (void *) data; + params.ulSourceDataLen = len; + + memcpy (value, ¶ms, sizeof (CK_RSA_PKCS_OAEP_PARAMS)); + } + + if (value_length) + *value_length = sizeof (CK_RSA_PKCS_OAEP_PARAMS); + + return true; +} + +static p11_rpc_mechanism_serializer p11_rpc_mechanism_serializers[] = { + { CKM_RSA_PKCS_PSS, p11_rpc_buffer_add_rsa_pkcs_pss_mechanism_value, p11_rpc_buffer_get_rsa_pkcs_pss_mechanism_value }, + { CKM_RSA_PKCS_OAEP, p11_rpc_buffer_add_rsa_pkcs_oaep_mechanism_value, p11_rpc_buffer_get_rsa_pkcs_oaep_mechanism_value } +}; + +static p11_rpc_mechanism_serializer p11_rpc_byte_array_mechanism_serializer = { + 0, p11_rpc_buffer_add_byte_array_value, p11_rpc_buffer_get_byte_array_value +}; + +static bool +mechanism_has_sane_parameters (CK_MECHANISM_TYPE type) +{ + int i; + + /* This can be set from tests, to override default set of supported */ + if (p11_rpc_mechanisms_override_supported) { + for (i = 0; p11_rpc_mechanisms_override_supported[i] != 0; i++) { + if (p11_rpc_mechanisms_override_supported[i] == type) + return true; + } + + return false; + } + + for (i = 0; i < ELEMS(p11_rpc_mechanism_serializers); i++) { + if (p11_rpc_mechanism_serializers[i].type == type) + return true; + } + + return false; +} + +static bool +mechanism_has_no_parameters (CK_MECHANISM_TYPE mech) +{ + /* This list is incomplete */ + + switch (mech) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + case CKM_RSA_X9_31_KEY_PAIR_GEN: + case CKM_RSA_PKCS: + case CKM_RSA_9796: + case CKM_RSA_X_509: + case CKM_RSA_X9_31: + case CKM_MD2_RSA_PKCS: + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_RIPEMD128_RSA_PKCS: + case CKM_RIPEMD160_RSA_PKCS: + case CKM_SHA1_RSA_X9_31: + case CKM_DSA_KEY_PAIR_GEN: + case CKM_DSA_PARAMETER_GEN: + case CKM_DSA: + case CKM_DSA_SHA1: + case CKM_FORTEZZA_TIMESTAMP: + case CKM_EC_KEY_PAIR_GEN: + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_DH_PKCS_KEY_PAIR_GEN: + case CKM_DH_PKCS_PARAMETER_GEN: + case CKM_X9_42_DH_KEY_PAIR_GEN: + case CKM_X9_42_DH_PARAMETER_GEN: + case CKM_KEA_KEY_PAIR_GEN: + case CKM_GENERIC_SECRET_KEY_GEN: + case CKM_RC2_KEY_GEN: + case CKM_RC4_KEY_GEN: + case CKM_RC4: + case CKM_RC5_KEY_GEN: + case CKM_AES_KEY_GEN: + case CKM_AES_ECB: + case CKM_AES_MAC: + case CKM_DES_KEY_GEN: + case CKM_DES2_KEY_GEN: + case CKM_DES3_KEY_GEN: + case CKM_CDMF_KEY_GEN: + case CKM_CAST_KEY_GEN: + case CKM_CAST3_KEY_GEN: + case CKM_CAST128_KEY_GEN: + case CKM_IDEA_KEY_GEN: + case CKM_SSL3_PRE_MASTER_KEY_GEN: + case CKM_TLS_PRE_MASTER_KEY_GEN: + case CKM_SKIPJACK_KEY_GEN: + case CKM_BATON_KEY_GEN: + case CKM_JUNIPER_KEY_GEN: + case CKM_RC2_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST128_ECB: + case CKM_RC5_ECB: + case CKM_IDEA_ECB: + case CKM_RC2_MAC: + case CKM_DES_MAC: + case CKM_DES3_MAC: + case CKM_CDMF_MAC: + case CKM_CAST_MAC: + case CKM_CAST3_MAC: + case CKM_RC5_MAC: + case CKM_IDEA_MAC: + case CKM_SSL3_MD5_MAC: + case CKM_SSL3_SHA1_MAC: + case CKM_SKIPJACK_WRAP: + case CKM_BATON_WRAP: + case CKM_JUNIPER_WRAP: + case CKM_MD2: + case CKM_MD2_HMAC: + case CKM_MD5: + case CKM_MD5_HMAC: + case CKM_SHA_1: + case CKM_SHA_1_HMAC: + case CKM_SHA256: + case CKM_SHA256_HMAC: + case CKM_SHA384: + case CKM_SHA384_HMAC: + case CKM_SHA512: + case CKM_SHA512_HMAC: + case CKM_FASTHASH: + case CKM_RIPEMD128: + case CKM_RIPEMD128_HMAC: + case CKM_RIPEMD160: + case CKM_RIPEMD160_HMAC: + case CKM_KEY_WRAP_LYNKS: + return true; + default: + return false; + }; +} + +bool +p11_rpc_mechanism_is_supported (CK_MECHANISM_TYPE mech) +{ + if (mechanism_has_no_parameters (mech) || + mechanism_has_sane_parameters (mech)) + return true; + return false; +} + +void +p11_rpc_buffer_add_mechanism (p11_buffer *buffer, const CK_MECHANISM *mech) +{ + p11_rpc_mechanism_serializer *serializer = NULL; + size_t i; + + /* The mechanism type */ + p11_rpc_buffer_add_uint32 (buffer, mech->mechanism); + + if (mechanism_has_no_parameters (mech->mechanism)) { + p11_rpc_buffer_add_byte_array (buffer, NULL, 0); + return; + } + + assert (mechanism_has_sane_parameters (mech->mechanism)); + + for (i = 0; i < ELEMS (p11_rpc_mechanism_serializers); i++) { + if (p11_rpc_mechanism_serializers[i].type == mech->mechanism) { + serializer = &p11_rpc_mechanism_serializers[i]; + break; + } + } + + if (serializer == NULL) + serializer = &p11_rpc_byte_array_mechanism_serializer; + + serializer->encode (buffer, mech->pParameter, mech->ulParameterLen); +} + +bool +p11_rpc_buffer_get_mechanism (p11_buffer *buffer, + size_t *offset, + CK_MECHANISM *mech) +{ + uint32_t mechanism; + p11_rpc_mechanism_serializer *serializer = NULL; + size_t i; + + /* The mechanism type */ + if (!p11_rpc_buffer_get_uint32 (buffer, offset, &mechanism)) + return false; + + mech->mechanism = mechanism; + + for (i = 0; i < ELEMS (p11_rpc_mechanism_serializers); i++) { + if (p11_rpc_mechanism_serializers[i].type == mech->mechanism) { + serializer = &p11_rpc_mechanism_serializers[i]; + break; + } + } + + if (serializer == NULL) + serializer = &p11_rpc_byte_array_mechanism_serializer; + + if (!serializer->decode (buffer, offset, + mech->pParameter, &mech->ulParameterLen)) + return false; + + return true; +}