aboutsummaryrefslogtreecommitdiff
path: root/ks_volatile.c
diff options
context:
space:
mode:
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