diff options
author | Rob Austein <sra@hactrn.net> | 2016-09-01 15:37:07 -0400 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2016-09-01 15:37:07 -0400 |
commit | c2b116a5e46ed89bf1426def0c447d2e46cc9474 (patch) | |
tree | bf08b8a09de4335b7fe6c269b9d7eed79c70a73c /ks_flash.c | |
parent | ccdb3ab006dd46c125fc0277fa0ce2d3d7660147 (diff) |
Revised keystore API, part one. Not usable yet.
Changes to implement a revised keystore API. This code probably won't
even compile properly yet, and almost certainly will not run, but most
of the expected changes are complete at this point. Main points:
* Key names are now UUIDs, and are generated by the HSM, not the client.
* Keystore API no longer assumes that key database is resident in
memory (original API was written on the assumption that the keystore
flash would be mapped into the HSM CPU's address space, but
apparently the board and flash drivers don't really support that).
A few other changes have probably crept in, but the bulk of this
changeset is just following through implications of the above, some of
which percolate all the way back to the public RPC API.
Diffstat (limited to 'ks_flash.c')
-rw-r--r-- | ks_flash.c | 653 |
1 files changed, 466 insertions, 187 deletions
@@ -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 |