From f59533ee9807832ea5ca7dd5492592c8991a9f34 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sun, 28 May 2017 12:11:31 -0400 Subject: Further keystore cleanup and consolidation. Still not yet expected to compile, much less run, but getting closer. --- ks_token.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 ks_token.c (limited to 'ks_token.c') diff --git a/ks_token.c b/ks_token.c new file mode 100644 index 0000000..cc25ca5 --- /dev/null +++ b/ks_token.c @@ -0,0 +1,661 @@ +/* + * ks_token.c + * ---------- + * Keystore implementation in flash memory. + * + * Authors: Rob Austein, Fredrik Thulin + * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This keystore driver operates over bare flash, versus over a flash file + * system or flash translation layer. The block size is large enough to + * hold an AES-keywrapped 4096-bit RSA key. Any remaining space in the key + * block may be used to store attributes (opaque TLV blobs). If the + * attributes overflow the key block, additional blocks may be added, but + * no attribute may exceed the block size. + */ + +#include +#include +#include + +#include "hal.h" +#include "hal_internal.h" +#include "ks.h" + +#include "last_gasp_pin_internal.h" + +#define HAL_OK CMIS_HAL_OK +#include "stm-keystore.h" +#undef HAL_OK + +#ifndef KS_TOKEN_CACHE_SIZE +#define KS_TOKEN_CACHE_SIZE 4 +#endif + +#define NUM_FLASH_BLOCKS KEYSTORE_NUM_SUBSECTORS + +/* + * Keystore database. + */ + +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; +} ks_token_db_t; + +/* + * This is a bit silly, but it's safe enough, and it lets us avoid a + * nasty mess of forward references. + */ + +#define db ((ks_token_db_t * const) hal_ks_token) + +/* + * PIN block gets the all-zeros UUID, which will never be returned by + * the UUID generation code (by definition -- it's not a version 4 UUID). + */ + +const static hal_uuid_t pin_uuid = {{0}}; + +/* + * Calculate offset of the block in the flash address space. + */ + +static inline uint32_t ks_token_offset(const unsigned blockno) +{ + return blockno * KEYSTORE_SUBSECTOR_SIZE; +} + +/* + * Read a flash block. + * + * Flash read on the Alpha is slow enough that it pays to check the + * first page before reading the rest of the block. + */ + +static hal_error_t ks_token_read(hal_k_t *ks, const unsigned blockno, ks_block_t *block) +{ + if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE) + return HAL_ERROR_IMPOSSIBLE; + + /* Sigh, magic numeric return codes */ + if (keystore_read_data(block_offset(blockno), + block->bytes, + KEYSTORE_PAGE_SIZE) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + switch (block_get_type(block)) { + case HAL_KS_BLOCK_TYPE_ERASED: + case HAL_KS_BLOCK_TYPE_ZEROED: + return HAL_OK; + case HAL_KS_BLOCK_TYPE_KEY: + case HAL_KS_BLOCK_TYPE_PIN: + break; + default: + return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE; + } + + switch (block_get_status(block)) { + case HAL_KS_BLOCK_STATUS_LIVE: + case HAL_KS_BLOCK_STATUS_TOMBSTONE: + break; + default: + return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE; + } + + /* Sigh, magic numeric return codes */ + if (keystore_read_data(block_offset(blockno) + KEYSTORE_PAGE_SIZE, + block->bytes + KEYSTORE_PAGE_SIZE, + sizeof(*block) - KEYSTORE_PAGE_SIZE) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + if (calculate_block_crc(block) != block->header.crc) + return HAL_ERROR_KEYSTORE_BAD_CRC; + + return HAL_OK; +} + +/* + * Convert a live block into a tombstone. Caller is responsible for + * making sure that the block being converted is valid; since we don't + * need to update the CRC for this, we just modify the first page. + */ + +static hal_error_t ks_token_deprecate(hal_k_t *ks, const unsigned blockno) +{ + if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) + return HAL_ERROR_IMPOSSIBLE; + + uint8_t page[KEYSTORE_PAGE_SIZE]; + flash_block_header_t *header = (void *) page; + uint32_t offset = ks_token_offset(blockno); + + /* Sigh, magic numeric return codes */ + if (keystore_read_data(offset, page, sizeof(page)) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + header->block_status = HAL_KS_BLOCK_STATUS_TOMBSTONE; + + /* Sigh, magic numeric return codes */ + if (keystore_write_data(offset, page, sizeof(page)) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + return HAL_OK; +} + +/* + * Zero (not erase) a flash block. Just need to zero the first page. + */ + +static hal_error_t ks_token_zero(hal_k_t *ks, const unsigned blockno) +{ + if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) + return HAL_ERROR_IMPOSSIBLE; + + uint8_t page[KEYSTORE_PAGE_SIZE] = {0}; + + /* Sigh, magic numeric return codes */ + if (keystore_write_data(block_offset(blockno), page, sizeof(page)) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + return HAL_OK; +} + +/* + * Erase a flash block. Also see ks_token_erase_maybe(), below. + */ + +static hal_error_t ks_token_erase(hal_k_t *ks, const unsigned blockno) +{ + if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) + return HAL_ERROR_IMPOSSIBLE; + + /* Sigh, magic numeric return codes */ + if (keystore_erase_subsector(blockno) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + return HAL_OK; +} + +/* + * Erase a flash block if it hasn't already been erased. + * May not be necessary, trying to avoid unnecessary wear. + * + * Unclear whether there's any sane reason why this needs to be + * constant time, given how slow erasure is. But side channel attacks + * can be tricky things, and it's theoretically possible that we could + * leak information about, eg, key length, so we do constant time. + */ + +static hal_error_t ks_token_erase_maybe(hal_k_t *ks, const unsigned blockno) +{ + if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) + return HAL_ERROR_IMPOSSIBLE; + + uint8_t mask = 0xFF; + + for (uint32_t a = ks_token_offset(blockno); a < ks_token_offset(blockno + 1); a += KEYSTORE_PAGE_SIZE) { + uint8_t page[KEYSTORE_PAGE_SIZE]; + if (keystore_read_data(a, page, sizeof(page)) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + for (int i = 0; i < KEYSTORE_PAGE_SIZE; i++) + mask &= page[i]; + } + + return mask == 0xFF ? HAL_OK : ks_token_erase(blockno); +} + +/* + * Write a flash block, calculating CRC when appropriate. + */ + +static hal_error_t ks_token_write(hal_k_t *ks, const unsigned blockno, ks_block_t *block) +{ + if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE) + return HAL_ERROR_IMPOSSIBLE; + + hal_error_t err = ks_token_erase_maybe(blockno); + + if (err != HAL_OK) + return err; + + switch (block_get_type(block)) { + case HAL_KS_BLOCK_TYPE_KEY: + case HAL_KS_BLOCK_TYPE_PIN: + block->header.crc = calculate_block_crc(block); + break; + default: + break; + } + + /* Sigh, magic numeric return codes */ + if (keystore_write_data(block_offset(blockno), block->bytes, sizeof(*block)) != 1) + return HAL_ERROR_KEYSTORE_ACCESS; + + return HAL_OK; +} + +/* + * The token keystore doesn't implement per-session objects, so these are no-ops. + */ + +static hal_error_t ks_token_set_owner(hal_ks_t *ks, + const unsigned blockno, + const hal_client_handle_t client, + const hal_session_handle_t session) +{ + return HAL_OK; +} + +static hal_error_t ks_token_test_owner(hal_ks_t *ks, const + unsigned blockno, + const hal_client_handle_t client, + const hal_session_handle_t session) +{ + return HAL_OK; +} + +/* + * Forward reference. + */ + +static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block); + +/* + * Initialize keystore. + */ + +static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) +{ + if (ks != hal_ks_token) + return HAL_ERROR_IMPOSSIBLE; + + hal_error_t err = HAL_OK; + + hal_ks_lock(); + + if (alloc && (err = hal_ks_alloc_common(ks, NUM_FLASH_BLOCKS, KS_TOKEN_CACHE_SIZE, NULL, 0)) != HAL_OK) + goto done; + + if ((err = hal_ks_init_common(ks)) != HAL_OK) + goto done; + + /* + * Fetch or create the PIN block. + */ + + memset(&db->wheel_pin, 0, sizeof(db->wheel_pin)); + memset(&db->so_pin, 0, sizeof(db->so_pin)); + memset(&db->user_pin, 0, sizeof(db->user_pin)); + + err = fetch_pin_block(NULL, &block); + + if (err == HAL_OK) { + db->wheel_pin = block->pin.wheel_pin; + db->so_pin = block->pin.so_pin; + db->user_pin = block->pin.user_pin; + } + + else if (err != HAL_ERROR_KEY_NOT_FOUND) + goto done; + + else { + /* + * We found no PIN block, so create one, with the user and so PINs + * cleared and the wheel PIN set to the last-gasp value. The + * last-gasp WHEEL PIN is a terrible answer, but we need some kind + * of bootstrapping mechanism when all else fails. If you have a + * better suggestion, we'd love to hear it. + */ + + unsigned b; + + memset(block, 0xFF, sizeof(*block)); + + block->header.block_type = HAL_KS_BLOCK_TYPE_PIN; + block->header.block_status = HAL_KS_BLOCK_STATUS_LIVE; + + block->pin.wheel_pin = db->wheel_pin = hal_last_gasp_pin; + block->pin.so_pin = db->so_pin; + block->pin.user_pin = db->user_pin; + + if ((err = hal_ks_index_add(ks, &pin_uuid, &b, NULL)) != HAL_OK) + goto done; + + cache_mark_used(block, b); + + err = ks_token_write(b, block); + + cache_release(block); + + if (err != HAL_OK) + goto done; + } + + err = HAL_OK; + + done: + hal_ks_unlock(); + return err; +} + +/* + * Dispatch vector and keystore definition, now that we've defined all + * the driver functions. + */ + +static const hal_ks_driver_t ks_token_driver = { + .init = ks_token_init, + .read = ks_token_read, + .write = ks_token_write, + .deprecate = ks_token_deprecate, + .zero = ks_token_zero, + .erase = ks_token_erase, + .erase_maybe = ks_token_erase_maybe, + .set_owner = ks_token_set_owner, + .test_owner = ks_token_test_owner +}; + +static ks_token_db_t _db = { .ks.driver = &ks_token_driver }; + +hal_ks_t * const hal_ks_token = &_db.ks; + +/* + * 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. + */ + +/* + * Special bonus init routine used only by the bootloader, so that it + * can read PINs set by the main firmware. Yes, this is a kludge. We + * could of course call the real ks_init() routine instead, but it's + * slow, and we don't want to allow anything that would modify the + * flash here, so having a special entry point for this kludge is + * simplest, overall. Sigh. + */ + +void hal_ks_init_read_only_pins_only(void) +{ + unsigned b, best_seen = ~0; + ks_block_t block[1]; + + hal_ks_lock(); + + for (b = 0; b < NUM_FLASH_BLOCKS; b++) { + if (block_read(b, block) != HAL_OK || ks_token_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) + continue; + best_seen = b; + if (block_get_status(block) == HAL_KS_BLOCK_STATUS_LIVE) + break; + } + + if (b != best_seen && best_seen != ~0 && ks_token_read(best_seen, block) != HAL_OK) + best_seen = ~0; + + if (best_seen == ~0) { + memset(block, 0xFF, sizeof(*block)); + block->pin.wheel_pin = hal_last_gasp_pin; + } + + db->wheel_pin = block->pin.wheel_pin; + db->so_pin = block->pin.so_pin; + db->user_pin = block->pin.user_pin; + + hal_ks_unlock(); +} + +/* + * Fetch PIN. This is always cached, so just returned cached value. + */ + +hal_error_t hal_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 = HAL_OK; + + hal_ks_lock(); + + 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: err = HAL_ERROR_BAD_ARGUMENTS; + } + + hal_ks_unlock(); + + return err; +} + +/* + * Fetch PIN block. hint = 0 because we know that the all-zeros UUID + * should always sort to first slot in the index. + */ + +static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block) +{ + if (block == NULL) + return HAL_ERROR_IMPOSSIBLE; + + hal_error_t err; + int hint = 0; + unsigned b_; + + if (b == NULL) + b = &b_; + + if ((err = hal_ks_index_find(hal_ks_token, &pin_uuid, b, &hint)) != HAL_OK || + (err = ks_token_read_cached(*b, block)) != HAL_OK) + return err; + + cache_mark_used(*block, *b); + + if (block_get_type(*block) != HAL_KS_BLOCK_TYPE_PIN) + return HAL_ERROR_IMPOSSIBLE; + + return HAL_OK; +} + +/* + * Update the PIN block. This block should always be present, but we + * have to do the zombie jamboree to make sure we write the new PIN + * block before destroying the old one. hint = 0 because we know that + * the all-zeros UUID should always sort to first slot in the index. + */ + +static hal_error_t update_pin_block(const unsigned b, + ks_block_t *block, + const flash_pin_block_t * const new_data) +{ + if (block == NULL || new_data == NULL || ks_token_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) + return HAL_ERROR_IMPOSSIBLE; + + int hint = 0; + + block->pin = *new_data; + + return ks_token_update(b, block, &pin_uuid, &hint); +} + +/* + * Change a PIN. + */ + +hal_error_t hal_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin) +{ + if (pin == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + ks_block_t *block; + hal_error_t err; + unsigned b; + + hal_ks_lock(); + + if ((err = fetch_pin_block(&b, &block)) != HAL_OK) + goto done; + + flash_pin_block_t new_data = block->pin; + hal_ks_pin_t *dp, *bp; + + switch (user) { + case HAL_USER_WHEEL: bp = &new_data.wheel_pin; dp = &db->wheel_pin; break; + case HAL_USER_SO: bp = &new_data.so_pin; dp = &db->so_pin; break; + case HAL_USER_NORMAL: bp = &new_data.user_pin; dp = &db->user_pin; break; + default: err = HAL_ERROR_BAD_ARGUMENTS; goto done; + } + + const hal_ks_pin_t old_pin = *dp; + *dp = *bp = *pin; + + if ((err = update_pin_block(b, block, &new_data)) != HAL_OK) + *dp = old_pin; + + done: + hal_ks_unlock(); + return err; +} + +#if HAL_MKM_FLASH_BACKUP_KLUDGE + +/* + * Horrible insecure kludge in lieu of a battery for the MKM. + * + * API here is a little strange: all calls pass a length parameter, + * but any length other than the compiled in constant just returns an + * immediate error, there's no notion of buffer max length vs buffer + * used length, querying for the size of buffer really needed, or + * anything like that. + * + * We might want to rewrite this some day, if we don't replace it with + * a battery first. For now we just preserve the API as we found it + * while re-implementing it on top of the new keystore. + */ + +hal_error_t hal_mkm_flash_read_no_lock(uint8_t *buf, const size_t len) +{ + if (buf != NULL && len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + ks_block_t *block; + hal_error_t err; + unsigned b; + + if ((err = fetch_pin_block(&b, &block)) != HAL_OK) + return err; + + if (block->pin.kek_set != FLASH_KEK_SET) + return HAL_ERROR_MASTERKEY_NOT_SET; + + if (buf != NULL) + memcpy(buf, block->pin.kek, len); + + return HAL_OK; +} + +hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len) +{ + hal_ks_lock(); + const hal_error_t err = hal_mkm_flash_read_no_lock(buf, len); + hal_ks_unlock(); + return err; +} + +hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len) +{ + if (buf == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + ks_block_t *block; + hal_error_t err; + unsigned b; + + hal_ks_lock(); + + if ((err = fetch_pin_block(&b, &block)) != HAL_OK) + goto done; + + flash_pin_block_t new_data = block->pin; + + new_data.kek_set = FLASH_KEK_SET; + memcpy(new_data.kek, buf, len); + + err = update_pin_block(b, block, &new_data); + + done: + hal_ks_unlock(); + return err; +} + +hal_error_t hal_mkm_flash_erase(const size_t len) +{ + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + ks_block_t *block; + hal_error_t err; + unsigned b; + + hal_ks_lock(); + + if ((err = fetch_pin_block(&b, &block)) != HAL_OK) + goto done; + + flash_pin_block_t new_data = block->pin; + + new_data.kek_set = FLASH_KEK_SET; + memset(new_data.kek, 0, len); + + err = update_pin_block(b, block, &new_data); + + done: + hal_ks_unlock(); + return err; +} + +#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */ + + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3 From 2caa6c72640877abc5f3572c4d926a23ff672ab1 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sun, 28 May 2017 16:11:25 -0400 Subject: Almost compiles. Need to refactor init sequence slightly (again), this time to humor the bootloader, which has its own special read-only view of the PIN block in the token keystore. --- ks_token.c | 107 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'ks_token.c') diff --git a/ks_token.c b/ks_token.c index cc25ca5..c2ebee2 100644 --- a/ks_token.c +++ b/ks_token.c @@ -62,6 +62,10 @@ #define NUM_FLASH_BLOCKS KEYSTORE_NUM_SUBSECTORS +#if HAL_KS_BLOCK_SIZE % KEYSTORE_SUBSECTOR_SIZE != 0 +#error Keystore block size is not a multiple of flash subsector size +#endif + /* * Keystore database. */ @@ -80,13 +84,6 @@ typedef struct { #define db ((ks_token_db_t * const) hal_ks_token) -/* - * PIN block gets the all-zeros UUID, which will never be returned by - * the UUID generation code (by definition -- it's not a version 4 UUID). - */ - -const static hal_uuid_t pin_uuid = {{0}}; - /* * Calculate offset of the block in the flash address space. */ @@ -103,18 +100,18 @@ static inline uint32_t ks_token_offset(const unsigned blockno) * first page before reading the rest of the block. */ -static hal_error_t ks_token_read(hal_k_t *ks, const unsigned blockno, ks_block_t *block) +static hal_error_t ks_token_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block) { if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE) return HAL_ERROR_IMPOSSIBLE; /* Sigh, magic numeric return codes */ - if (keystore_read_data(block_offset(blockno), + if (keystore_read_data(ks_token_offset(blockno), block->bytes, KEYSTORE_PAGE_SIZE) != 1) return HAL_ERROR_KEYSTORE_ACCESS; - switch (block_get_type(block)) { + switch (hal_ks_block_get_type(block)) { case HAL_KS_BLOCK_TYPE_ERASED: case HAL_KS_BLOCK_TYPE_ZEROED: return HAL_OK; @@ -125,7 +122,7 @@ static hal_error_t ks_token_read(hal_k_t *ks, const unsigned blockno, ks_block_t return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE; } - switch (block_get_status(block)) { + switch (hal_ks_block_get_status(block)) { case HAL_KS_BLOCK_STATUS_LIVE: case HAL_KS_BLOCK_STATUS_TOMBSTONE: break; @@ -134,12 +131,12 @@ static hal_error_t ks_token_read(hal_k_t *ks, const unsigned blockno, ks_block_t } /* Sigh, magic numeric return codes */ - if (keystore_read_data(block_offset(blockno) + KEYSTORE_PAGE_SIZE, + if (keystore_read_data(ks_token_offset(blockno) + KEYSTORE_PAGE_SIZE, block->bytes + KEYSTORE_PAGE_SIZE, sizeof(*block) - KEYSTORE_PAGE_SIZE) != 1) return HAL_ERROR_KEYSTORE_ACCESS; - if (calculate_block_crc(block) != block->header.crc) + if (hal_ks_block_calculate_crc(block) != block->header.crc) return HAL_ERROR_KEYSTORE_BAD_CRC; return HAL_OK; @@ -151,13 +148,13 @@ static hal_error_t ks_token_read(hal_k_t *ks, const unsigned blockno, ks_block_t * need to update the CRC for this, we just modify the first page. */ -static hal_error_t ks_token_deprecate(hal_k_t *ks, const unsigned blockno) +static hal_error_t ks_token_deprecate(hal_ks_t *ks, const unsigned blockno) { if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) return HAL_ERROR_IMPOSSIBLE; uint8_t page[KEYSTORE_PAGE_SIZE]; - flash_block_header_t *header = (void *) page; + hal_ks_block_header_t *header = (void *) page; uint32_t offset = ks_token_offset(blockno); /* Sigh, magic numeric return codes */ @@ -177,7 +174,7 @@ static hal_error_t ks_token_deprecate(hal_k_t *ks, const unsigned blockno) * Zero (not erase) a flash block. Just need to zero the first page. */ -static hal_error_t ks_token_zero(hal_k_t *ks, const unsigned blockno) +static hal_error_t ks_token_zero(hal_ks_t *ks, const unsigned blockno) { if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) return HAL_ERROR_IMPOSSIBLE; @@ -185,7 +182,7 @@ static hal_error_t ks_token_zero(hal_k_t *ks, const unsigned blockno) uint8_t page[KEYSTORE_PAGE_SIZE] = {0}; /* Sigh, magic numeric return codes */ - if (keystore_write_data(block_offset(blockno), page, sizeof(page)) != 1) + if (keystore_write_data(ks_token_offset(blockno), page, sizeof(page)) != 1) return HAL_ERROR_KEYSTORE_ACCESS; return HAL_OK; @@ -195,7 +192,7 @@ static hal_error_t ks_token_zero(hal_k_t *ks, const unsigned blockno) * Erase a flash block. Also see ks_token_erase_maybe(), below. */ -static hal_error_t ks_token_erase(hal_k_t *ks, const unsigned blockno) +static hal_error_t ks_token_erase(hal_ks_t *ks, const unsigned blockno) { if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) return HAL_ERROR_IMPOSSIBLE; @@ -217,7 +214,7 @@ static hal_error_t ks_token_erase(hal_k_t *ks, const unsigned blockno) * leak information about, eg, key length, so we do constant time. */ -static hal_error_t ks_token_erase_maybe(hal_k_t *ks, const unsigned blockno) +static hal_error_t ks_token_erase_maybe(hal_ks_t *ks, const unsigned blockno) { if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS) return HAL_ERROR_IMPOSSIBLE; @@ -232,34 +229,34 @@ static hal_error_t ks_token_erase_maybe(hal_k_t *ks, const unsigned blockno) mask &= page[i]; } - return mask == 0xFF ? HAL_OK : ks_token_erase(blockno); + return mask == 0xFF ? HAL_OK : ks_token_erase(ks, blockno); } /* * Write a flash block, calculating CRC when appropriate. */ -static hal_error_t ks_token_write(hal_k_t *ks, const unsigned blockno, ks_block_t *block) +static hal_error_t ks_token_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block) { if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE) return HAL_ERROR_IMPOSSIBLE; - hal_error_t err = ks_token_erase_maybe(blockno); + hal_error_t err = ks_token_erase_maybe(ks, blockno); if (err != HAL_OK) return err; - switch (block_get_type(block)) { + switch (hal_ks_block_get_type(block)) { case HAL_KS_BLOCK_TYPE_KEY: case HAL_KS_BLOCK_TYPE_PIN: - block->header.crc = calculate_block_crc(block); + block->header.crc = hal_ks_block_calculate_crc(block); break; default: break; } /* Sigh, magic numeric return codes */ - if (keystore_write_data(block_offset(blockno), block->bytes, sizeof(*block)) != 1) + if (keystore_write_data(ks_token_offset(blockno), block->bytes, sizeof(*block)) != 1) return HAL_ERROR_KEYSTORE_ACCESS; return HAL_OK; @@ -289,7 +286,7 @@ static hal_error_t ks_token_test_owner(hal_ks_t *ks, const * Forward reference. */ -static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block); +static hal_error_t fetch_pin_block(unsigned *b, hal_ks_block_t **block); /* * Initialize keystore. @@ -300,6 +297,7 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) if (ks != hal_ks_token) return HAL_ERROR_IMPOSSIBLE; + hal_ks_block_t *block = NULL; hal_error_t err = HAL_OK; hal_ks_lock(); @@ -349,14 +347,14 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) block->pin.so_pin = db->so_pin; block->pin.user_pin = db->user_pin; - if ((err = hal_ks_index_add(ks, &pin_uuid, &b, NULL)) != HAL_OK) + if ((err = hal_ks_index_add(ks, &hal_ks_pin_uuid, &b, NULL)) != HAL_OK) goto done; - cache_mark_used(block, b); + hal_ks_cache_mark_used(ks, block, b); - err = ks_token_write(b, block); + err = ks_token_write(ks, b, block); - cache_release(block); + hal_ks_cache_release(ks, block); if (err != HAL_OK) goto done; @@ -376,12 +374,12 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) static const hal_ks_driver_t ks_token_driver = { .init = ks_token_init, - .read = ks_token_read, + .read = ks_token_read, .write = ks_token_write, - .deprecate = ks_token_deprecate, + .deprecate = ks_token_deprecate, .zero = ks_token_zero, .erase = ks_token_erase, - .erase_maybe = ks_token_erase_maybe, + .erase_maybe = ks_token_erase_maybe, .set_owner = ks_token_set_owner, .test_owner = ks_token_test_owner }; @@ -408,19 +406,21 @@ hal_ks_t * const hal_ks_token = &_db.ks; void hal_ks_init_read_only_pins_only(void) { unsigned b, best_seen = ~0; - ks_block_t block[1]; + hal_ks_block_t block[1]; hal_ks_lock(); for (b = 0; b < NUM_FLASH_BLOCKS; b++) { - if (block_read(b, block) != HAL_OK || ks_token_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) + if (hal_ks_block_read(hal_ks_token, b, block) != HAL_OK || + hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) continue; best_seen = b; - if (block_get_status(block) == HAL_KS_BLOCK_STATUS_LIVE) + if (hal_ks_block_get_status(block) == HAL_KS_BLOCK_STATUS_LIVE) break; } - if (b != best_seen && best_seen != ~0 && ks_token_read(best_seen, block) != HAL_OK) + if (b != best_seen && best_seen != ~0 && + hal_ks_block_read(hal_ks_token, best_seen, block) != HAL_OK) best_seen = ~0; if (best_seen == ~0) { @@ -466,7 +466,7 @@ hal_error_t hal_get_pin(const hal_user_t user, * should always sort to first slot in the index. */ -static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block) +static hal_error_t fetch_pin_block(unsigned *b, hal_ks_block_t **block) { if (block == NULL) return HAL_ERROR_IMPOSSIBLE; @@ -478,13 +478,13 @@ static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block) if (b == NULL) b = &b_; - if ((err = hal_ks_index_find(hal_ks_token, &pin_uuid, b, &hint)) != HAL_OK || - (err = ks_token_read_cached(*b, block)) != HAL_OK) + if ((err = hal_ks_index_find(hal_ks_token, &hal_ks_pin_uuid, b, &hint)) != HAL_OK || + (err = hal_ks_block_read_cached(hal_ks_token, *b, block)) != HAL_OK) return err; - cache_mark_used(*block, *b); + hal_ks_cache_mark_used(hal_ks_token, *block, *b); - if (block_get_type(*block) != HAL_KS_BLOCK_TYPE_PIN) + if (hal_ks_block_get_type(*block) != HAL_KS_BLOCK_TYPE_PIN) return HAL_ERROR_IMPOSSIBLE; return HAL_OK; @@ -498,17 +498,17 @@ static hal_error_t fetch_pin_block(unsigned *b, ks_block_t **block) */ static hal_error_t update_pin_block(const unsigned b, - ks_block_t *block, - const flash_pin_block_t * const new_data) + hal_ks_block_t *block, + const hal_ks_pin_block_t * const new_data) { - if (block == NULL || new_data == NULL || ks_token_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) + if (block == NULL || new_data == NULL || hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_PIN) return HAL_ERROR_IMPOSSIBLE; int hint = 0; block->pin = *new_data; - return ks_token_update(b, block, &pin_uuid, &hint); + return hal_ks_block_update(hal_ks_token, b, block, &hal_ks_pin_uuid, &hint); } /* @@ -521,7 +521,7 @@ hal_error_t hal_set_pin(const hal_user_t user, if (pin == NULL) return HAL_ERROR_BAD_ARGUMENTS; - ks_block_t *block; + hal_ks_block_t *block; hal_error_t err; unsigned b; @@ -530,7 +530,7 @@ hal_error_t hal_set_pin(const hal_user_t user, if ((err = fetch_pin_block(&b, &block)) != HAL_OK) goto done; - flash_pin_block_t new_data = block->pin; + hal_ks_pin_block_t new_data = block->pin; hal_ks_pin_t *dp, *bp; switch (user) { @@ -572,7 +572,7 @@ hal_error_t hal_mkm_flash_read_no_lock(uint8_t *buf, const size_t len) if (buf != NULL && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - ks_block_t *block; + hal_ks_block_t *block; hal_error_t err; unsigned b; @@ -604,7 +604,7 @@ hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len) if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - ks_block_t *block; + hal_ks_block_t *block; hal_error_t err; unsigned b; @@ -613,7 +613,7 @@ hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len) if ((err = fetch_pin_block(&b, &block)) != HAL_OK) goto done; - flash_pin_block_t new_data = block->pin; + hal_ks_pin_block_t new_data = block->pin; new_data.kek_set = FLASH_KEK_SET; memcpy(new_data.kek, buf, len); @@ -630,7 +630,7 @@ hal_error_t hal_mkm_flash_erase(const size_t len) if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - ks_block_t *block; + hal_ks_block_t *block; hal_error_t err; unsigned b; @@ -639,7 +639,7 @@ hal_error_t hal_mkm_flash_erase(const size_t len) if ((err = fetch_pin_block(&b, &block)) != HAL_OK) goto done; - flash_pin_block_t new_data = block->pin; + hal_ks_pin_block_t new_data = block->pin; new_data.kek_set = FLASH_KEK_SET; memset(new_data.kek, 0, len); @@ -653,7 +653,6 @@ hal_error_t hal_mkm_flash_erase(const size_t len) #endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */ - /* * Local variables: * indent-tabs-mode: nil -- cgit v1.2.3 From 9e20f2fa42bcd493548bf7764958848ab72d1255 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sun, 28 May 2017 18:50:23 -0400 Subject: Debug new keystore init code. --- ks_token.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'ks_token.c') diff --git a/ks_token.c b/ks_token.c index c2ebee2..6172f79 100644 --- a/ks_token.c +++ b/ks_token.c @@ -338,6 +338,11 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) unsigned b; + if ((block = hal_ks_cache_pick_lru(ks)) == NULL) { + err = HAL_ERROR_IMPOSSIBLE; + goto done; + } + memset(block, 0xFF, sizeof(*block)); block->header.block_type = HAL_KS_BLOCK_TYPE_PIN; -- cgit v1.2.3 From 5cee716555db92942c5b11c824839bb00aaf35b9 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Mon, 29 May 2017 00:44:18 -0400 Subject: Debug per-session keys. --- ks_token.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'ks_token.c') diff --git a/ks_token.c b/ks_token.c index 6172f79..e69eb02 100644 --- a/ks_token.c +++ b/ks_token.c @@ -267,17 +267,24 @@ static hal_error_t ks_token_write(hal_ks_t *ks, const unsigned blockno, hal_ks_b */ static hal_error_t ks_token_set_owner(hal_ks_t *ks, - const unsigned blockno, - const hal_client_handle_t client, - const hal_session_handle_t session) + const unsigned blockno, + const hal_client_handle_t client, + const hal_session_handle_t session) { return HAL_OK; } -static hal_error_t ks_token_test_owner(hal_ks_t *ks, const - unsigned blockno, - const hal_client_handle_t client, - const hal_session_handle_t session) +static hal_error_t ks_token_test_owner(hal_ks_t *ks, + const unsigned blockno, + const hal_client_handle_t client, + const hal_session_handle_t session) +{ + return HAL_OK; +} + +static hal_error_t ks_token_copy_owner(hal_ks_t *ks, + const unsigned source, + const unsigned target) { return HAL_OK; } @@ -386,7 +393,8 @@ static const hal_ks_driver_t ks_token_driver = { .erase = ks_token_erase, .erase_maybe = ks_token_erase_maybe, .set_owner = ks_token_set_owner, - .test_owner = ks_token_test_owner + .test_owner = ks_token_test_owner, + .copy_owner = ks_token_copy_owner }; static ks_token_db_t _db = { .ks.driver = &ks_token_driver }; -- cgit v1.2.3 From 6b881dfa81a0d51d4897c62de5abdb94c1aba0b7 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Tue, 30 May 2017 19:52:32 -0400 Subject: Hold keystore lock before calling keystore driver methods. Most keystore methods already followed this rule, but hal_ks_*_init() and hal_ks_*_logout() were confused, in different ways. --- ks_token.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'ks_token.c') diff --git a/ks_token.c b/ks_token.c index e29a90d..38ca5d8 100644 --- a/ks_token.c +++ b/ks_token.c @@ -313,13 +313,11 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) hal_ks_block_t *block = NULL; hal_error_t err = HAL_OK; - hal_ks_lock(); - if (alloc && (err = hal_ks_alloc_common(ks, NUM_FLASH_BLOCKS, KS_TOKEN_CACHE_SIZE, NULL, 0)) != HAL_OK) - goto done; + return err; if ((err = hal_ks_init_common(ks)) != HAL_OK) - goto done; + return err; /* * Fetch or create the PIN block. @@ -337,10 +335,7 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) db->user_pin = block->pin.user_pin; } - else if (err != HAL_ERROR_KEY_NOT_FOUND) - goto done; - - else { + else if (err == HAL_ERROR_KEY_NOT_FOUND) { /* * We found no PIN block, so create one, with the user and so PINs * cleared and the wheel PIN set to the last-gasp value. The @@ -351,10 +346,8 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) unsigned b; - if ((block = hal_ks_cache_pick_lru(ks)) == NULL) { - err = HAL_ERROR_IMPOSSIBLE; - goto done; - } + if ((block = hal_ks_cache_pick_lru(ks)) == NULL) + return HAL_ERROR_IMPOSSIBLE; memset(block, 0xFF, sizeof(*block)); @@ -366,22 +359,15 @@ static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc) block->pin.user_pin = db->user_pin; if ((err = hal_ks_index_add(ks, &hal_ks_pin_uuid, &b, NULL)) != HAL_OK) - goto done; + return err; hal_ks_cache_mark_used(ks, block, b); err = ks_token_write(ks, b, block); hal_ks_cache_release(ks, block); - - if (err != HAL_OK) - goto done; } - err = HAL_OK; - - done: - hal_ks_unlock(); return err; } -- cgit v1.2.3