diff options
author | Daiki Ueno <dueno@redhat.com> | 2017-05-11 15:26:36 +0200 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2017-05-22 17:19:20 +0200 |
commit | ba49b85ecf280e7fb6eec96c3ef33c50122e75a6 (patch) | |
tree | 7ecbde7a26eca8e14c72616ab5556eb618f2d8a2 | |
parent | 480337a68446033dc9374e9c4fe4d3cae9d4e972 (diff) |
rpc: Convert attribute value for portability
When using the RPC across multiple architectures, where data models
are different, say LP64 vs ILP32, there can be unwanted truncation of
attribute values.
This patch converts the values into portable format for the known
attributes.
Co-authored-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | p11-kit/rpc-client.c | 63 | ||||
-rw-r--r-- | p11-kit/rpc-message.c | 509 | ||||
-rw-r--r-- | p11-kit/rpc-message.h | 77 | ||||
-rw-r--r-- | p11-kit/rpc-server.c | 35 | ||||
-rw-r--r-- | p11-kit/test-rpc.c | 223 |
5 files changed, 827 insertions, 80 deletions
diff --git a/p11-kit/rpc-client.c b/p11-kit/rpc-client.c index c69dcfd..3521ddd 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 d1b491d..25d8a7b 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 <assert.h> #include <string.h> +#define ELEMS(x) (sizeof (x) / sizeof (x[0])) + void p11_rpc_message_init (p11_rpc_message *msg, p11_buffer *input, @@ -255,8 +258,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); @@ -268,22 +269,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); } @@ -768,3 +755,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.h b/p11-kit/rpc-message.h index 9827097..5c81c1c 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 071064f..dec9b0b 100644 --- a/p11-kit/rpc-server.c +++ b/p11-kit/rpc-server.c @@ -281,11 +281,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); @@ -306,34 +302,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/test-rpc.c b/p11-kit/test-rpc.c index c9f8333..c6490bf 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"); |