aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hal.h1
-rw-r--r--hal_internal.h77
-rw-r--r--ks_attribute.c19
-rw-r--r--ks_flash.c459
-rw-r--r--libhal.py1
-rw-r--r--unit-tests.py40
6 files changed, 563 insertions, 34 deletions
diff --git a/hal.h b/hal.h
index 74e0a51..59018ea 100644
--- a/hal.h
+++ b/hal.h
@@ -156,6 +156,7 @@
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") \
+ DEFINE_HAL_ERROR(HAL_ERROR_NOT_IMPLEMENTED, "Not implemented") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
diff --git a/hal_internal.h b/hal_internal.h
index 6b82b9c..554ca62 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -575,34 +575,46 @@ extern const hal_ks_driver_t
static inline hal_error_t hal_ks_init(const hal_ks_driver_t * const driver)
{
- if (driver == NULL || driver->init == NULL)
+ if (driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (driver->init == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return driver->init(driver);
}
static inline hal_error_t hal_ks_shutdown(const hal_ks_driver_t * const driver)
{
- if (driver == NULL || driver->shutdown == NULL)
+ if (driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (driver->shutdown == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return driver->shutdown(driver);
}
static inline hal_error_t hal_ks_open(const hal_ks_driver_t * const driver,
hal_ks_t **ks)
{
- if (driver == NULL || driver->open == NULL || ks == NULL)
+ if (driver == NULL || ks == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (driver->open == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return driver->open(driver, ks);
}
static inline hal_error_t hal_ks_close(hal_ks_t *ks)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->close == NULL)
+ if (ks == NULL || ks->driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->close == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->close(ks);
}
@@ -610,9 +622,12 @@ static inline hal_error_t hal_ks_store(hal_ks_t *ks,
hal_pkey_slot_t *slot,
const uint8_t * const der, const size_t der_len)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->store == NULL || slot == NULL || der == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL || der == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->store == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->store(ks, slot, der, der_len);
}
@@ -620,18 +635,24 @@ static inline hal_error_t hal_ks_fetch(hal_ks_t *ks,
hal_pkey_slot_t *slot,
uint8_t *der, size_t *der_len, const size_t der_max)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->fetch == NULL || slot == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->fetch == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->fetch(ks, slot, der, der_len, der_max);
}
static inline hal_error_t hal_ks_delete(hal_ks_t *ks,
hal_pkey_slot_t *slot)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->delete == NULL || slot == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->delete == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->delete(ks, slot);
}
@@ -642,9 +663,12 @@ static inline hal_error_t hal_ks_list(hal_ks_t *ks,
unsigned *result_len,
const unsigned result_max)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->list == NULL)
+ if (ks == NULL || ks->driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->list == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->list(ks, client, session, result, result_len, result_max);
}
@@ -661,9 +685,12 @@ static inline hal_error_t hal_ks_match(hal_ks_t *ks,
const unsigned result_max,
const hal_uuid_t * const previous_uuid)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->match == NULL)
+ if (ks == NULL || ks->driver == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->match == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->match(ks, client, session, type, curve, flags, attributes, attributes_len,
result, result_len, result_max, previous_uuid);
}
@@ -674,9 +701,12 @@ static inline hal_error_t hal_ks_set_attribute(hal_ks_t *ks,
const uint8_t * const value,
const size_t value_len)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->set_attribute == NULL || slot == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->set_attribute == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->set_attribute(ks, slot, type, value, value_len);
}
@@ -687,9 +717,12 @@ static inline hal_error_t hal_ks_get_attribute(hal_ks_t *ks,
size_t *value_len,
const size_t value_max)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->get_attribute == NULL || slot == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->get_attribute == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->get_attribute(ks, slot, type, value, value_len, value_max);
}
@@ -697,9 +730,12 @@ static inline hal_error_t hal_ks_delete_attribute(hal_ks_t *ks,
hal_pkey_slot_t *slot,
const uint32_t type)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->delete_attribute == NULL || slot == NULL)
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->delete_attribute == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->delete_attribute(ks, slot, type);
}
@@ -708,10 +744,13 @@ static inline hal_error_t hal_ks_set_attributes(hal_ks_t *ks,
const hal_rpc_pkey_attribute_t *attributes,
const unsigned attributes_len)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->set_attributes == NULL || slot == NULL ||
+ if (ks == NULL || ks->driver == NULL || slot == NULL ||
attributes == NULL || attributes_len == 0)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->set_attributes == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
for (int i = 0; i < attributes_len; i++)
if (attributes[i].length == 0 || attributes[i].value == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -726,11 +765,14 @@ static inline hal_error_t hal_ks_get_attributes(hal_ks_t *ks,
uint8_t *attributes_buffer,
const size_t attributes_buffer_len)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->get_attributes == NULL || slot == NULL ||
+ if (ks == NULL || ks->driver == NULL || slot == NULL ||
attributes == NULL || attributes_len == 0 ||
attributes_buffer == NULL || attributes_buffer_len == 0)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->get_attributes == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->get_attributes(ks, slot, attributes, attributes_len,
attributes_buffer, attributes_buffer_len);
}
@@ -740,10 +782,13 @@ static inline hal_error_t hal_ks_delete_attributes(hal_ks_t *ks,
const uint32_t *types,
const unsigned types_len)
{
- if (ks == NULL || ks->driver == NULL || ks->driver->delete_attributes == NULL || slot == NULL ||
+ if (ks == NULL || ks->driver == NULL || slot == NULL ||
types == NULL || types_len == 0)
return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks->driver->delete_attributes == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
return ks->driver->delete_attributes(ks, slot, types, types_len);
}
@@ -881,6 +926,8 @@ extern hal_error_t hal_ks_index_fsck(hal_ks_index_t *ksi);
* Keystore attribute utilities, for use by keystore drivers.
*/
+extern const size_t hal_ks_attribute_header_size;
+
extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes,
const size_t bytes_len,
hal_rpc_pkey_attribute_t *attributes,
diff --git a/ks_attribute.c b/ks_attribute.c
index 0c71345..53cd6bf 100644
--- a/ks_attribute.c
+++ b/ks_attribute.c
@@ -44,12 +44,13 @@
* issues, and doing it this way just isn't expensive enough to worry about.
*/
-#define HEADER_LEN (4 + 2)
+const size_t hal_ks_attribute_header_size = 2 * sizeof(uint32_t);
static inline hal_error_t read_header(const uint8_t * const bytes, const size_t bytes_len,
uint32_t *attribute_type, size_t *attribute_len)
{
- if (bytes == NULL || bytes_len < HEADER_LEN || attribute_type == NULL || attribute_len == NULL)
+ if (bytes == NULL || bytes_len < hal_ks_attribute_header_size ||
+ attribute_type == NULL || attribute_len == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
*attribute_type = ((bytes[0] << 24) |
@@ -65,7 +66,7 @@ static inline hal_error_t read_header(const uint8_t * const bytes, const size_t
static inline hal_error_t write_header(uint8_t *bytes, const size_t bytes_len,
const uint32_t attribute_type, const size_t attribute_len)
{
- if (bytes == NULL || bytes_len < HEADER_LEN)
+ if (bytes == NULL || bytes_len < hal_ks_attribute_header_size)
return HAL_ERROR_BAD_ARGUMENTS;
bytes[0] = (attribute_type >> 24) & 0xFF;
@@ -94,7 +95,7 @@ hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, const size_t byte
hal_error_t err = read_header(b, end - b, &type, &length);
if (err != HAL_OK)
return err;
- b += HEADER_LEN;
+ b += hal_ks_attribute_header_size;
if (attributes != NULL) {
attributes[i].type = type;
attributes[i].length = length;
@@ -127,8 +128,8 @@ hal_error_t hal_ks_attribute_delete(uint8_t *bytes, const size_t bytes_len,
if (i == *attributes_len)
return HAL_OK;
- const size_t delete_length = HEADER_LEN + attributes[i].length;
- const size_t delete_offset = attributes[i].value - HEADER_LEN - bytes;
+ const size_t delete_length = hal_ks_attribute_header_size + attributes[i].length;
+ const size_t delete_offset = attributes[i].value - hal_ks_attribute_header_size - bytes;
if (delete_offset + delete_length > *total_len)
return HAL_ERROR_IMPOSSIBLE;
@@ -163,7 +164,7 @@ hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
if (err != HAL_OK)
return err;
- if (*total_len + HEADER_LEN + value_len > bytes_len)
+ if (*total_len + hal_ks_attribute_header_size + value_len > bytes_len)
return HAL_ERROR_RESULT_TOO_LONG;
uint8_t *b = bytes + *total_len;
@@ -171,11 +172,11 @@ hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
if ((err = write_header(b, bytes_len - *total_len, type, value_len)) != HAL_OK)
return err;
- b += HEADER_LEN;
+ b += hal_ks_attribute_header_size;
memcpy(b, value, value_len);
- *total_len += HEADER_LEN + value_len;
+ *total_len += hal_ks_attribute_header_size + value_len;
attributes[*attributes_len].type = type;
attributes[*attributes_len].length = value_len;
diff --git a/ks_flash.c b/ks_flash.c
index c96efd5..0d8542e 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -315,7 +315,7 @@ static hal_crc32_t calculate_block_crc(const flash_block_t * const block)
* Calculate block offset.
*/
-static uint32_t block_offset(const unsigned blockno)
+static inline uint32_t block_offset(const unsigned blockno)
{
return blockno * KEYSTORE_SUBSECTOR_SIZE;
}
@@ -1544,6 +1544,458 @@ static hal_error_t ks_delete_attribute(hal_ks_t *ks,
return HAL_OK;
}
+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)
+{
+#warning This function is much too long
+ // Probably needs to be broken up into multiple sub-functions, or at least
+ // into discrete blocks to scope most of the variables, but let's finish
+ // writing the icky version before polishing the chrome.
+
+ if (ks != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Try to add new attribute as a single-block update.
+ */
+
+ unsigned updated_attributes_len = attributes_len;
+ flash_block_t *block;
+ unsigned chunk = 0;
+ hal_error_t err;
+ unsigned b;
+
+ do {
+ int hint = slot->hint + chunk;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ cache_mark_used(block, b);
+
+ if (chunk == 0)
+ slot->hint = hint;
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ updated_attributes_len += *attrs_len;
+
+ hal_rpc_pkey_attribute_t attrs[*attrs_len + attributes_len];
+ size_t total;
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK)
+ return err;
+
+ for (int i = 0; err == HAL_OK && i < attributes_len; i++) {
+ if (attributes[i].length == 0)
+ err = hal_ks_attribute_delete(bytes, bytes_len, attrs, attrs_len, &total,
+ attributes[i].type);
+ else
+ err = hal_ks_attribute_insert(bytes, bytes_len, attrs, attrs_len, &total,
+ attributes[i].type,
+ attributes[i].value,
+ attributes[i].length);
+ if (err != HAL_OK)
+ cache_release(block);
+ }
+
+ if (err == HAL_ERROR_RESULT_TOO_LONG)
+ continue;
+
+ if (err != HAL_OK)
+ return err;
+
+ return block_update(b, block, &slot->name, chunk, &hint);
+
+ } while (++chunk < block->header.total_chunks);
+
+ /*
+ * If we get here, we have to add a new block, which requires
+ * rewriting all the others to bump the total_blocks count. We need
+ * to keep track of all the old chunks so we can zero them at the
+ * end, and because we can't zero them until we've written out the
+ * new chunks, we need enough free blocks for the entire new object.
+ *
+ * Calculating all of this is extremely tedious, but flash writes
+ * are so much more expensive than anything else we do here that
+ * it's almost certainly worth it.
+ *
+ * We don't need the attribute values to compute the sizes, just the
+ * attribute sizes, so we scan all the existing blocks, build up a
+ * structure with the current attribute types and sizes, modify that
+ * according to our arguments, and compute the needed size. Once we
+ * have that, we can start rewriting existing blocks. We put all
+ * the new stuff at the end, which simplifies this slightly.
+ *
+ * In theory, this process never requires us to have more than two
+ * blocks in memory at the same time (source and destination when
+ * copying across chunk boundaries), but having enough cache buffers
+ * to keep the whole set in memory will almost certainly make this
+ * run faster.
+ */
+
+ hal_rpc_pkey_attribute_t updated_attributes[updated_attributes_len];
+ const unsigned total_chunks_old = block->header.total_chunks;
+ size_t bytes_available = 0;
+
+ updated_attributes_len = 0;
+
+ for (chunk = 0; chunk < total_chunks_old; chunk++) {
+ int hint = slot->hint + chunk;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ cache_mark_used(block, b);
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ hal_rpc_pkey_attribute_t attrs[*attrs_len];
+ size_t total;
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK)
+ return err;
+
+ if (chunk == 0)
+ bytes_available = bytes_len;
+
+ for (int i = 0; i < *attrs_len; i++) {
+ if (updated_attributes_len >= sizeof(updated_attributes)/sizeof(*updated_attributes))
+ return HAL_ERROR_IMPOSSIBLE;
+ updated_attributes[updated_attributes_len].type = attrs[i].type;
+ updated_attributes[updated_attributes_len].length = attrs[i].length;
+ updated_attributes[updated_attributes_len].value = NULL;
+ updated_attributes_len++;
+ }
+ }
+
+ for (int i = 0; i < attributes_len; i++) {
+
+ for (int j = 0; j < updated_attributes_len; j++)
+ if (updated_attributes[j].type == attributes[i].type)
+ updated_attributes[j].length = 0;
+
+ if (updated_attributes_len >= sizeof(updated_attributes)/sizeof(*updated_attributes))
+ return HAL_ERROR_IMPOSSIBLE;
+ updated_attributes[updated_attributes_len].type = attributes[i].type;
+ updated_attributes[updated_attributes_len].length = attributes[i].length;
+ updated_attributes[updated_attributes_len].value = attributes[i].value;
+ updated_attributes_len++;
+ }
+
+ chunk = 0;
+
+ for (int i = 0; i < updated_attributes_len; i++) {
+
+ if (updated_attributes[i].length == 0) {
+ memmove(&updated_attributes[i], &updated_attributes[i + 1], updated_attributes_len - i - 1);
+ updated_attributes_len--;
+ i--;
+ continue;
+ }
+
+ const size_t needed = hal_ks_attribute_header_size + updated_attributes[i].length;
+
+ if (needed > bytes_available) {
+ bytes_available = SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES;
+ chunk++;
+ }
+
+ if (needed > bytes_available)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ bytes_available -= needed;
+ }
+
+ const unsigned total_chunks_new = chunk + 1;
+
+ if (db.ksi.used + total_chunks_new > db.ksi.size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ /*
+ * Phase 1: Deprecate all the old chunks, remember where they were.
+ */
+
+ unsigned old_blocks[total_chunks_old];
+
+ for (chunk = 0; chunk < total_chunks_old; chunk++) {
+ int hint = slot->hint + chunk;
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_deprecate(b)) != HAL_OK)
+ return err;
+ old_blocks[chunk] = b;
+ }
+
+ /*
+ * Phase 2: Write new chunks, copying attributes from old chunks and attributes[]
+ * as needed. This is tedious.
+ */
+
+ {
+ hal_rpc_pkey_attribute_t old_attrs[updated_attributes_len], new_attrs[updated_attributes_len];
+ unsigned *old_attrs_len = NULL, *new_attrs_len = NULL;
+ flash_block_t *old_block = NULL, *new_block = NULL;
+ uint8_t *old_bytes = NULL, *new_bytes = NULL;
+ size_t old_bytes_len = 0, new_bytes_len = 0;
+ unsigned old_chunk = 0, new_chunk = 0;
+ size_t old_total = 0, new_total = 0;
+
+ int updated_attributes_i = 0, old_attrs_i = 0;
+
+ uint32_t new_attr_type;
+ size_t new_attr_length;
+ const uint8_t *new_attr_value;
+
+ while (updated_attributes_i < updated_attributes_len) {
+
+ if (old_chunk >= total_chunks_old || new_chunk >= total_chunks_new)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (updated_attributes[updated_attributes_i].value != NULL) {
+ new_attr_type = updated_attributes[updated_attributes_i].type;
+ new_attr_length = updated_attributes[updated_attributes_i].length;
+ new_attr_value = updated_attributes[updated_attributes_i].value;
+ }
+
+ else {
+
+ if (old_block == NULL) {
+
+ if ((err = block_read_cached(old_blocks[old_chunk], &old_block)) != HAL_OK)
+ return err;
+
+ if (old_block->header.this_chunk != old_chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((err = locate_attributes(old_block, old_chunk,
+ &old_bytes, &old_bytes_len, &old_attrs_len)) != HAL_OK ||
+ (err = hal_ks_attribute_scan(old_bytes, old_bytes_len,
+ old_attrs, *old_attrs_len, &old_total)) != HAL_OK)
+ return err;
+
+ old_attrs_i = 0;
+ }
+
+ while (old_attrs_i < *old_attrs_len &&
+ old_attrs[old_attrs_i].type != updated_attributes[updated_attributes_i].type)
+ old_attrs_i++;
+
+ if (old_attrs_i >= *old_attrs_len) {
+ old_chunk++;
+ old_block = NULL;
+ continue;
+ }
+
+ new_attr_type = old_attrs[old_attrs_i].type;
+ new_attr_length = old_attrs[old_attrs_i].length;
+ new_attr_value = old_attrs[old_attrs_i].value;
+ }
+
+ if (new_block == NULL) {
+
+ new_block = cache_pick_lru();
+ memset(new_block, 0xFF, sizeof(*new_block));
+
+ if (new_chunk == 0) {
+ flash_block_t *tmp_block;
+ if ((err = block_read_cached(old_blocks[0], &tmp_block)) != HAL_OK)
+ return err;
+ if (tmp_block->header.this_chunk != 0)
+ return HAL_ERROR_IMPOSSIBLE;
+ new_block->header.block_type = BLOCK_TYPE_KEY;
+ new_block->key.name = slot->name;
+ new_block->key.type = tmp_block->key.type;
+ new_block->key.curve = tmp_block->key.curve;
+ new_block->key.flags = tmp_block->key.flags;
+ new_block->key.der_len = tmp_block->key.der_len;
+ new_block->key.attributes_len = 0;
+ memcpy(new_block->key.der, tmp_block->key.der, tmp_block->key.der_len);
+ }
+ else {
+ new_block->header.block_type = BLOCK_TYPE_ATTR;
+ new_block->attr.name = slot->name;
+ new_block->attr.attributes_len = 0;
+ }
+
+ new_block->header.block_status = BLOCK_STATUS_LIVE;
+ new_block->header.total_chunks = total_chunks_new;
+ new_block->header.this_chunk = new_chunk;
+
+ if ((err = locate_attributes(new_block, new_chunk,
+ &new_bytes, &new_bytes_len, &new_attrs_len)) != HAL_OK)
+ return err;
+
+ new_total = 0;
+ }
+
+ err = hal_ks_attribute_insert(new_bytes, new_bytes_len, new_attrs, new_attrs_len, &new_total,
+ new_attr_type, new_attr_value, new_attr_length);
+
+ switch (err) {
+ case HAL_OK:
+ if (++updated_attributes_i >= updated_attributes_len)
+ continue;
+ break;
+ case HAL_ERROR_RESULT_TOO_LONG:
+ if (new_chunk == 0 || new_attrs_len > 0)
+ break;
+ default:
+ return err;
+ }
+
+ int hint = slot->hint + new_chunk;
+
+ if (new_chunk < total_chunks_old)
+ err = hal_ks_index_replace(&db.ksi, &slot->name, new_chunk, &b, &hint);
+ else
+ err = hal_ks_index_add( &db.ksi, &slot->name, new_chunk, &b, &hint);
+
+ if (err != HAL_OK || (err = block_write(b, new_block)) != HAL_OK)
+ return err;
+
+ cache_mark_used(new_block, b);
+
+ new_block = NULL;
+ new_chunk++;
+ }
+ }
+
+ /*
+ * Phase 3: Zero the old chunks we deprecated in phase 1.
+ */
+
+ for (chunk = 0; chunk < total_chunks_old; chunk++)
+ if ((err = block_zero(old_blocks[chunk])) != 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 != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0 ||
+ attributes_buffer == NULL || attributes_buffer_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ for (int i = 0; i < attributes_len; i++) {
+ attributes[i].length = 0;
+ attributes[i].value = NULL;
+ }
+
+ uint8_t *abuf = attributes_buffer;
+ flash_block_t *block = NULL;
+ unsigned chunk = 0;
+ unsigned found = 0;
+ hal_error_t err;
+ unsigned b;
+
+ do {
+ int hint = slot->hint + chunk;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (chunk == 0)
+ slot->hint = hint;
+
+ cache_mark_used(block, b);
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ if (*attrs_len == 0)
+ continue;
+
+ hal_rpc_pkey_attribute_t attrs[*attrs_len];
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
+ return err;
+
+ for (int i = 0; i < attributes_len; i++) {
+
+ if (attributes[i].value != NULL)
+ continue;
+
+ int j = 0;
+ while (j < *attrs_len && attrs[j].type != attributes[i].type)
+ j++;
+ if (j >= *attrs_len)
+ continue;
+
+ 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;
+ found++;
+ }
+
+ } while (found < attributes_len && ++chunk < block->header.total_chunks);
+
+ if (found < attributes_len)
+ return HAL_ERROR_ATTRIBUTE_NOT_FOUND;
+
+ 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)
+{
+ // Most likely we will remove this function from the API entirely,
+ // but for now implement it in terms of ks_set_attributes() to keep
+ // all the horrid update logic in one place.
+
+ if (ks != &db.ks || slot == NULL || types == NULL || types_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_rpc_pkey_attribute_t attributes[types_len];
+
+ for (int i = 0; i < types_len; i++) {
+ attributes[i].type = types[i];
+ attributes[i].length = 0;
+ attributes[i].value = NULL;
+ }
+
+ return ks_set_attributes(ks, slot, attributes, types_len);
+}
+
const hal_ks_driver_t hal_ks_token_driver[1] = {{
ks_init,
ks_shutdown,
@@ -1556,7 +2008,10 @@ const hal_ks_driver_t hal_ks_token_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
}};
/*
diff --git a/libhal.py b/libhal.py
index 4023edc..b243a26 100644
--- a/libhal.py
+++ b/libhal.py
@@ -113,6 +113,7 @@ 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")
+HALError.define(HAL_ERROR_NOT_IMPLEMENTED = "Not implemented")
class Enum(int):
diff --git a/unit-tests.py b/unit-tests.py
index 43b56ba..3d79da9 100644
--- a/unit-tests.py
+++ b/unit-tests.py
@@ -701,18 +701,30 @@ 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)
- for i in xrange(12):
- self.k.set_attribute(i, "Attribute {}".format(i))
+ if False:
+ for i in xrange(12):
+ self.k.set_attribute(i, "Attribute {}".format(i))
+ else:
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(12)))
super(TestPKeyAttributeReadSpeedToken, self).setUp()
+ def verify_attributes(self, n_attrs, attributes):
+ expected = dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs))
+ self.assertEqual(attributes, expected)
+
def get_attributes_single(self, n_attrs):
pinwheel = Pinwheel()
+ attributes = {}
for i in xrange(n_attrs):
pinwheel()
- self.k.get_attribute(i)
+ attributes[i] = self.k.get_attribute(i)
+ self.verify_attributes(n_attrs, attributes)
def get_attributes_bulk(self, n_attrs):
- self.k.get_attributes(range(n_attrs))
+ attributes = self.k.get_attributes(range(n_attrs))
+ self.verify_attributes(n_attrs, attributes)
def test_get_1_attribute_single(self):
self.get_attributes_single(1)
@@ -741,18 +753,30 @@ 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)
- for i in xrange(12):
- self.k.set_attribute(i, "Attribute {}".format(i))
+ if False:
+ for i in xrange(12):
+ self.k.set_attribute(i, "Attribute {}".format(i))
+ else:
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(12)))
super(TestPKeyAttributeReadSpeedVolatile, self).setUp()
+ def verify_attributes(self, n_attrs, attributes):
+ expected = dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs))
+ self.assertEqual(attributes, expected)
+
def get_attributes_single(self, n_attrs):
pinwheel = Pinwheel()
+ attributes = {}
for i in xrange(n_attrs):
pinwheel()
- self.k.get_attribute(i)
+ attributes[i] = self.k.get_attribute(i)
+ self.verify_attributes(n_attrs, attributes)
def get_attributes_bulk(self, n_attrs):
- self.k.get_attributes(range(n_attrs))
+ attributes = self.k.get_attributes(range(n_attrs))
+ self.verify_attributes(n_attrs, attributes)
def test_get_1_attribute_single(self):
self.get_attributes_single(1)