[Cryptech-Commits] [sw/libhal] 10/12: Cleanup prior to rewriting ks_flash.c.

git at cryptech.is git at cryptech.is
Fri Sep 16 19:53:18 UTC 2016


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch ksng
in repository sw/libhal.

commit 38c4b787fa7c1f5e7fbf810cdda136621dd743b7
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Tue Sep 13 16:37:39 2016 -0400

    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(-)

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
@@ -294,16 +294,6 @@ static inline hal_crc32_t hal_crc32_finalize(hal_crc32_t crc)
 }
 
 /*
- * 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.
@@ -613,19 +621,6 @@ extern hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi,
                                        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 <string.h>
-#include <assert.h>
-
-#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 <string.h>
@@ -53,16 +52,124 @@
 #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 <string.h>
-
-
-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 <string.h>
+
+
+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:
+ */



More information about the Commits mailing list