aboutsummaryrefslogtreecommitdiff
path: root/ks_volatile.c
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2016-09-01 15:37:07 -0400
committerRob Austein <sra@hactrn.net>2016-09-01 15:37:07 -0400
commitc2b116a5e46ed89bf1426def0c447d2e46cc9474 (patch)
treebf08b8a09de4335b7fe6c269b9d7eed79c70a73c /ks_volatile.c
parentccdb3ab006dd46c125fc0277fa0ce2d3d7660147 (diff)
Revised keystore API, part one. Not usable yet.
Changes to implement a revised keystore API. This code probably won't even compile properly yet, and almost certainly will not run, but most of the expected changes are complete at this point. Main points: * Key names are now UUIDs, and are generated by the HSM, not the client. * Keystore API no longer assumes that key database is resident in memory (original API was written on the assumption that the keystore flash would be mapped into the HSM CPU's address space, but apparently the board and flash drivers don't really support that). A few other changes have probably crept in, but the bulk of this changeset is just following through implications of the above, some of which percolate all the way back to the public RPC API.
Diffstat (limited to 'ks_volatile.c')
-rw-r--r--ks_volatile.c269
1 files changed, 215 insertions, 54 deletions
diff --git a/ks_volatile.c b/ks_volatile.c
index 00f656a..147e6c9 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -7,7 +7,7 @@
* to survive library exit, eg, for storing PKCS #11 session keys.
*
* Authors: Rob Austein
- * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2015-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
@@ -37,106 +37,267 @@
*/
#include <string.h>
+#include <assert.h>
#include "hal.h"
#include "hal_internal.h"
-/*
- * Splitting the different keystore backends out into separate files
- * seemed like a good idea at the time, but the code is getting
- * somewhat repetitive. Might want to re-merge and conditionalize in
- * some other way. Deferred until we sort out ks_flash.c.
- */
+#define KEK_LENGTH (bitsToBytes(256))
+
+#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
+#define HAL_STATIC_PKEY_STATE_BLOCKS 0
+#endif
/*
- * Use a one-element array here so that references can be pointer-based
- * as in the other implementations, to ease re-merge at some later date.
+ * Keystore database itself. For the moment, we stick to the old
+ * model where the entire database is wrapped in a C structure. We
+ * may want to change this, but if so, we'll need a replacement for
+ * the length check. If we do decide to replace it, we may want to
+ * keep the C structure but replace the fixed size array with a C99
+ * "flexible array", ie,
+ *
+ * hal_ks_key_t keys[];
+ *
+ * which is like the old GCC zero-length array hack, and can only
+ * go at the end of the structure.
*/
-static hal_ks_keydb_t db[1];
+typedef struct {
+
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+ hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
+#else
+#warning No keys in keydb
+#endif
+
+} db_t;
/*
- * There's no good place to store the master key (KEK) in this volatile memory implementation.
- * We might be able to add a bit of protection doing things like using locked physical memory,
- * as gpg does, or obfuscating the KEK a bit to make it harder to pull out of a crash dump,
- * but, really, there's not a lot we can do against a determined opponant in this case.
- *
- * For now, we just go through the motions.
+ * "Subclass" (well, what one can do in C) of hal_ks_t. This is
+ * separate from db_t primarily to simplify things like rewriting the
+ * old ks_mmap driver to piggy-back on the ks_volatile driver: we
+ * wouldn't want the hal_ks_t into the mmap()ed file.
*/
-static uint8_t kekbuf[bitsToBytes(256)];
+typedef struct {
+ hal_ks_t ks; /* Must be first */
+ db_t *db; /* Which memory-based keystore database */
+} ks_t;
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
+static db_t volatile_db;
+
+static ks_t volatile_ks = { { hal_ks_volatile_driver }, &volatile_db };
+
+static inline ks_t *ks_to_ksv(hal_ks_t *ks)
{
- return db;
+ return (ks_t *) ks;
}
-hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating)
+static hal_error_t ks_volatile_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
{
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
- return HAL_ERROR_BAD_ARGUMENTS;
+ assert(driver != NULL && ks != NULL);
+ *ks = &volatile_ks.ks;
+ return HAL_OK;
+}
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
+static hal_error_t ks_volatile_close(hal_ks_t *ks)
+{
return HAL_OK;
}
-hal_error_t hal_ks_del_keydb(const int loc)
+static inline int acceptable_key_type(const hal_key_type_t type)
+{
+ switch (type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ case HAL_KEY_TYPE_EC_PRIVATE:
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ case HAL_KEY_TYPE_EC_PUBLIC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static hal_error_t ks_store(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot,
+ const uint8_t * const der, const size_t der_len)
{
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+ if (ks == NULL || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
return HAL_ERROR_BAD_ARGUMENTS;
- memset(&db->keys[loc], 0, sizeof(db->keys[loc]));
+ ks_t *ksv = ks_to_ksv(ks);
+ hal_error_t err;
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ int loc = -1;
+
+ for (int i = 0; i < sizeof(ksv->db->keys)/sizeof(*ksv->db->keys); i++) {
+ if (!ksv->db->keys[i].in_use && loc < 0)
+ loc = i;
+ if (ksv->db->keys[i].in_use &&
+ ksv->db->keys[i].type == slot->type &&
+ hal_uuid_cmp(&ksv->db->keys[i].name, &slot->name) == 0)
+ return HAL_ERROR_KEY_NAME_IN_USE;
+ }
+
+ if (loc < 0)
+ return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
+
+ hal_ks_key_t k;
+ memset(&k, 0, sizeof(k));
+ k.der_len = sizeof(k.der);
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+
+ if ((err = hal_ks_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;
+
+ k.name = slot->name;
+ k.type = slot->type;
+ k.curve = slot->curve;
+ k.flags = slot->flags;
+
+ ksv->db->keys[loc] = k;
+ ksv->db->keys[loc].in_use = 1;
+
return HAL_OK;
}
-hal_error_t hal_ks_set_pin(const hal_user_t user,
- const hal_ks_pin_t * const pin)
+static hal_ks_key_t *find(ks_t *ksv,
+ const hal_key_type_t type,
+ const hal_uuid_t * const name)
{
- if (pin == NULL)
+ assert(ksv != NULL && name != NULL && acceptable_key_type(type));
+
+ for (int i = 0; i < sizeof(ksv->db->keys)/sizeof(*ksv->db->keys); i++)
+ if (ksv->db->keys[i].in_use && ksv->db->keys[i].type == type && hal_uuid_cmp(&ksv->db->keys[i].name, name) == 0)
+ return &ksv->db->keys[i];
+
+ return NULL;
+}
+
+static hal_error_t ks_fetch(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (ks == NULL || slot == NULL || !acceptable_key_type(slot->type))
return HAL_ERROR_BAD_ARGUMENTS;
- hal_ks_pin_t *p = NULL;
+ ks_t *ksv = ks_to_ksv(ks);
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ const hal_ks_key_t * const k = find(ksv, slot->type, &slot->name);
+
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ slot->curve = k->curve;
+ slot->flags = k->flags;
- 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;
+ if (der == NULL && der_len != NULL)
+ *der_len = k->der_len;
+
+ if (der != NULL) {
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len, der_len_;
+ hal_error_t err;
+
+ if (der_len == NULL)
+ der_len = &der_len_;
+
+ *der_len = der_max;
+
+ if ((err = hal_ks_get_kek(kek, &kek_len, sizeof(kek))) == 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;
}
- *p = *pin;
return HAL_OK;
}
-hal_error_t hal_ks_get_kek(uint8_t *kek,
- size_t *kek_len,
- const size_t kek_max)
+static hal_error_t ks_delete(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot)
{
- if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128))
+ if (ks == NULL || slot == NULL || !acceptable_key_type(slot->type))
return HAL_ERROR_BAD_ARGUMENTS;
- hal_error_t err;
+ ks_t *ksv = ks_to_ksv(ks);
- const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) :
- (kek_max < bitsToBytes(256)) ? bitsToBytes(192) :
- bitsToBytes(256));
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
- uint8_t t = 0;
+ hal_ks_key_t *k = find(ksv, slot->type, &slot->name);
- for (int i = 0; i < sizeof(kekbuf); i++)
- t |= kekbuf[i];
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
- if (t == 0 && (err = hal_rpc_get_random(kekbuf, sizeof(kekbuf))) != HAL_OK)
- return err;
+ memset(k, 0, sizeof(*k));
+
+ return HAL_OK;
+}
+
+static hal_error_t ks_list(hal_ks_t *ks,
+ hal_pkey_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max)
+{
+ if (ks == NULL || result == NULL || result_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ ks_t *ksv = ks_to_ksv(ks);
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ *result_len = 0;
+
+ for (int i = 0; i < sizeof(ksv->db->keys)/sizeof(*ksv->db->keys); i++) {
+
+ if (!ksv->db->keys[i].in_use)
+ continue;
+
+ if (*result_len == result_max)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ result[*result_len].type = ksv->db->keys[i].type;
+ result[*result_len].curve = ksv->db->keys[i].curve;
+ result[*result_len].flags = ksv->db->keys[i].flags;
+ result[*result_len].name = ksv->db->keys[i].name;
+ ++ *result_len;
+ }
- memcpy(kek, kekbuf, len);
- *kek_len = len;
return HAL_OK;
}
+const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
+ ks_volatile_open,
+ ks_volatile_close,
+ ks_store,
+ ks_fetch,
+ ks_delete,
+ ks_list
+}};
+
/*
* Local variables:
* indent-tabs-mode: nil