From 09a065bb67bf055da0417a6c972c11ba5ab13da0 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Tue, 8 Nov 2016 01:44:50 -0500 Subject: First cut at multi-attribute get/set/delete API. This is not yet complete, only the ks_volatile driver supports it, ks_flash will be a bit more complicated and isn't written yet. At the moment, this adds a complete duplicate set of {set,get,delete}_attributes() functions in parallel to the earlier {set,get,delete}_attribute() functions. We will almost certainly want to get rid of the duplicates, probably (but not necessarily) the entire single-attribute suite. At the moment, though, we want both sets so we can compare execution speeds of the two sets of functions. --- hal.h | 17 +++++- hal_internal.h | 137 ++++++++++++++++++++++++++++++----------------- ks_flash.c | 2 +- ks_volatile.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- libhal.py | 33 ++++++++++-- rpc_api.c | 32 ++++++++++- rpc_client.c | 115 ++++++++++++++++++++++++++++++++++++++-- rpc_pkey.c | 79 ++++++++++++++++++++++++++- rpc_server.c | 108 +++++++++++++++++++++++++++++++++++++ unit-tests.py | 116 +++++++++++++++++++++++++++++----------- 10 files changed, 698 insertions(+), 106 deletions(-) diff --git a/hal.h b/hal.h index 9ac17dc..74e0a51 100644 --- a/hal.h +++ b/hal.h @@ -155,6 +155,7 @@ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_CHUNK_MISSING, "Key index chunk missing") \ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_CHUNK_OVERLAPS, "Key index chunk overlaps") \ DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE, "Wrong block type in keystore") \ + DEFINE_HAL_ERROR(HAL_ERROR_RPC_PROTOCOL_ERROR, "RPC protocol error") \ END_OF_HAL_ERROR_LIST /* Marker to forestall silly line continuation errors */ @@ -783,7 +784,7 @@ extern hal_error_t hal_rpc_pkey_match(const hal_client_handle_t client, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -804,6 +805,20 @@ extern hal_error_t hal_rpc_pkey_get_attribute(const hal_pkey_handle_t pkey, extern hal_error_t hal_rpc_pkey_delete_attribute(const hal_pkey_handle_t pkey, const uint32_t type); +extern hal_error_t hal_rpc_pkey_set_attributes(const hal_pkey_handle_t pkey, + const hal_rpc_pkey_attribute_t *const attributes, + const unsigned attributes_len); + +extern hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len); + +extern hal_error_t hal_rpc_pkey_delete_attributes(const hal_pkey_handle_t pkey, + const uint32_t * const types, + const unsigned types_len); + extern hal_error_t hal_rpc_client_init(void); extern hal_error_t hal_rpc_client_close(void); diff --git a/hal_internal.h b/hal_internal.h index 5faba54..6b82b9c 100644 --- a/hal_internal.h +++ b/hal_internal.h @@ -250,7 +250,7 @@ typedef struct { const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -271,6 +271,21 @@ typedef struct { hal_error_t (*delete_attribute)(const hal_pkey_handle_t pkey, const uint32_t type); + + hal_error_t (*set_attributes)(const hal_pkey_handle_t pkey, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len); + + hal_error_t (*get_attributes)(const hal_pkey_handle_t pkey, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len); + + hal_error_t (*delete_attributes)(const hal_pkey_handle_t pkey, + const uint32_t *types, + const unsigned types_len); + } hal_rpc_pkey_dispatch_t; @@ -497,7 +512,7 @@ struct hal_ks_driver { const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -521,6 +536,23 @@ struct hal_ks_driver { hal_pkey_slot_t *slot, const uint32_t type); + hal_error_t (*set_attributes)(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len); + + hal_error_t (*get_attributes)(hal_ks_t *ks, + hal_pkey_slot_t *slot, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len); + + hal_error_t (*delete_attributes)(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const uint32_t *types, + const unsigned types_len); + }; @@ -622,7 +654,7 @@ static inline hal_error_t hal_ks_match(hal_ks_t *ks, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -649,11 +681,11 @@ static inline hal_error_t hal_ks_set_attribute(hal_ks_t *ks, } static inline hal_error_t hal_ks_get_attribute(hal_ks_t *ks, - hal_pkey_slot_t *slot, - const uint32_t type, - uint8_t *value, - size_t *value_len, - const size_t value_max) + hal_pkey_slot_t *slot, + const uint32_t type, + uint8_t *value, + size_t *value_len, + const size_t value_max) { if (ks == NULL || ks->driver == NULL || ks->driver->get_attribute == NULL || slot == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -662,8 +694,8 @@ static inline hal_error_t hal_ks_get_attribute(hal_ks_t *ks, } static inline hal_error_t hal_ks_delete_attribute(hal_ks_t *ks, - hal_pkey_slot_t *slot, - const uint32_t type) + hal_pkey_slot_t *slot, + const uint32_t type) { if (ks == NULL || ks->driver == NULL || ks->driver->delete_attribute == NULL || slot == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -671,6 +703,50 @@ static inline hal_error_t hal_ks_delete_attribute(hal_ks_t *ks, return ks->driver->delete_attribute(ks, slot, type); } +static inline hal_error_t hal_ks_set_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len) +{ + if (ks == NULL || ks->driver == NULL || ks->driver->set_attributes == NULL || slot == NULL || + attributes == NULL || attributes_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + for (int i = 0; i < attributes_len; i++) + if (attributes[i].length == 0 || attributes[i].value == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + return ks->driver->set_attributes(ks, slot, attributes, attributes_len); +} + +static inline hal_error_t hal_ks_get_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len) +{ + if (ks == NULL || ks->driver == NULL || ks->driver->get_attributes == NULL || slot == NULL || + attributes == NULL || attributes_len == 0 || + attributes_buffer == NULL || attributes_buffer_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + return ks->driver->get_attributes(ks, slot, attributes, attributes_len, + attributes_buffer, attributes_buffer_len); +} + +static inline hal_error_t hal_ks_delete_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const uint32_t *types, + const unsigned types_len) +{ + if (ks == NULL || ks->driver == NULL || ks->driver->delete_attributes == NULL || slot == NULL || + types == NULL || types_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + return ks->driver->delete_attributes(ks, slot, types, types_len); +} + /* * Keystore index. This is intended to be usable by both memory-based * (in-memory, mmap(), ...) keystores and keystores based on raw flash. @@ -803,44 +879,6 @@ extern hal_error_t hal_ks_index_fsck(hal_ks_index_t *ksi); /* * Keystore attribute utilities, for use by keystore drivers. - * - * Basic model here is probably to replace the "der" block in a key - * object with a byte array. We could use padding to get alignment, - * but it's probably easier just to do this DNS style, pulling a - * 16-bit length and 32-bit attribute type out of the byte array - * directly. Well, maybe. I guess if we cast the uint8_t* to a - * structure pointer we could use the structure to pull out the header - * fields, but that has portability issues, particulary if the - * compiler gets tetchy about type punning. - * - * Unclear whether we should treat the key DER specially. Might just - * give it an attribute code of 0xFFFFFFFF and treat it same as - * everything else, just always first for convenience. This assumes - * that PKCS #11 will never use 0xFFFFFFFF, which is a bit risky, but - * maybe the code just treats it a little bit specially and knows to - * skip over the key DER when looking for attributes, etc. - * - * We probably don't want to let attributes span block boundaries. We - * probably do want to attempt to fit a new attribute into the first - * available space which can hold it. In theory, taken together, this - * means we will only have to update multiple blocks when required to - * add a new block (in which case the max_blocks count changes). Most - * of this only applies to flash, for volatile we can use as much - * memory as we like, although even there we might want smaller chunks - * to avoid wasting huge tracts of space that don't end up being used. - * But maybe that's just a configuration thing for the volatile - * keystore(s). - * - * If we have to rewrite a block at all we might as well compact it, - * so fragmentation in that sense is a non-issue. Might need to - * collapse blocks when deletion has freed up enough space, but that - * might be something we handle directly in ks_flash rather than in - * the ks_attribute code. - * - * We need some way of figuring out how many attributes there are. - * Options are a marker (like the IPv4 END-OF-OPTIONS option) or a - * count in the header. Count is simpler and lets us pre-allocate - * arrays so probably go with that. */ extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, @@ -919,6 +957,9 @@ typedef enum { RPC_FUNC_PKEY_GET_ATTRIBUTE, RPC_FUNC_PKEY_DELETE_ATTRIBUTE, RPC_FUNC_PKEY_GET_KEY_CURVE, + RPC_FUNC_PKEY_SET_ATTRIBUTES, + RPC_FUNC_PKEY_GET_ATTRIBUTES, + RPC_FUNC_PKEY_DELETE_ATTRIBUTES, } rpc_func_num_t; #define RPC_VERSION 0x01010000 /* 1.1.0.0 */ diff --git a/ks_flash.c b/ks_flash.c index 7a11f0f..c96efd5 100644 --- a/ks_flash.c +++ b/ks_flash.c @@ -1156,7 +1156,7 @@ static hal_error_t ks_match(hal_ks_t *ks, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, diff --git a/ks_volatile.c b/ks_volatile.c index c8a424c..b69c3c0 100644 --- a/ks_volatile.c +++ b/ks_volatile.c @@ -390,7 +390,7 @@ static hal_error_t ks_match(hal_ks_t *ks, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -447,7 +447,7 @@ static hal_error_t ks_match(hal_ks_t *ks, key_attrs, k->attributes_len, NULL)) != HAL_OK) return err; - for (hal_rpc_pkey_attribute_t *required = attributes; + for (const hal_rpc_pkey_attribute_t *required = attributes; ok && required < attributes + attributes_len; required++) { hal_rpc_pkey_attribute_t *present = key_attrs; @@ -470,11 +470,11 @@ static hal_error_t ks_match(hal_ks_t *ks, return HAL_OK; } -static hal_error_t ks_set_attribute(hal_ks_t *ks, - hal_pkey_slot_t *slot, - const uint32_t type, - const uint8_t * const value, - const size_t value_len) +static hal_error_t ks_set_attribute(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const uint32_t type, + const uint8_t * const value, + const size_t value_len) { if (ks == NULL || slot == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -508,12 +508,12 @@ static hal_error_t ks_set_attribute(hal_ks_t *ks, type, value, value_len); } -static hal_error_t ks_get_attribute(hal_ks_t *ks, - hal_pkey_slot_t *slot, - const uint32_t type, - uint8_t *value, - size_t *value_len, - const size_t value_max) +static hal_error_t ks_get_attribute(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const uint32_t type, + uint8_t *value, + size_t *value_len, + const size_t value_max) { if (ks == NULL || slot == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -595,6 +595,140 @@ static hal_error_t ks_delete_attribute(hal_ks_t *ks, return hal_ks_attribute_delete(bytes, bytes_len, attributes, &k->attributes_len, &total_len, type); } +static hal_error_t ks_set_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len) +{ + if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + ks_t *ksv = ks_to_ksv(ks); + hal_error_t err; + unsigned b; + + if (ksv->db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK) + return err; + + ks_key_t * const k = &ksv->db->keys[b]; + + if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_rpc_pkey_attribute_t attrs[k->attributes_len + attributes_len]; + uint8_t *bytes = k->der + k->der_len; + size_t bytes_len = sizeof(k->der) - k->der_len; + size_t total_len; + + if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, k->attributes_len, &total_len)) != HAL_OK) + return err; + + for (const hal_rpc_pkey_attribute_t *a = attributes; a < attributes + attributes_len; a++) + if ((err = hal_ks_attribute_insert(bytes, bytes_len, attrs, &k->attributes_len, &total_len, + a->type, a->value, a->length)) != HAL_OK) + return err; + + return HAL_OK; +} + +static hal_error_t ks_get_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len) +{ + if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0 || + attributes_buffer == NULL || attributes_buffer_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + ks_t *ksv = ks_to_ksv(ks); + hal_error_t err; + unsigned b; + + if (ksv->db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK) + return err; + + const ks_key_t * const k = &ksv->db->keys[b]; + + if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) + return HAL_ERROR_KEY_NOT_FOUND; + + if (k->attributes_len == 0) + return HAL_ERROR_ATTRIBUTE_NOT_FOUND; + + hal_rpc_pkey_attribute_t attrs[k->attributes_len]; + + if ((err = hal_ks_attribute_scan(k->der + k->der_len, sizeof(k->der) - k->der_len, + attrs, k->attributes_len, NULL)) != HAL_OK) + return err; + + uint8_t *abuf = attributes_buffer; + + for (int i = 0; i < attributes_len; i++) { + + int j = 0; + while (attrs[j].type != attributes[i].type) + if (++j >= k->attributes_len) + return HAL_ERROR_ATTRIBUTE_NOT_FOUND; + + if (attrs[j].length > attributes_buffer + attributes_buffer_len - abuf) + return HAL_ERROR_RESULT_TOO_LONG; + + memcpy(abuf, attrs[j].value, attrs[j].length); + attributes[i].value = abuf; + attributes[i].length = attrs[j].length; + abuf += attrs[j].length; + } + + return HAL_OK; +} + +static hal_error_t ks_delete_attributes(hal_ks_t *ks, + hal_pkey_slot_t *slot, + const uint32_t *types, + const unsigned types_len) +{ + if (ks == NULL || slot == NULL || types == NULL || types_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + + ks_t *ksv = ks_to_ksv(ks); + hal_error_t err; + unsigned b; + + if (ksv->db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK) + return err; + + ks_key_t * const k = &ksv->db->keys[b]; + + if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_rpc_pkey_attribute_t attrs[k->attributes_len + 1]; + uint8_t *bytes = k->der + k->der_len; + size_t bytes_len = sizeof(k->der) - k->der_len; + size_t total_len; + + if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, k->attributes_len, &total_len)) != HAL_OK) + return err; + + for (int i = 0; i < types_len; i++) + if ((err = hal_ks_attribute_delete(bytes, bytes_len, attrs, &k->attributes_len, + &total_len, types[i])) != HAL_OK) + return err; + + return HAL_OK; +} + const hal_ks_driver_t hal_ks_volatile_driver[1] = {{ ks_volatile_init, ks_volatile_shutdown, @@ -607,7 +741,10 @@ const hal_ks_driver_t hal_ks_volatile_driver[1] = {{ ks_match, ks_set_attribute, ks_get_attribute, - ks_delete_attribute + ks_delete_attribute, + ks_set_attributes, + ks_get_attributes, + ks_delete_attributes }}; #endif /* STATIC_KS_VOLATILE_SLOTS > 0 */ diff --git a/libhal.py b/libhal.py index 06445f0..4023edc 100644 --- a/libhal.py +++ b/libhal.py @@ -112,6 +112,7 @@ HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_ORPHANED = "Key index chunk orphaned" HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_MISSING = "Key index chunk missing") HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_OVERLAPS = "Key index chunk overlaps") HALError.define(HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE = "Wrong block type in keystore") +HALError.define(HAL_ERROR_RPC_PROTOCOL_ERROR = "RPC protocol error") class Enum(int): @@ -183,6 +184,9 @@ RPCFunc.define(''' RPC_FUNC_PKEY_GET_ATTRIBUTE, RPC_FUNC_PKEY_DELETE_ATTRIBUTE, RPC_FUNC_PKEY_GET_KEY_CURVE, + RPC_FUNC_PKEY_SET_ATTRIBUTES, + RPC_FUNC_PKEY_GET_ATTRIBUTES, + RPC_FUNC_PKEY_DELETE_ATTRIBUTES, ''') class HALDigestAlgorithm(Enum): pass @@ -389,6 +393,15 @@ class PKey(Handle): def delete_attribute(self, attr_type): self.hsm.pkey_delete_attribute(self, attr_type) + def set_attributes(self, attributes): + self.hsm.pkey_set_attributes(self, attributes) + + def get_attributes(self, attributes, attributes_buffer_len = 2048): + return self.hsm.pkey_get_attributes(self, attributes, attributes_buffer_len) + + def delete_attributes(self, attributes): + self.hsm.pkey_delete_attributes(self, attributes) + class HSM(object): @@ -642,7 +655,7 @@ class HSM(object): key_name = UUID(bytes = r.unpack_bytes()) yield key_type, key_curve, key_flags, key_name - def pkey_match(self, type = 0, curve = 0, flags = 0, attributes = (), + def pkey_match(self, type = 0, curve = 0, flags = 0, attributes = {}, length = 64, client = 0, session = 0): u = UUID(int = 0) n = length @@ -655,8 +668,6 @@ class HSM(object): yield u def pkey_set_attribute(self, pkey, attr_type, attr_value = None): - if attr_value is None and isinstance(attr_type, Attribute): - attr_type, attr_value = attr_type.type, attr_type.attr_value with self.rpc(RPC_FUNC_PKEY_SET_ATTRIBUTE, pkey, attr_type, attr_value): return @@ -667,3 +678,19 @@ class HSM(object): def pkey_delete_attribute(self, pkey, attr_type): with self.rpc(RPC_FUNC_PKEY_DELETE_ATTRIBUTE, pkey, attr_type): return + + def pkey_set_attributes(self, pkey, attributes): + with self.rpc(RPC_FUNC_PKEY_SET_ATTRIBUTES, pkey, attributes): + return + + def pkey_get_attributes(self, pkey, attributes, attributes_buffer_len = 2048): + attributes = tuple(attributes) + with self.rpc(RPC_FUNC_PKEY_GET_ATTRIBUTES, pkey, attributes, attributes_buffer_len) as r: + n = r.unpack_uint() + if n != len(attributes): + raise HAL_ERROR_RPC_PROTOCOL_ERROR + return dict((r.unpack_uint(), r.unpack_bytes()) for i in xrange(n)) + + def pkey_delete_attributes(self, pkey, attributes): + with self.rpc(RPC_FUNC_PKEY_DELETE_ATTRIBUTES, pkey, attributes): + return diff --git a/rpc_api.c b/rpc_api.c index d337eeb..772d522 100644 --- a/rpc_api.c +++ b/rpc_api.c @@ -351,7 +351,7 @@ hal_error_t hal_rpc_pkey_match(const hal_client_handle_t client, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -399,6 +399,36 @@ hal_error_t hal_rpc_pkey_delete_attribute(const hal_pkey_handle_t pkey, return hal_rpc_pkey_dispatch->delete_attribute(pkey, type); } +hal_error_t hal_rpc_pkey_set_attributes(const hal_pkey_handle_t pkey, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len) +{ + if (attributes == NULL || attributes_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->set_attributes(pkey, attributes, attributes_len); +} + +hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len) +{ + if (attributes == NULL || attributes_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->get_attributes(pkey, attributes, attributes_len, + attributes_buffer, attributes_buffer_len); +} + +hal_error_t hal_rpc_pkey_delete_attributes(const hal_pkey_handle_t pkey, + const uint32_t * const types, + const unsigned types_len) +{ + if (types == NULL || types_len == 0) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->delete_attributes(pkey, types, types_len); +} + /* * Local variables: * indent-tabs-mode: nil diff --git a/rpc_client.c b/rpc_client.c index 0bd3ed5..76c4f0f 100644 --- a/rpc_client.c +++ b/rpc_client.c @@ -830,7 +830,7 @@ static hal_error_t pkey_remote_match(const hal_client_handle_t client, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -869,10 +869,11 @@ static hal_error_t pkey_remote_match(const hal_client_handle_t client, check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); if (rpc_ret == HAL_OK) { - uint32_t array_len, uuid_len; + uint32_t array_len; *result_len = 0; check(hal_xdr_decode_int(&iptr, ilimit, &array_len)); for (int i = 0; i < array_len; ++i) { + uint32_t uuid_len = sizeof(result[i].uuid); check(hal_xdr_decode_buffer(&iptr, ilimit, result[i].uuid, &uuid_len)); if (uuid_len != sizeof(result[i].uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; @@ -958,6 +959,106 @@ static hal_error_t pkey_remote_delete_attribute(const hal_pkey_handle_t pkey, return rpc_ret; } +static hal_error_t pkey_remote_set_attributes(const hal_pkey_handle_t pkey, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len) +{ + size_t outbuf_len = nargs(4 + 2 * attributes_len); + for (int i = 0; i < attributes_len; i++) + outbuf_len += pad(attributes[i].length); + + uint8_t outbuf[outbuf_len], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(3)]; + const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + hal_client_handle_t dummy_client = {0}; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_SET_ATTRIBUTES)); + check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, attributes_len)); + for (int i = 0; i < attributes_len; i++) { + check(hal_xdr_encode_int(&optr, olimit, attributes[i].type)); + check(hal_xdr_encode_buffer(&optr, olimit, attributes[i].value, attributes[i].length)); + } + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(read_matching_packet(RPC_FUNC_PKEY_SET_ATTRIBUTES, inbuf, sizeof(inbuf), &iptr, &ilimit)); + + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len) +{ + /* inbuf[] here includes one extra word per attribute for padding */ + uint8_t outbuf[nargs(5 + attributes_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(3 + 3 * attributes_len) + attributes_buffer_len]; + const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + hal_client_handle_t dummy_client = {0}; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_ATTRIBUTES)); + check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, attributes_len)); + for (int i = 0; i < attributes_len; i++) + check(hal_xdr_encode_int(&optr, olimit, attributes[i].type)); + check(hal_xdr_encode_int(&optr, olimit, attributes_buffer_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(read_matching_packet(RPC_FUNC_PKEY_GET_ATTRIBUTES, inbuf, sizeof(inbuf), &iptr, &ilimit)); + + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + uint8_t *abuf = attributes_buffer; + uint32_t u32; + check(hal_xdr_decode_int(&iptr, ilimit, &u32)); + if (u32 != attributes_len) + return HAL_ERROR_RPC_PROTOCOL_ERROR; + for (int i = 0; i < attributes_len; i++) { + check(hal_xdr_decode_int(&iptr, ilimit, &u32)); + if (u32 != attributes[i].type) + return HAL_ERROR_RPC_PROTOCOL_ERROR; + u32 = attributes_buffer + attributes_buffer_len - abuf; + check(hal_xdr_decode_buffer(&iptr, ilimit, abuf, &u32)); + attributes[i].value = abuf; + attributes[i].length = u32; + abuf += u32; + } + } + return rpc_ret; +} + +static hal_error_t pkey_remote_delete_attributes(const hal_pkey_handle_t pkey, + const uint32_t *types, + const unsigned types_len) +{ + uint8_t outbuf[nargs(4 + types_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(3)]; + const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + hal_client_handle_t dummy_client = {0}; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE_ATTRIBUTES)); + check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, types_len)); + for (int i = 0; i < types_len; i++) { + check(hal_xdr_encode_int(&optr, olimit, types[i])); + } + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(read_matching_packet(RPC_FUNC_PKEY_DELETE_ATTRIBUTES, inbuf, sizeof(inbuf), &iptr, &ilimit)); + + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + #if RPC_CLIENT == RPC_CLIENT_MIXED /* @@ -1088,7 +1189,10 @@ const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = { pkey_remote_match, pkey_remote_set_attribute, pkey_remote_get_attribute, - pkey_remote_delete_attribute + pkey_remote_delete_attribute, + pkey_remote_set_attributes, + pkey_remote_get_attributes, + pkey_remote_delete_attributes }; #if RPC_CLIENT == RPC_CLIENT_MIXED @@ -1110,7 +1214,10 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = { pkey_remote_match, pkey_remote_set_attribute, pkey_remote_get_attribute, - pkey_remote_delete_attribute + pkey_remote_delete_attribute, + pkey_remote_set_attributes, + pkey_remote_get_attributes, + pkey_remote_delete_attributes }; #endif /* RPC_CLIENT == RPC_CLIENT_MIXED */ diff --git a/rpc_pkey.c b/rpc_pkey.c index 88b6248..50403d7 100644 --- a/rpc_pkey.c +++ b/rpc_pkey.c @@ -954,7 +954,7 @@ static hal_error_t pkey_local_match(const hal_client_handle_t client, const hal_key_type_t type, const hal_curve_name_t curve, const hal_key_flags_t flags, - hal_rpc_pkey_attribute_t *attributes, + const hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len, hal_uuid_t *result, unsigned *result_len, @@ -1048,6 +1048,78 @@ static hal_error_t pkey_local_delete_attribute(const hal_pkey_handle_t pkey, return err; } +static hal_error_t pkey_local_set_attributes(const hal_pkey_handle_t pkey, + const hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len) +{ + hal_pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_ks_t *ks = NULL; + hal_error_t err; + + if ((err = check_writable(slot->client_handle, slot->flags)) != HAL_OK) + return err; + + if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK && + (err = hal_ks_set_attributes(ks, slot, attributes, attributes_len)) == HAL_OK) + err = hal_ks_close(ks); + else if (ks != NULL) + (void) hal_ks_close(ks); + + return err; +} + +static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t pkey, + hal_rpc_pkey_attribute_t *attributes, + const unsigned attributes_len, + uint8_t *attributes_buffer, + const size_t attributes_buffer_len) +{ + hal_pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_ks_t *ks = NULL; + hal_error_t err; + + if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK && + (err = hal_ks_get_attributes(ks, slot, attributes, attributes_len, + attributes_buffer, attributes_buffer_len)) == HAL_OK) + err = hal_ks_close(ks); + else if (ks != NULL) + (void) hal_ks_close(ks); + + return err; +} + +static hal_error_t pkey_local_delete_attributes(const hal_pkey_handle_t pkey, + const uint32_t * const types, + const unsigned types_len) +{ + hal_pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_ks_t *ks = NULL; + hal_error_t err; + + if ((err = check_writable(slot->client_handle, slot->flags)) != HAL_OK) + return err; + + if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK && + (err = hal_ks_delete_attributes(ks, slot, types, types_len)) == HAL_OK) + err = hal_ks_close(ks); + else if (ks != NULL) + (void) hal_ks_close(ks); + + return err; +} + const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = { pkey_local_load, pkey_local_find, @@ -1066,7 +1138,10 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = { pkey_local_match, pkey_local_set_attribute, pkey_local_get_attribute, - pkey_local_delete_attribute + pkey_local_delete_attribute, + pkey_local_set_attributes, + pkey_local_get_attributes, + pkey_local_delete_attributes }; /* diff --git a/rpc_server.c b/rpc_server.c index a19a44b..201d028 100644 --- a/rpc_server.c +++ b/rpc_server.c @@ -44,6 +44,8 @@ #define pad(n) (((n) + 3) & ~3) +#define nargs(n) ((n) * 4) + static hal_error_t get_version(const uint8_t **iptr, const uint8_t * const ilimit, uint8_t **optr, const uint8_t * const olimit) { @@ -811,6 +813,103 @@ static hal_error_t pkey_delete_attribute(const uint8_t **iptr, const uint8_t * c return ret; } +static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_pkey_handle_t pkey; + uint32_t attributes_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &attributes_len)); + + hal_rpc_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1]; + + for (int i = 0; i < attributes_len; i++) { + hal_rpc_pkey_attribute_t *a = &attributes[i]; + uint32_t value_len; + check(hal_xdr_decode_int(iptr, ilimit, &a->type)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &a->value, &value_len)); + a->length = value_len; + } + + ret = hal_rpc_pkey_set_attributes(pkey, attributes, attributes_len); + + return ret; +} + +static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_pkey_handle_t pkey; + uint32_t attributes_len, u32; + uint8_t *optr_orig = *optr; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &attributes_len)); + + hal_rpc_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1]; + + for (int i = 0; i < attributes_len; i++) + check(hal_xdr_decode_int(iptr, ilimit, &attributes[i].type)); + + check(hal_xdr_decode_int(iptr, ilimit, &u32)); + + const size_t attributes_buffer_len = u32; + + if (nargs(1 + 2 * attributes_len) + attributes_buffer_len > olimit - *optr) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + uint8_t attributes_buffer[attributes_buffer_len > 0 ? attributes_buffer_len : 1]; + + ret = hal_rpc_pkey_get_attributes(pkey, attributes, attributes_len, + attributes_buffer, attributes_buffer_len); + + if (ret == HAL_OK) { + ret = hal_xdr_encode_int(optr, olimit, attributes_len); + for (int i = 0; ret == HAL_OK && i < attributes_len; i++) { + ret = hal_xdr_encode_int(optr, olimit, attributes[i].type); + if (ret != HAL_OK) + break; + ret = hal_xdr_encode_buffer(optr, olimit, attributes[i].value, attributes[i].length); + } + } + + if (ret != HAL_OK) + *optr = optr_orig; + + return ret; +} + +static hal_error_t pkey_delete_attributes(const uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_pkey_handle_t pkey; + uint32_t types_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &types_len)); + + uint32_t types[types_len > 0 ? types_len : 1]; + + for (int i = 0; i < types_len; i++) { + check(hal_xdr_decode_int(iptr, ilimit, &types[i])); + } + + ret = hal_rpc_pkey_delete_attributes(pkey, types, types_len); + + return ret; +} + + hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen) { @@ -922,6 +1021,15 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile case RPC_FUNC_PKEY_DELETE_ATTRIBUTE: handler = pkey_delete_attribute; break; + case RPC_FUNC_PKEY_SET_ATTRIBUTES: + handler = pkey_set_attributes; + break; + case RPC_FUNC_PKEY_GET_ATTRIBUTES: + handler = pkey_get_attributes; + break; + case RPC_FUNC_PKEY_DELETE_ATTRIBUTES: + handler = pkey_delete_attributes; + break; } if (handler) diff --git a/unit-tests.py b/unit-tests.py index ca18e3a..43b56ba 100644 --- a/unit-tests.py +++ b/unit-tests.py @@ -625,20 +625,33 @@ class TestPKeyAttributeWriteSpeedToken(TestCaseLoggedIn): self.addCleanup(self.k.delete) super(TestPKeyAttributeWriteSpeedToken, self).setUp() - def set_attributes(self, n_attrs): + def set_attributes_single(self, n_attrs): pinwheel = Pinwheel() for i in xrange(n_attrs): pinwheel() self.k.set_attribute(i, "Attribute {}".format(i)) - def test_set_1_attribute(self): - self.set_attributes(1) + def set_attributes_bulk(self, n_attrs): + self.k.set_attributes(dict((i, "Attribute {}".format(i)) + for i in xrange(n_attrs))) - def test_set_6_attributes(self): - self.set_attributes(6) + def test_set_1_attribute_single(self): + self.set_attributes_single(1) - def test_set_12_attributes(self): - self.set_attributes(12) + def test_set_6_attributes_single(self): + self.set_attributes_single(6) + + def test_set_12_attributes_single(self): + self.set_attributes_single(12) + + def test_set_1_attribute_bulk(self): + self.set_attributes_bulk(1) + + def test_set_6_attributes_bulk(self): + self.set_attributes_bulk(6) + + def test_set_12_attributes_bulk(self): + self.set_attributes_bulk(12) class TestPKeyAttributeWriteSpeedVolatile(TestCaseLoggedIn): """ @@ -651,19 +664,33 @@ class TestPKeyAttributeWriteSpeedVolatile(TestCaseLoggedIn): self.addCleanup(self.k.delete) super(TestPKeyAttributeWriteSpeedVolatile, self).setUp() - def set_attributes(self, n_attrs): + def set_attributes_single(self, n_attrs): + pinwheel = Pinwheel() for i in xrange(n_attrs): + pinwheel() self.k.set_attribute(i, "Attribute {}".format(i)) - def test_set_1_attribute(self): - self.set_attributes(1) + def set_attributes_bulk(self, n_attrs): + self.k.set_attributes(dict((i, "Attribute {}".format(i)) + for i in xrange(n_attrs))) + + def test_set_1_attribute_single(self): + self.set_attributes_single(1) + + def test_set_6_attributes_single(self): + self.set_attributes_single(6) + + def test_set_12_attributes_single(self): + self.set_attributes_single(12) - def test_set_6_attributes(self): - self.set_attributes(6) + def test_set_1_attribute_bulk(self): + self.set_attributes_bulk(1) - def test_set_12_attributes(self): - self.set_attributes(12) + def test_set_6_attributes_bulk(self): + self.set_attributes_bulk(6) + def test_set_12_attributes_bulk(self): + self.set_attributes_bulk(12) class TestPKeyAttributeReadSpeedToken(TestCaseLoggedIn): """ @@ -674,23 +701,36 @@ class TestPKeyAttributeReadSpeedToken(TestCaseLoggedIn): der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, HAL_KEY_FLAG_TOKEN) self.addCleanup(self.k.delete) - self.k.set_attribute(0, "Attribute 0") + for i in xrange(12): + self.k.set_attribute(i, "Attribute {}".format(i)) super(TestPKeyAttributeReadSpeedToken, self).setUp() - def get_attributes(self, n_attrs): + def get_attributes_single(self, n_attrs): pinwheel = Pinwheel() for i in xrange(n_attrs): pinwheel() - self.k.get_attribute(0) + self.k.get_attribute(i) + + def get_attributes_bulk(self, n_attrs): + self.k.get_attributes(range(n_attrs)) + + def test_get_1_attribute_single(self): + self.get_attributes_single(1) + + def test_get_6_attributes_single(self): + self.get_attributes_single(6) + + def test_get_12_attributes_single(self): + self.get_attributes_single(12) - def test_get_1_attribute(self): - self.get_attributes(1) + def test_get_1_attribute_bulk(self): + self.get_attributes_bulk(1) - def test_get_6_attributes(self): - self.get_attributes(6) + def test_get_6_attributes_bulk(self): + self.get_attributes_bulk(6) - def test_get_12_attributes(self): - self.get_attributes(12) + def test_get_12_attributes_bulk(self): + self.get_attributes_bulk(12) class TestPKeyAttributeReadSpeedVolatile(TestCaseLoggedIn): """ @@ -701,24 +741,36 @@ class TestPKeyAttributeReadSpeedVolatile(TestCaseLoggedIn): der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, 0) self.addCleanup(self.k.delete) - self.k.set_attribute(0, "Attribute 0") + for i in xrange(12): + self.k.set_attribute(i, "Attribute {}".format(i)) super(TestPKeyAttributeReadSpeedVolatile, self).setUp() - def get_attributes(self, n_attrs): + def get_attributes_single(self, n_attrs): pinwheel = Pinwheel() for i in xrange(n_attrs): pinwheel() - self.k.get_attribute(0) + self.k.get_attribute(i) + + def get_attributes_bulk(self, n_attrs): + self.k.get_attributes(range(n_attrs)) + + def test_get_1_attribute_single(self): + self.get_attributes_single(1) + + def test_get_6_attributes_single(self): + self.get_attributes_single(6) - def test_get_1_attribute(self): - self.get_attributes(1) + def test_get_12_attributes_single(self): + self.get_attributes_single(12) - def test_get_6_attributes(self): - self.get_attributes(6) + def test_get_1_attribute_bulk(self): + self.get_attributes_bulk(1) - def test_get_12_attributes(self): - self.get_attributes(12) + def test_get_6_attributes_bulk(self): + self.get_attributes_bulk(6) + def test_get_12_attributes_bulk(self): + self.get_attributes_bulk(12) @unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package") -- cgit v1.2.3