aboutsummaryrefslogtreecommitdiff
path: root/ks_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ks_flash.c')
-rw-r--r--ks_flash.c653
1 files changed, 466 insertions, 187 deletions
diff --git a/ks_flash.c b/ks_flash.c
index 9ba342a..c51ece9 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -49,234 +49,511 @@
#define PAGE_SIZE_MASK (KEYSTORE_PAGE_SIZE - 1)
/*
- * Use a one-element array here so that references can be pointer-based
- * as in the other implementations, to ease re-merge at some later date.
+ * Temporary hack: In-memory copy of entire (tiny) keystore database.
+ * This is backwards compatability to let us debug without changing
+ * too many moving parts at the same time, but will need to be
+ * replaced by something that can handle a much larger number of keys,
+ * which is one of the main points of the new keystore API.
*/
-static hal_ks_keydb_t db[1];
+typedef struct {
+ hal_ks_t ks; /* Must be first (C "subclassing") */
+
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+ hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
+#else
+#warning No keys in keydb
+#endif
+
+} db_t;
+
+static db_t db;
#define FLASH_SECTOR_1_OFFSET (0 * KEYSTORE_SECTOR_SIZE)
#define FLASH_SECTOR_2_OFFSET (1 * KEYSTORE_SECTOR_SIZE)
-uint32_t _active_sector_offset()
+static inline uint32_t _active_sector_offset()
{
- /* XXX Load status bytes from both sectors and decide which is current. */
- #warning Have not implemented two flash sectors yet
- return FLASH_SECTOR_1_OFFSET;
+ /* XXX Load status bytes from both sectors and decide which is current. */
+#warning Have not implemented two flash sectors yet
+ return FLASH_SECTOR_1_OFFSET;
}
-uint32_t _get_key_offset(uint32_t num)
+static inline uint32_t _get_key_offset(uint32_t num)
{
- /* Reserve first two pages for flash sector state, PINs and future additions.
- * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252).
- */
- uint32_t offset = KEYSTORE_PAGE_SIZE * 2;
- uint32_t key_size = sizeof(*db->keys);
- uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1);
- offset += num * bytes_per_key;
- return offset;
+ /*
+ * Reserve first two pages for flash sector state, PINs and future additions.
+ * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252).
+ */
+ uint32_t offset = KEYSTORE_PAGE_SIZE * 2;
+ uint32_t key_size = sizeof(*db.keys);
+ uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1);
+ offset += num * bytes_per_key;
+ return offset;
}
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
+static hal_error_t ks_init(void)
{
- uint32_t offset, i, idx = 0, active_sector_offset;
- hal_ks_key_t *key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
-
- memset(db, 0, sizeof(*db));
-
- if (keystore_check_id() != 1) return NULL;
-
- active_sector_offset = _active_sector_offset();
-
- /* The PINs are in the second page of the sector. */
- offset = active_sector_offset + KEYSTORE_PAGE_SIZE;
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
- offset = 0;
- memcpy(&db->wheel_pin, page_buf + offset, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(&db->so_pin, page_buf + offset, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(&db->user_pin, page_buf + offset, sizeof(db->user_pin));
-
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- idx++;
- continue;
- }
-
- offset += active_sector_offset;
-
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
-
- key = (hal_ks_key_t *) page_buf;
- if (key->in_use == 0xff) {
- /* unprogrammed data */
- idx++;
- continue;
- }
-
- if (key->in_use == 1) {
- uint8_t *dst = (uint8_t *) &db->keys[idx];
- uint32_t to_read = sizeof(*db->keys);
-
- /* We already have the first page in page_buf. Put it into place. */
- memcpy(dst, page_buf, sizeof(page_buf));
- to_read -= sizeof(page_buf);
- dst += sizeof(page_buf);
-
- /* Read as many more full pages as possible */
- if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1) return NULL;
- dst += to_read & ~PAGE_SIZE_MASK;
- to_read &= PAGE_SIZE_MASK;
-
- if (to_read) {
- /* Partial last page. We can only read full pages so load it into page_buf. */
- if (keystore_read_data(offset + sizeof(*db->keys) - to_read, page_buf, sizeof(page_buf)) != 1) return NULL;
- memcpy(dst, page_buf, to_read);
- }
- }
- idx++;
+ if (db.ks.driver == hal_ks_flash_driver)
+ return LIBHAL_OK;
+
+ if (db.ks.driver != NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t idx = 0; /* Current index into db.keys[] */
+
+ memset(db, 0, sizeof(*db));
+
+ if (keystore_check_id() != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ uint32_t active_sector_offset = _active_sector_offset();
+
+ /*
+ * The PINs are in the second page of the sector.
+ * Caching all of these these makes some sense in any case.
+ */
+
+ uint32_t offset = active_sector_offset + KEYSTORE_PAGE_SIZE;
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ offset = 0;
+ memcpy(&db.wheel_pin, page_buf + offset, sizeof(db.wheel_pin));
+
+ offset += sizeof(db.wheel_pin);
+ memcpy(&db.so_pin, page_buf + offset, sizeof(db.so_pin));
+
+ offset += sizeof(db.so_pin);
+ memcpy(&db.user_pin, page_buf + offset, sizeof(db.user_pin));
+
+ /*
+ * Now read out all the keys. This is a temporary hack, in the long
+ * run we want to pull these as they're needed, although depending
+ * on how we organize the flash we might still need an initial scan
+ * on startup to build some kind of in-memory index.
+ */
+
+ for (int i = 0; i < sizeof(db.keys) / sizeof(*db.keys); i++) {
+
+ if ((offset = _get_key_offset(i)) > KEYSTORE_SECTOR_SIZE) {
+ idx++;
+ continue;
}
- return db;
-}
+ offset += active_sector_offset;
-hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len)
-{
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t to_write = len;
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
- if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
+ const hal_ks_key_t *key = (const hal_ks_key_t *) page_buf;
+
+ if (key->in_use == 0xff) {
+ /* unprogrammed data */
+ idx++;
+ continue;
}
- to_write &= PAGE_SIZE_MASK;
- if (to_write) {
- /* Use page_buf to write the remaining bytes, since we must write a full page each time. */
- memset(page_buf, 0xff, sizeof(page_buf));
- memcpy(page_buf, data + len - to_write, to_write);
- if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
+
+ if (key->in_use == 1) {
+ uint8_t *dst = (uint8_t *) &db.keys[idx];
+ uint32_t to_read = sizeof(*db.keys);
+
+ /* We already have the first page in page_buf. Put it into place. */
+ memcpy(dst, page_buf, sizeof(page_buf));
+ to_read -= sizeof(page_buf);
+ dst += sizeof(page_buf);
+
+ /* Read as many more full pages as possible */
+ if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ dst += to_read & ~PAGE_SIZE_MASK;
+ to_read &= PAGE_SIZE_MASK;
+
+ if (to_read) {
+ /* Partial last page. We can only read full pages so load it into page_buf. */
+ if (keystore_read_data(offset + sizeof(*db.keys) - to_read, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ memcpy(dst, page_buf, to_read);
+ }
}
+ idx++;
+ }
- return LIBHAL_OK;
+ db.ks.driver = hal_ks_flash_driver;
+
+ return LIBHAL_OK;
+}
+
+static hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len)
+{
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t to_write = len;
+
+ if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ to_write &= PAGE_SIZE_MASK;
+ if (to_write) {
+ /*
+ * Use page_buf to write the remaining bytes, since we must write a full page each time.
+ */
+ memset(page_buf, 0xff, sizeof(page_buf));
+ memcpy(page_buf, data + len - to_write, to_write);
+ if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ }
+
+ return LIBLIBHAL_OK;
}
/*
* Write the full DB to flash, PINs and all.
*/
-hal_error_t _write_db_to_flash(const uint32_t sector_offset)
+
+static hal_error_t _write_db_to_flash(const uint32_t sector_offset)
{
- hal_error_t status;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t i, offset;
+ hal_error_t status;
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t i, offset;
- if (sizeof(db->wheel_pin) + sizeof(db->so_pin) + sizeof(db->user_pin) > sizeof(page_buf)) {
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ if (sizeof(db.wheel_pin) + sizeof(db.so_pin) + sizeof(db.user_pin) > sizeof(page_buf))
+ return HAL_ERROR_BAD_ARGUMENTS;
- /* Put the three PINs into page_buf */
- offset = 0;
- memcpy(page_buf + offset, &db->wheel_pin, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(page_buf + offset, &db->so_pin, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(page_buf + offset, &db->user_pin, sizeof(db->user_pin));
-
- /* Write PINs into the second of the two reserved pages at the start of the sector. */
- offset = sector_offset + KEYSTORE_PAGE_SIZE;
- if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK) {
- return status;
- }
+ /* Put the three PINs into page_buf */
+ offset = 0;
+ memcpy(page_buf + offset, &db.wheel_pin, sizeof(db.wheel_pin));
+ offset += sizeof(db.wheel_pin);
+ memcpy(page_buf + offset, &db.so_pin, sizeof(db.so_pin));
+ offset += sizeof(db.so_pin);
+ memcpy(page_buf + offset, &db.user_pin, sizeof(db.user_pin));
+
+ /* Write PINs into the second of the two reserved pages at the start of the sector. */
+ offset = sector_offset + KEYSTORE_PAGE_SIZE;
+ if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK)
+ return status;
+
+ for (i = 0; i < sizeof(db.keys) / sizeof(*db.keys); i++) {
+ offset = _get_key_offset(i);
+ if (offset > KEYSTORE_SECTOR_SIZE)
+ return HAL_ERROR_BAD_ARGUMENTS;
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ offset += sector_offset;
- offset += sector_offset;
+ if ((status =_write_data_to_flash(offset, (uint8_t *) &db.keys[i], sizeof(*db.keys))) != LIBHAL_OK)
+ return status;
+ }
- if ((status =_write_data_to_flash(offset, (uint8_t *) &db->keys[i], sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
- }
- }
+ return LIBHAL_OK;
+}
- return LIBHAL_OK;
+static hal_error_t ks_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ hal_error_t err;
+
+ if (driver != hal_ks_flash_driver || ks == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if ((err = ks_init()) != LIBHAL_OK)
+ return err;
+
+ *ks = &db.ks;
+ return LIBHAL_OK;
}
-hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating)
+static hal_error_t ks_close(hal_ks_t *ks)
{
- hal_error_t status;
- uint32_t offset, active_sector_offset;
- hal_ks_key_t *tmp_key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ if (ks != NULL && ks != &db.ks)
+ return HAL_ERROR_BAD_ARGUMENTS;
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
- return HAL_ERROR_BAD_ARGUMENTS;
+ return LIBHAL_OK;
+}
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) return HAL_ERROR_BAD_ARGUMENTS;
+static inline int acceptable_key_type(const hal_key_type_t type)
+{
+ switch (type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ case HAL_KEY_TYPE_EC_PRIVATE:
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ case HAL_KEY_TYPE_EC_PUBLIC:
+ return 1;
+ default:
+ return 0;
+ }
+}
- active_sector_offset = _active_sector_offset();
+static inline hal_ks_key_t *find(const hal_key_type_t type,
+ const hal_uuid_t * const name)
+{
+ assert(name != NULL && acceptable_key_type(type));
- offset += active_sector_offset;
+ for (int i = 0; i < sizeof(db.keys)/sizeof(*db.keys); i++)
+ if (db.keys[i].in_use && db.keys[i].type == type && hal_uuid_cmp(&db.keys[i].name, name) == 0)
+ return &db.keys[i];
- if (keystore_check_id() != 1) return HAL_ERROR_KEYSTORE_ACCESS;
+ return NULL;
+}
- /* Check if there is a key occupying this slot in the flash already.
- * Don't trust the in-memory representation since it would mean data
- * corruption in flash if it had been altered.
- */
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- tmp_key = (hal_ks_key_t *) page_buf;
-
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
-
- if (tmp_key->in_use == 0xff) {
- /* Key slot was unused in flash. Write the new key there. */
- if ((status = _write_data_to_flash(offset, (uint8_t *) key, sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
- }
- } else {
- /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
- if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- if ((status =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK) {
- return status;
- }
- }
+static hal_error_t 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 != &db.ks || slot == NULL || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
- return LIBHAL_OK;
+ const hal_ks_key_t * const k = find(slot->type, &slot->name);
+
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ slot->curve = k->curve;
+ slot->flags = k->flags;
+
+ if (der == NULL && der_len != NULL)
+ *der_len = k->der_len;
+
+ if (der != NULL) {
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len, der_len_;
+ hal_error_t err;
+
+ if (der_len == NULL)
+ der_len = &der_len_;
+
+ *der_len = der_max;
+
+ if ((err = hal_ks_get_kek(kek, &kek_len, sizeof(kek))) == LIBHAL_OK)
+ err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len);
+
+ memset(kek, 0, sizeof(kek));
+
+ if (err != LIBHAL_OK)
+ return err;
+ }
+
+ return LIBHAL_OK;
+}
+
+static hal_error_t ks_list(hal_ks_t *ks,
+ hal_pkey_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max)
+{
+ if (ks != &db.ks || result == NULL || result_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *result_len = 0;
+
+ for (int i = 0; i < sizeof(db.keys)/sizeof(*db.keys); i++) {
+
+ if (!db.keys[i].in_use)
+ continue;
+
+ if (*result_len == result_max)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ result[*result_len].type = db.keys[i].type;
+ result[*result_len].curve = db.keys[i].curve;
+ result[*result_len].flags = db.keys[i].flags;
+ result[*result_len].name = db.keys[i].name;
+ ++ *result_len;
+ }
+
+ return LIBHAL_OK;
}
-hal_error_t hal_ks_del_keydb(const int loc)
+/*
+ * This function in particular really needs to be rewritten to take
+ * advantage of the new keystore API.
+ */
+
+static hal_error_t ks_store(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot,
+ const uint8_t * const der, const size_t der_len)
{
- uint32_t offset;
+ if (ks != &db.ks || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (find(slot->type, &slot->name) != NULL)
+ return HAL_ERROR_KEY_NAME_IN_USE;
+
+ int loc = -1;
+
+ for (int i = 0; i < sizeof(db.keys)/sizeof(*db.keys); i++)
+ if (!db.keys[i].in_use && loc < 0)
+ loc = i;
+
+ if (loc < 0)
+ return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
+
+ hal_ks_key_t k;
+ memset(&k, 0, sizeof(k));
+ k.der_len = sizeof(k.der);
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+
+ hal_error_t err;
+
+ if ((err = hal_ks_get_kek(kek, &kek_len, sizeof(kek))) == LIBHAL_OK)
+ err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k.der, &k.der_len);
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+ memset(kek, 0, sizeof(kek));
+
+ if (err != LIBHAL_OK)
+ return err;
+
+ k.name = slot->name;
+ k.type = slot->type;
+ k.curve = slot->curve;
+ k.flags = slot->flags;
+
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+
+ uint32_t offset = _get_key_offset(loc);
+
+ if (offset > KEYSTORE_SECTOR_SIZE)
return HAL_ERROR_BAD_ARGUMENTS;
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
+ uint32_t active_sector_offset = _active_sector_offset();
+
+ offset += active_sector_offset;
+
+ if (keystore_check_id() != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ /*
+ * Check if there is a key occupying this slot in the flash already.
+ * This includes the case where we've zeroed a former key without
+ * erasing the flash sector, so we have to check the flash itself,
+ * we can't just look at the in-memory representation.
+ */
+
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ const int unused_since_erasure = ((hal_ks_key_t *) page_buf)->in_use == 0xFF;
+
+ db.keys[loc] = k;
+ db.keys[loc].in_use = 1;
+
+ if (unused_since_erasure) {
+
+ /*
+ * Key slot was unused in flash, so we can just write the new key there.
+ */
+
+ if ((err = _write_data_to_flash(offset, (uint8_t *) &k, sizeof(k))) != LIBHAL_OK)
+ return err;
+
+ } else {
+
+ /*
+ * Key slot in flash has been used. We should be more clever than
+ * this, but for now we just rewrite the whole freaking keystore.
+ */
+
+ /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
+
+ if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
+ active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK)
+ return err;
}
+ return LIBHAL_OK;
+}
+
+static hal_error_t ks_delete(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot)
+{
+ if (ks != &db.ks || slot == NULL || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_ks_key_t *k = find(slot->type, &slot->name);
+
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ const int loc = k - db.keys
+ uint32_t offset = _get_key_offset(loc);
+
+ if (loc < 0 || offset > KEYSTORE_SECTOR_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
offset += _active_sector_offset();
- memset(&db->keys[loc], 0, sizeof(*db->keys));
+ memset(k, 0, sizeof(*k));
+
+ /*
+ * Setting bits to 0 never requires erasing flash. Just write it.
+ */
- /* Setting bits to 0 never requires erasing flash. Just write it. */
- return _write_data_to_flash(offset, (uint8_t *) &db->keys[loc], sizeof(*db->keys));
+ return _write_data_to_flash(offset, (uint8_t *) k, sizeof(*k));
+}
+
+const hal_ks_driver_t hal_ks_flash_driver[1] = {{
+ ks_flash_open,
+ ks_flash_close,
+ ks_store,
+ ks_fetch,
+ ks_delete,
+ ks_list
+}};
+
+/*
+ * The remaining functions aren't really part of the keystore API per se,
+ * but they all involve non-key data which we keep in the keystore
+ * because it's the flash we've got.
+ */
+
+hal_error_t hal_ks_get_pin(const hal_user_t user,
+ const hal_ks_pin_t **pin)
+{
+ if (pin == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+
+ if ((err = ks_init()) != LIBHAL_OK)
+ return err;
+
+ switch (user) {
+ case HAL_USER_WHEEL: *pin = &db.wheel_pin; break;
+ case HAL_USER_SO: *pin = &db.so_pin; break;
+ case HAL_USER_NORMAL: *pin = &db.user_pin; break;
+ default: return HAL_ERROR_BAD_ARGUMENTS;
+ }
+
+ /*
+ * If we were looking for the WHEEL PIN and it appears to be
+ * completely unset, return the compiled-in last-gasp PIN. This is
+ * a terrible answer, but we need some kind of bootstrapping
+ * mechanism. Feel free to suggest something better.
+ */
+
+ uint8_t u00 = 0x00, uFF = 0xFF;
+ for (int i = 0; i < sizeof((*pin)->pin); i++) {
+ u00 |= (*pin)->pin[i];
+ uFF &= (*pin)->pin[i];
+ }
+ for (int i = 0; i < sizeof((*pin)->salt); i++) {
+ u00 |= (*pin)->salt[i];
+ uFF &= (*pin)->salt[i];
+ }
+ if (user == HAL_USER_WHEEL && ((u00 == 0x00 && (*pin)->iterations == 0x00000000) ||
+ (uFF == 0xFF && (*pin)->iterations == 0xFFFFFFFF)))
+ *pin = &hal_last_gasp_pin;
+
+ return LIBHAL_OK;
}
hal_error_t hal_ks_set_pin(const hal_user_t user,
@@ -290,9 +567,9 @@ hal_error_t hal_ks_set_pin(const hal_user_t user,
hal_ks_pin_t *p = NULL;
switch (user) {
- case HAL_USER_WHEEL: p = &db->wheel_pin; break;
- case HAL_USER_SO: p = &db->so_pin; break;
- case HAL_USER_NORMAL: p = &db->user_pin; break;
+ case HAL_USER_WHEEL: p = &db.wheel_pin; break;
+ case HAL_USER_SO: p = &db.so_pin; break;
+ case HAL_USER_NORMAL: p = &db.user_pin; break;
default: return HAL_ERROR_BAD_ARGUMENTS;
}
@@ -306,9 +583,9 @@ hal_error_t hal_ks_set_pin(const hal_user_t user,
/* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
+ active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
return _write_db_to_flash(active_sector_offset);
}
@@ -325,16 +602,19 @@ hal_error_t hal_ks_get_kek(uint8_t *kek,
bitsToBytes(256));
hal_error_t err = masterkey_volatile_read(kek, len);
+
if (err == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
+ *kek_len = len;
+ return LIBHAL_OK;
}
+
if (masterkey_flash_read(kek, len) == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
+ *kek_len = len;
+ return LIBHAL_OK;
}
- /* Both keystores returned an error, probably HAL_ERROR_MASTERKEY_NOT_SET.
+ /*
+ * Both keystores returned an error, probably HAL_ERROR_MASTERKEY_NOT_SET.
* I could try to be clever and compare the errors, but really the volatile
* keystore is the important one (you shouldn't store the master key in
* flash), so return that error.
@@ -343,7 +623,6 @@ hal_error_t hal_ks_get_kek(uint8_t *kek,
}
-
/*
* Local variables:
* indent-tabs-mode: nil