From 38c4b787fa7c1f5e7fbf810cdda136621dd743b7 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Tue, 13 Sep 2016 16:37:39 -0400 Subject: Cleanup prior to rewriting ks_flash.c. Whack masterkey code to meet libhal coding standards, such as they are. Started layout of new ks_flash data structures but no changes to functions or flash usage yet. MKM initialization from flash placed under compile-time conditional with warning because it's a dangerous kludge that should go away. Started getting rid of obsolete keystore code; ks_mmap.c kept for now, until I get around to merging the useful bits into ks_volatile. --- Makefile | 2 +- hal_internal.h | 83 ++++++------ ks.c | 411 --------------------------------------------------------- ks_flash.c | 170 +++++++++++++++++------- ks_mmap.c | 2 +- ks_volatile.c | 4 +- masterkey.c | 248 ---------------------------------- masterkey.h | 46 ------- mkm.c | 320 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 488 insertions(+), 798 deletions(-) delete mode 100644 ks.c delete mode 100644 masterkey.c delete mode 100644 masterkey.h create mode 100644 mkm.c diff --git a/Makefile b/Makefile index d500641..b4c6086 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ KS_OBJ = ks_index.o ks_volatile.o ifeq "${KS}" "mmap" KS_OBJ += ks_mmap.o else ifeq "${KS}" "flash" - KS_OBJ += ks_flash.o masterkey.o + KS_OBJ += ks_flash.o mkm.o endif # RPC_MODE = none | server | client-simple | client-mixed diff --git a/hal_internal.h b/hal_internal.h index e92f22a..a6dc619 100644 --- a/hal_internal.h +++ b/hal_internal.h @@ -293,16 +293,6 @@ static inline hal_crc32_t hal_crc32_finalize(hal_crc32_t crc) return crc ^ 0xffffffff; } -/* - * Keystore API. - */ - -/* - * The first chunk of this is stuff that's really internal to the - * keystore implementation(s), and perhaps should move to a separate - * ks_internal.h. - */ - /* * Sizes for ASN.1-encoded keys, this may not be exact due to ASN.1 * INTEGER encoding rules but should be good enough for buffer sizing: @@ -321,27 +311,11 @@ static inline hal_crc32_t hal_crc32_finalize(hal_crc32_t crc) #define HAL_KS_WRAPPED_KEYSIZE ((4655 + 15) & ~7) /* - * hal_ks_key_t probably should not be here, or perhaps even exist at - * all, since it's really a relic of an older design from before we - * understood how the keystore flash fit into this picture. Leaving - * it in place for now, but expect it to go away once the new ks_index - * stuff is ready to use. + * PINs. * - * This struct is ordered such that all metadata appears before the - * big buffers, in order for all metadata to be loaded with a single - * page read from e.g. the ks_flash module. + * The functions here might want renaming, eg, to hal_pin_*(). */ -typedef struct { - hal_key_type_t type; - hal_curve_name_t curve; - hal_key_flags_t flags; - uint8_t in_use; - size_t der_len; - hal_uuid_t name; - uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; -} hal_ks_key_t; - #ifndef HAL_PIN_SALT_LENGTH #define HAL_PIN_SALT_LENGTH 16 #endif @@ -352,9 +326,43 @@ typedef struct { uint8_t salt[HAL_PIN_SALT_LENGTH]; } hal_ks_pin_t; -extern hal_error_t hal_get_kek(uint8_t *kek, - size_t *kek_len, - const size_t kek_max); +extern hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client, + const uint32_t iterations); + +extern hal_error_t hal_get_pin(const hal_user_t user, + const hal_ks_pin_t **pin); + +extern hal_error_t hal_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin); + +/* + * Master key memory (MKM) and key-encryption-key (KEK). + * + * Providing a mechanism for storing the KEK in flash is a horrible + * kludge which defeats the entire purpose of having the MKM. We + * support it for now because the Alpha hardware does not yet have + * a working battery backup for the MKM, but it should go away RSN. + */ + +#ifndef HAL_MKM_FLASH_BACKUP_KLUDGE +#define HAL_MKM_FLASH_BACKUP_KLUDGE 1 +#endif + +extern hal_error_t hal_mkm_get_kek(uint8_t *kek, size_t *kek_len, const size_t kek_max); + +extern hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len); +extern hal_error_t hal_mkm_volatile_write(const uint8_t * const buf, const size_t len); +extern hal_error_t hal_mkm_volatile_erase(const size_t len); + +#if HAL_MKM_FLASH_BACKUP_KLUDGE + +#warning MKM flash backup kludge enabled. Do NOT use this in production! + +extern hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len); +extern hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len); +extern hal_error_t hal_mkm_flash_erase(const size_t len); + +#endif /* * Keystore API for use by the pkey implementation. @@ -612,19 +620,6 @@ extern hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi, const hal_uuid_t * const name, unsigned *blockno); -/* - * This stuff might want renaming, eg, to hal_pin_*(). - */ - -extern hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client, - const uint32_t iterations); - -extern hal_error_t hal_get_pin(const hal_user_t user, - const hal_ks_pin_t **pin); - -extern hal_error_t hal_set_pin(const hal_user_t user, - const hal_ks_pin_t * const pin); - /* * RPC lowest-level send and receive routines. These are blocking, and * transport-specific (sockets, USB). diff --git a/ks.c b/ks.c deleted file mode 100644 index a2c0f3c..0000000 --- a/ks.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * ks.c - * ---- - * Keystore API. This is internal within libhal. - * - * Authors: Rob Austein - * Copyright (c) 2015, 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. - */ - -#include -#include - -#include "hal.h" -#include "hal_internal.h" -#include "last_gasp_pin_internal.h" - -#define KEK_LENGTH (bitsToBytes(256)) - -/* - * In "remote" and "mixed" RPC modes we're a software only RPC client - * without (direct) access to secure hardware, thus there is no real - * point in encrypting keys. As precautions, we (a) warn about this - * when configured in one of these modes, and (b) refuse to store any - * sort of private keys. - */ - -#define USE_KEK (RPC_CLIENT != RPC_CLIENT_REMOTE && RPC_CLIENT != RPC_CLIENT_MIXED) - -#if !USE_KEK -#warning ks.c compiled without KEK support and will only accept public keys -- this is normal for the host-side build of libhsm -#endif - -static inline int acceptable_key_type(const hal_key_type_t type) -{ - switch (type) { -#if USE_KEK - case HAL_KEY_TYPE_RSA_PRIVATE: - case HAL_KEY_TYPE_EC_PRIVATE: -#endif - case HAL_KEY_TYPE_RSA_PUBLIC: - case HAL_KEY_TYPE_EC_PUBLIC: - return 1; - default: - return 0; - } -} - -hal_error_t hal_ks_store(const hal_key_type_t type, - const hal_curve_name_t curve, - const hal_key_flags_t flags, - const uint8_t * const name, const size_t name_len, - const uint8_t * const der, const size_t der_len, - int *hint) -{ - if (name == NULL || der == NULL || der_len == 0 || !acceptable_key_type(type)) - return HAL_ERROR_BAD_ARGUMENTS; - - if (name_len > HAL_RPC_PKEY_NAME_MAX) - return HAL_ERROR_KEY_NAME_TOO_LONG; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - hal_error_t err; - int hint_; - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - if (hint == NULL) - hint = &hint_; - - *hint = -1; - - for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) { - if (!db->keys[i].in_use && *hint < 0) - *hint = i; - if (db->keys[i].in_use && - db->keys[i].type == type && - db->keys[i].name_len == name_len && memcmp(db->keys[i].name, name, name_len) == 0) - return HAL_ERROR_KEY_NAME_IN_USE; - } - - if (*hint < 0) - return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; - - hal_ks_key_t k; - memset(&k, 0, sizeof(k)); - k.der_len = sizeof(k.der); - -#if USE_KEK - - uint8_t kek[KEK_LENGTH]; - size_t kek_len; - - if ((err = hal_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) - err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k.der, &k.der_len); - - memset(kek, 0, sizeof(kek)); - - if (err != HAL_OK) - return err; - -#else /* USE_KEK */ - - if (der_len > k.der_len) - return HAL_ERROR_RESULT_TOO_LONG; - - k.der_len = der_len; - memcpy(k.der, der, der_len); - -#endif /* USE_KEK */ - - assert(name_len <= sizeof(k.name)); - memcpy(k.name, name, name_len); - k.name_len = name_len; - k.type = type; - k.curve = curve; - k.flags = flags; - - if ((err = hal_ks_set_keydb(&k, *hint, 0)) != HAL_OK) - return err; - - return HAL_OK; -} - -static int find(const hal_ks_keydb_t * const db, - const hal_key_type_t type, - const uint8_t * const name, const size_t name_len, - int *hint) -{ - assert(db != NULL && name != NULL && acceptable_key_type(type)); - - if (hint != NULL && *hint >= 0 && *hint < sizeof(db->keys)/sizeof(*db->keys) && - db->keys[*hint].in_use && - db->keys[*hint].type == type && - db->keys[*hint].name_len == name_len && memcmp(db->keys[*hint].name, name, name_len) == 0) - return 1; - - for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) { - if (!db->keys[i].in_use || - (hint != NULL && i == *hint) || - db->keys[i].type != type || - db->keys[i].name_len != name_len || memcmp(db->keys[i].name, name, name_len) != 0) - continue; - if (hint != NULL) - *hint = i; - return 1; - } - - return 0; -} - -hal_error_t hal_ks_exists(const hal_key_type_t type, - const uint8_t * const name, const size_t name_len, - int *hint) -{ - if (name == NULL || !acceptable_key_type(type)) - return HAL_ERROR_BAD_ARGUMENTS; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - if (find(db, type, name, name_len, hint)) - return HAL_OK; - else - return HAL_ERROR_KEY_NOT_FOUND; -} - -hal_error_t hal_ks_fetch(const hal_key_type_t type, - const uint8_t * const name, const size_t name_len, - hal_curve_name_t *curve, - hal_key_flags_t *flags, - uint8_t *der, size_t *der_len, const size_t der_max, - int *hint) -{ - if (name == NULL || !acceptable_key_type(type)) - return HAL_ERROR_BAD_ARGUMENTS; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - int hint_ = -1; - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - if (hint == NULL) - hint = &hint_; - - if (!find(db, type, name, name_len, hint)) - return HAL_ERROR_KEY_NOT_FOUND; - - const hal_ks_key_t * const k = &db->keys[*hint]; - - if (curve != NULL) - *curve = k->curve; - - if (flags != NULL) - *flags = k->flags; - - if (der == NULL && der_len != NULL) - *der_len = k->der_len; - - if (der != NULL) { - -#if USE_KEK - - 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_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) - err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len); - - memset(kek, 0, sizeof(kek)); - - if (err != HAL_OK) - return err; - -#else /* USE_KEK */ - - if (k->der_len > der_max) - return HAL_ERROR_RESULT_TOO_LONG; - - if (der_len != NULL) - *der_len = k->der_len; - - memcpy(der, k->der, k->der_len); - -#endif /* USE_KEK */ - } - - return HAL_OK; -} - -hal_error_t hal_ks_delete(const hal_key_type_t type, - const uint8_t * const name, const size_t name_len, - int *hint) -{ - if (name == NULL || !acceptable_key_type(type)) - return HAL_ERROR_BAD_ARGUMENTS; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - int hint_ = -1; - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - if (hint == NULL) - hint = &hint_; - - if (!find(db, type, name, name_len, hint)) - return HAL_ERROR_KEY_NOT_FOUND; - - return hal_ks_del_keydb(*hint); -} - -hal_error_t hal_ks_rename(const hal_key_type_t type, - const uint8_t * const old_name, const size_t old_name_len, - const uint8_t * const new_name, const size_t new_name_len, - int *hint) -{ - if (old_name == NULL || new_name == NULL || !acceptable_key_type(type)) - return HAL_ERROR_BAD_ARGUMENTS; - - if (new_name_len > HAL_RPC_PKEY_NAME_MAX) - return HAL_ERROR_KEY_NAME_TOO_LONG; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - int hint_ = -1; - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - if (find(db, type, new_name, new_name_len, NULL)) - return HAL_ERROR_KEY_NAME_IN_USE; - - if (hint == NULL) - hint = &hint_; - - if (!find(db, type, old_name, old_name_len, hint)) - return HAL_ERROR_KEY_NOT_FOUND; - - hal_ks_key_t k = db->keys[*hint]; - - assert(new_name_len <= sizeof(k.name)); - memcpy(k.name, new_name, new_name_len); - k.name_len = new_name_len; - - return hal_ks_set_keydb(&k, *hint, 1); -} - -hal_error_t hal_ks_list(hal_pkey_info_t *result, - unsigned *result_len, - const unsigned result_max) -{ - if (result == NULL || result_len == NULL) - return HAL_ERROR_BAD_ARGUMENTS; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - *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_len = db->keys[i].name_len; - memcpy(result[*result_len].name, db->keys[i].name, db->keys[i].name_len); - ++ *result_len; - } - - return HAL_OK; -} - -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; - - const hal_ks_keydb_t * const db = hal_ks_get_keydb(); - - if (db == NULL) - return HAL_ERROR_KEYSTORE_ACCESS; - - 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; - } - -#warning Need better "Have we been initialized yet?" test - /* - * 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. - * - * We probably need some more general "have we been initialized?" - * state somewhere, and might want to refuse to do things like - * storing keys until we've been initialized and the appropriate - * PINs have been set. - * - * Just to make things more fun, some drivers return all zeros for - * "this has never been set", some return all ones to indicate the - * same thing. REALLY need a flag somewhere. - */ - - 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 HAL_OK; -} - -/* - * Local variables: - * indent-tabs-mode: nil - * End: - */ diff --git a/ks_flash.c b/ks_flash.c index fdc800f..ac10602 100644 --- a/ks_flash.c +++ b/ks_flash.c @@ -40,7 +40,6 @@ #define HAL_OK CMIS_HAL_OK #include "stm-keystore.h" -#include "masterkey.h" #undef HAL_OK #include @@ -52,17 +51,125 @@ #define KEK_LENGTH (bitsToBytes(256)) +/* + * Revised flash keystore database. Work in progress. + * + * General consideration: + * + * - bits can only be cleared, not set, unless one wants to erase the + * (sub)sector. This has some odd knock on effects in terms of + * things like values of enumerated constants used here. + * + * - At the moment, all of hte the low-level flash code deals with + * sectors, not sub-sectors, so for the moment we only use the first + * sub-sector of each sector. Fixing this should not involve any + * major changes to the code, just redefinition of some constants + * here once we figure out what effect this will have on the rest of + * the code that shares the same low-level flash code. In either + * case we're dealing with "blocks", where a block is a sector now + * and will be a sub-sector later. + * + * - This code assumes we're using ks_index.c, including its notion + * of a free list and its attempt at light-weight wear leveling. + */ + +/* + * Known block states. + * + * This assumes that an enum is stored as a 32-bit unsigned integer, + * which may be a bad assumption. Might be better to use uint32_t (or + * whatever) and inline functions for safe casting. + * + * Might want an additional state 0xDEADDEAD to mark blocks which + * are known to be unusable, but the current hardware is NOR flash + * so that may not be as important as it would be with NAND flash. + */ + +typedef enum { + FLASH_ERASED = 0xFFFFFFFF, /* Pristine erased block (candidate for reuse) */ + FLASH_ZEROED = 0x00000000, /* Zeroed block (recently used) */ + FLASH_KEYBLK = 0x55555555, /* Block contains key material */ + FLASH_PINBLK = 0xAAAAAAAA, /* Block contains PINs */ +} flash_block_type_t; + +typedef struct { + + /* + * What kind of flash block this is + */ + flash_block_type_t block_type; + + /* + * CRC-32 of block contents. crc_mask width should be at least as + * many bits as there are slots in the crc array. Once all of the + * slots have been used, we have to move to a new block. Using 32 + * slots initially, adjust that up or down once we have some clue + * how well this design works and how many slots we really want. + */ + uint32_t crc_mask; + hal_crc32_t crc[32]; + + /* + * Payload for key and PIN blocks. Anonymous structures and unions + * until and unless we have a reason to name them. + * + * Storing the KEK in a PIN block is a dangerous kludge and should + * be removed as soon as we have a battery backup for the MKM. + * + * We probably want some kind of TLV format for optional attributes + * in key objects, and might want to put the DER key itself there to + * save space. + */ + + union { + + struct { + hal_uuid_t name; + hal_key_type_t type; + hal_curve_name_t curve; + hal_key_flags_t flags; + size_t der_len; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + } key; + + struct { + struct { + hal_user_t user; + hal_ks_pin_t pin; + } pins[40]; + uint8_t kek[KEK_LENGTH]; /* Kludge */ + } pin; + + } payload; + +} flash_block_t; + + +#warning Old keystore code below here /* * 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. + * + * hal_ks_key_t is ordered such that all metadata appears before the + * big buffers, in order for all metadata to be loaded with a single + * page read. */ typedef struct { - hal_ks_t ks; /* Must be first (C "subclassing") */ + hal_key_type_t type; + hal_curve_name_t curve; + hal_key_flags_t flags; + uint8_t in_use; + size_t der_len; + hal_uuid_t name; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; +} hal_ks_key_t; +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; @@ -77,8 +184,8 @@ typedef struct { static db_t db; -#define FLASH_SECTOR_1_OFFSET (0 * KEYSTORE_SECTOR_SIZE) -#define FLASH_SECTOR_2_OFFSET (1 * KEYSTORE_SECTOR_SIZE) +#define FLASH_SECTOR_1_OFFSET (0 * KEYSTORE_SECTOR_SIZE) +#define FLASH_SECTOR_2_OFFSET (1 * KEYSTORE_SECTOR_SIZE) static inline uint32_t _active_sector_offset() { @@ -329,7 +436,7 @@ static hal_error_t ks_fetch(hal_ks_t *ks, *der_len = der_max; - if ((err = hal_get_kek(kek, &kek_len, sizeof(kek))) == LIBHAL_OK) + if ((err = hal_mkm_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)); @@ -402,7 +509,7 @@ static hal_error_t ks_store(hal_ks_t *ks, hal_error_t err; - if ((err = hal_get_kek(kek, &kek_len, sizeof(kek))) == LIBHAL_OK) + if ((err = hal_mkm_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); memset(kek, 0, sizeof(kek)); @@ -526,9 +633,9 @@ hal_error_t hal_get_pin(const hal_user_t user, 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; + case HAL_USER_SO: *pin = &db.so_pin; break; + case HAL_USER_NORMAL: *pin = &db.user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; } /* @@ -566,9 +673,9 @@ hal_error_t hal_set_pin(const hal_user_t user, 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; - default: return HAL_ERROR_BAD_ARGUMENTS; + case HAL_USER_SO: p = &db.so_pin; break; + case HAL_USER_NORMAL: p = &db.user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; } memcpy(p, pin, sizeof(*p)); @@ -587,39 +694,12 @@ hal_error_t hal_set_pin(const hal_user_t user, return _write_db_to_flash(active_sector_offset); } - -hal_error_t hal_get_kek(uint8_t *kek, - size_t *kek_len, - const size_t kek_max) -{ - if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) - return HAL_ERROR_BAD_ARGUMENTS; - - const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : - (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : - bitsToBytes(256)); - - hal_error_t err = masterkey_volatile_read(kek, len); - - if (err == LIBHAL_OK) { - *kek_len = len; - return LIBHAL_OK; - } - - if (masterkey_flash_read(kek, len) == LIBHAL_OK) { - *kek_len = len; - return LIBHAL_OK; - } - - /* - * 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. - */ - return err; -} - +#warning MKM flash kludge support needed here +/* + * Need functions to handle lower level stuff we want + * hal_mkm_flash_read() and hal_mkm_flash_write() to call, since we're + * stuffing that data into the PIN block. + */ /* * Local variables: diff --git a/ks_mmap.c b/ks_mmap.c index 6d9ac6f..066e93e 100644 --- a/ks_mmap.c +++ b/ks_mmap.c @@ -144,7 +144,7 @@ hal_error_t hal_set_pin(const hal_user_t user, return HAL_OK; } -hal_error_t hal_get_kek(uint8_t *kek, +hal_error_t hal_mkm_get_kek(uint8_t *kek, size_t *kek_len, const size_t kek_max) { diff --git a/ks_volatile.c b/ks_volatile.c index 3c9cba5..02bd4cc 100644 --- a/ks_volatile.c +++ b/ks_volatile.c @@ -192,7 +192,7 @@ static hal_error_t ks_store(hal_ks_t *ks, k.curve = slot->curve; k.flags = slot->flags; - if ((err = hal_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) + if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k.der, &k.der_len); memset(kek, 0, sizeof(kek)); @@ -242,7 +242,7 @@ static hal_error_t ks_fetch(hal_ks_t *ks, *der_len = der_max; - if ((err = hal_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) + if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len); memset(kek, 0, sizeof(kek)); diff --git a/masterkey.c b/masterkey.c deleted file mode 100644 index 3c4f0d3..0000000 --- a/masterkey.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * masterkey.c - * ----------- - * Masterkey set/get functions. - * - * Copyright (c) 2016, 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. - */ - -/* - * Code to load the Master key (Key Encryption Key) from either the volatile MKM - * (by asking the FPGA to provide it, using the mkmif) or from the last sector in - * the keystore flash. - * - * Storing the master key in flash is a pretty Bad Idea, but since the Alpha board - * doesn't have a battery mounted (only pin headers for attaching one), it might - * help in non-production use where one doesn't have tamper protection anyways. - * - * For production use on the Alpha, one option is to have the Master Key on paper - * and enter it into volatile RAM after each power on. - * - * In both volatile memory and flash, the data is stored as a 32 bit status to - * know if the memory is initialized or not, followed by 32 bytes (256 bits) of - * Master Key. - */ - -#define HAL_OK CMIS_HAL_OK -#include "stm-init.h" -#include "stm-keystore.h" -#undef HAL_OK - -#define HAL_OK LIBHAL_OK -#include "hal.h" -#include "masterkey.h" -#undef HAL_OK - -#include - - -static int volatile_init = 0, flash_init = 0; -static hal_core_t *core = NULL; - -#define MKM_VOLATILE_STATUS_ADDRESS 0 -#define MKM_VOLATILE_SCLK_DIV 0x20 -#define MKM_FLASH_STATUS_ADDRESS (KEYSTORE_SECTOR_SIZE * (KEYSTORE_NUM_SECTORS - 1)) -#define KEK_LENGTH (256 / 8) - -/* Match uninitialized flash for the "not set" value. - * Leave some bits at 1 for the "set" value to allow - * for adding more values later, if needed. - */ -#define MKM_STATUS_NOT_SET 0xffffffff -#define MKM_STATUS_SET 0x0000ffff -#define MKM_STATUS_ERASED 0x00000000 - - -hal_error_t masterkey_volatile_init() -{ - hal_error_t err; - uint32_t status; - - if (! volatile_init) { - if ((core = hal_core_find(MKMIF_NAME, NULL)) == NULL) { - return HAL_ERROR_CORE_NOT_FOUND; - } - - if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != LIBHAL_OK || - (err = hal_mkmif_init(core)) != LIBHAL_OK || - (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) - return err; - - if (status != MKM_STATUS_SET && status != MKM_STATUS_NOT_SET) { - /* XXX Something is a bit fishy here. If we just write the status word, it reads back wrong sometimes, - * while if we write the full buf too it is consistently right afterwards. - */ - uint8_t buf[KEK_LENGTH] = {0}; - if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) - return err; - } - - volatile_init = 1; - } - return LIBHAL_OK; -} - -hal_error_t masterkey_volatile_read(uint8_t *buf, size_t len) -{ - hal_error_t err; - uint32_t status; - - if (len && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - - if ((err = masterkey_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) - return err; - - if (buf != NULL && len) { - /* Don't return the random bytes in the RAM memory in case it isn't initialized. - * Or maybe we should fill the buffer with proper random data in that case... hmm. - */ - if (status == MKM_STATUS_SET) { - if ((err = hal_mkmif_read(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK) { - return err; - } - } else { - memset(buf, 0x0, len); - } - } - - if (status == MKM_STATUS_SET) return LIBHAL_OK; - if (status == MKM_STATUS_NOT_SET) return HAL_ERROR_MASTERKEY_NOT_SET; - - return HAL_ERROR_MASTERKEY_FAIL; -} - -hal_error_t masterkey_volatile_write(uint8_t *buf, size_t len) -{ - hal_error_t err; - - if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - if (! buf) return HAL_ERROR_MASTERKEY_FAIL; - - if ((err = masterkey_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != LIBHAL_OK) - return err; - - return LIBHAL_OK; -} - -hal_error_t masterkey_volatile_erase(size_t len) -{ - uint8_t buf[KEK_LENGTH] = {0}; - hal_error_t err; - - if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - - if ((err = masterkey_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) - return err; - - return LIBHAL_OK; -} - -hal_error_t masterkey_flash_init() -{ - if (! flash_init) { - if (! keystore_check_id()) return HAL_ERROR_IO_UNEXPECTED; - flash_init = 1; - } - return LIBHAL_OK; -} - -hal_error_t masterkey_flash_read(uint8_t *buf, size_t len) -{ - uint8_t page[KEYSTORE_PAGE_SIZE]; - uint32_t *status = (uint32_t *) page; - hal_error_t err; - - if (len && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - - if ((err = masterkey_flash_init()) != LIBHAL_OK) return err; - - if (! keystore_read_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page))) { - memset(page, 0, sizeof(page)); - return HAL_ERROR_MASTERKEY_FAIL; - } - - if (buf != NULL && len) { - /* Don't return what's in the flash memory in case it isn't initialized. - * Or maybe we should fill the buffer with proper random data in that case... hmm. - */ - if (*status == MKM_STATUS_SET) { - memcpy(buf, page + 4, len); - } else { - memset(buf, 0x0, len); - } - } - - memset(page + 4, 0, sizeof(page) - 4); - - if (*status == MKM_STATUS_SET) return LIBHAL_OK; - if (*status == MKM_STATUS_ERASED || *status == MKM_STATUS_NOT_SET) return HAL_ERROR_MASTERKEY_NOT_SET; - - return HAL_ERROR_MASTERKEY_FAIL; -} - -hal_error_t masterkey_flash_write(uint8_t *buf, size_t len) -{ - uint8_t page[KEYSTORE_PAGE_SIZE] = {0xff}; - uint32_t *status = (uint32_t *) page; - int res; - - if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - if (buf == NULL) return HAL_ERROR_MASTERKEY_FAIL; - - if (masterkey_flash_init() != LIBHAL_OK) return HAL_ERROR_MASTERKEY_FAIL; - - *status = MKM_STATUS_SET; - memcpy(page + 4, buf, len); - - res = keystore_write_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page)); - memset(page, 0, sizeof(page)); - if (res != 1) { - return HAL_ERROR_MASTERKEY_FAIL; - } - - return LIBHAL_OK; -} - -hal_error_t masterkey_flash_erase(size_t len) -{ - if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - - if (keystore_erase_sectors(MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE, - MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE) != 1) { - return HAL_ERROR_MASTERKEY_FAIL; - } - - return LIBHAL_OK; -} diff --git a/masterkey.h b/masterkey.h deleted file mode 100644 index 1d5e7a5..0000000 --- a/masterkey.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * masterkey.h - * ----------- - * Code to handle the Master Key that wraps all the keys in the keystore. - * - * Copyright (c) 2016, 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. - */ - -#ifndef __STM32_HSM_MASTERKEY_H -#define __STM32_HSM_MASTERKEY_H - -extern hal_error_t masterkey_volatile_read(uint8_t *buf, size_t len); -extern hal_error_t masterkey_volatile_write(uint8_t *buf, size_t len); -extern hal_error_t masterkey_volatile_erase(size_t len); - -extern hal_error_t masterkey_flash_read(uint8_t *buf, size_t len); -extern hal_error_t masterkey_flash_write(uint8_t *buf, size_t len); -extern hal_error_t masterkey_flash_erase(size_t len); - -#endif /* __STM32_HSM_MASTERKEY_H */ diff --git a/mkm.c b/mkm.c new file mode 100644 index 0000000..b8dc3c5 --- /dev/null +++ b/mkm.c @@ -0,0 +1,320 @@ +/* + * mkm.c + * ----- + * Master Key Memory functions. + * + * Copyright (c) 2016, 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. + */ + +/* + * Code to load the Master key (Key Encryption Key) from either the volatile MKM + * (by asking the FPGA to provide it, using the mkmif) or from the last sector in + * the keystore flash. + * + * Storing the master key in flash is a pretty Bad Idea, but since the Alpha board + * doesn't have a battery mounted (only pin headers for attaching one), it might + * help in non-production use where one doesn't have tamper protection anyways. + * + * For production use on the Alpha, one option is to have the Master Key on paper + * and enter it into volatile RAM after each power on. + * + * In both volatile memory and flash, the data is stored as a 32 bit status to + * know if the memory is initialized or not, followed by 32 bytes (256 bits) of + * Master Key. + */ + +#define HAL_OK CMIS_HAL_OK +#include "stm-init.h" +#include "stm-keystore.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +#include + + +static int volatile_init = 0, flash_init = 0; +static hal_core_t *core = NULL; + +#define MKM_VOLATILE_STATUS_ADDRESS 0 +#define MKM_VOLATILE_SCLK_DIV 0x20 +#define MKM_FLASH_STATUS_ADDRESS (KEYSTORE_SECTOR_SIZE * (KEYSTORE_NUM_SECTORS - 1)) +#define KEK_LENGTH (256 / 8) + +/* + * Match uninitialized flash for the "not set" value. + * Leave some bits at 1 for the "set" value to allow + * for adding more values later, if needed. + */ +#define MKM_STATUS_NOT_SET 0xffffffff +#define MKM_STATUS_SET 0x0000ffff +#define MKM_STATUS_ERASED 0x00000000 + + +static hal_error_t hal_mkm_volatile_init(void) +{ + if (volatile_init) + return LIBHAL_OK; + + hal_error_t err; + uint32_t status; + + if ((core = hal_core_find(MKMIF_NAME, NULL)) == NULL) + return HAL_ERROR_CORE_NOT_FOUND; + + if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != LIBHAL_OK || + (err = hal_mkmif_init(core)) != LIBHAL_OK || + (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) + return err; + + if (status != MKM_STATUS_SET && status != MKM_STATUS_NOT_SET) { + /* + * XXX Something is a bit fishy here. If we just write the status word, it reads back wrong sometimes, + * while if we write the full buf too it is consistently right afterwards. + */ + uint8_t buf[KEK_LENGTH] = {0}; + if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || + (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) + return err; + } + + volatile_init = 1; + return LIBHAL_OK; +} + +hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len) +{ + hal_error_t err; + uint32_t status; + + if (len && len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || + (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) + return err; + + if (buf != NULL && len) { + /* + * Don't return the random bytes in the RAM memory in case it isn't initialized. + * Or maybe we should fill the buffer with proper random data in that case... hmm. + */ + if (status != MKM_STATUS_SET) + memset(buf, 0x0, len); + else if ((err = hal_mkmif_read(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK) + return err; + } + + if (status == MKM_STATUS_SET) + return LIBHAL_OK; + + if (status == MKM_STATUS_NOT_SET) + return HAL_ERROR_MASTERKEY_NOT_SET; + + return HAL_ERROR_MASTERKEY_FAIL; +} + +hal_error_t hal_mkm_volatile_write(const uint8_t * const buf, const size_t len) +{ + hal_error_t err; + + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if (buf == NULL) + return HAL_ERROR_MASTERKEY_FAIL; + + if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || + (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK || + (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != LIBHAL_OK) + return err; + + return LIBHAL_OK; +} + +hal_error_t hal_mkm_volatile_erase(const size_t len) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || + (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || + (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) + return err; + + return LIBHAL_OK; +} + +#if HAL_MKM_FLASH_BACKUP_KLUDGE + +static hal_error_t hal_mkm_flash_init(void) +{ + if (flash_init) + return LIBHAL_OK; + + if (!keystore_check_id()) + return HAL_ERROR_IO_UNEXPECTED; + + flash_init = 1; + return LIBHAL_OK; +} + +hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len) +{ + uint8_t page[KEYSTORE_PAGE_SIZE]; + uint32_t *status = (uint32_t *) page; + hal_error_t err; + + if (len && len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if ((err = hal_mkm_flash_init()) != LIBHAL_OK) + return err; + + if (!keystore_read_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page))) { + memset(page, 0, sizeof(page)); + return HAL_ERROR_MASTERKEY_FAIL; + } + + if (buf != NULL && len) { + /* + * Don't return what's in the flash memory in case it isn't initialized. + * Or maybe we should fill the buffer with proper random data in that case... hmm. + */ + if (*status == MKM_STATUS_SET) + memcpy(buf, page + 4, len); + else + memset(buf, 0x0, len); + } + + memset(page + 4, 0, sizeof(page) - 4); + + if (*status == MKM_STATUS_SET) + return LIBHAL_OK; + + if (*status == MKM_STATUS_ERASED || *status == MKM_STATUS_NOT_SET) + return HAL_ERROR_MASTERKEY_NOT_SET; + + return HAL_ERROR_MASTERKEY_FAIL; +} + +hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len) +{ + uint8_t page[KEYSTORE_PAGE_SIZE] = {0xff}; + uint32_t *status = (uint32_t *) page; + int res; + + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if (buf == NULL) + return HAL_ERROR_MASTERKEY_FAIL; + + if (hal_mkm_flash_init() != LIBHAL_OK) + return HAL_ERROR_MASTERKEY_FAIL; + + *status = MKM_STATUS_SET; + memcpy(page + 4, buf, len); + + res = keystore_write_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page)); + memset(page, 0, sizeof(page)); + if (res != 1) + return HAL_ERROR_MASTERKEY_FAIL; + + return LIBHAL_OK; +} + +hal_error_t hal_mkm_flash_erase(const size_t len) +{ + if (len != KEK_LENGTH) + return HAL_ERROR_MASTERKEY_BAD_LENGTH; + + if (keystore_erase_sectors(MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE, + MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE) != 1) + return HAL_ERROR_MASTERKEY_FAIL; + + return LIBHAL_OK; +} + +#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */ + + +hal_error_t hal_mkm_get_kek(uint8_t *kek, + size_t *kek_len, + const size_t kek_max) +{ + if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) + return HAL_ERROR_BAD_ARGUMENTS; + + const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : + (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : + bitsToBytes(256)); + + hal_error_t err = hal_mkm_volatile_read(kek, len); + + if (err == LIBHAL_OK) { + *kek_len = len; + return LIBHAL_OK; + } + +#if HAL_MKM_FLASH_BACKUP_KLUDGE + + if (hal_mkm_flash_read(kek, len) == LIBHAL_OK) { + *kek_len = len; + return LIBHAL_OK; + } + +#endif + + /* + * 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. + */ + return err; +} + +/* + * "Any programmer who fails to comply with the standard naming, formatting, + * or commenting conventions should be shot. If it so happens that it is + * inconvenient to shoot him, then he is to be politely requested to recode + * his program in adherence to the above standard." + * -- Michael Spier, Digital Equipment Corporation + * + * Local variables: + * indent-tabs-mode: nil + * End: + */ -- cgit v1.2.3