aboutsummaryrefslogtreecommitdiff
path: root/ks.h
diff options
context:
space:
mode:
Diffstat (limited to 'ks.h')
-rw-r--r--ks.h421
1 files changed, 421 insertions, 0 deletions
diff --git a/ks.h b/ks.h
new file mode 100644
index 0000000..1c09b53
--- /dev/null
+++ b/ks.h
@@ -0,0 +1,421 @@
+/*
+ * ks.h
+ * ----
+ * Keystore, generic parts anyway. This is internal within libhal.
+ *
+ * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KS_H_
+#define _KS_H_
+
+#include "hal.h"
+#include "hal_internal.h"
+
+/*
+ * Size of a keystore "block".
+ *
+ * This must be an integer multiple of the flash subsector size, among
+ * other reasons because that's the minimum erasable unit.
+ */
+
+#ifndef HAL_KS_BLOCK_SIZE
+#define HAL_KS_BLOCK_SIZE (4096)
+#endif
+
+/*
+ * PIN block gets the all-zeros UUID, which will never be returned by
+ * the UUID generation code (by definition -- it's not a version 4 UUID).
+ */
+
+const hal_uuid_t hal_ks_pin_uuid;
+
+/*
+ * Known block states.
+ *
+ * C does not guarantee any particular representation for enums, so
+ * including enums directly in the block header isn't safe. Instead,
+ * we use an access method which casts when reading from the header.
+ * Writing to the header isn't a problem, because C does guarantee
+ * that enum is compatible with *some* integer type, it just doesn't
+ * specify which one.
+ */
+
+typedef enum {
+ HAL_KS_BLOCK_TYPE_ERASED = 0xFF, /* Pristine erased block (candidate for reuse) */
+ HAL_KS_BLOCK_TYPE_ZEROED = 0x00, /* Zeroed block (recently used) */
+ HAL_KS_BLOCK_TYPE_KEY = 0x55, /* Block contains key material */
+ HAL_KS_BLOCK_TYPE_PIN = 0xAA, /* Block contains PINs */
+ HAL_KS_BLOCK_TYPE_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} hal_ks_block_type_t;
+
+/*
+ * Block status.
+ */
+
+typedef enum {
+ HAL_KS_BLOCK_STATUS_LIVE = 0x66, /* This is a live block */
+ HAL_KS_BLOCK_STATUS_TOMBSTONE = 0x44, /* This is a tombstone left behind during an update */
+ HAL_KS_BLOCK_STATUS_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} hal_ks_block_status_t;
+
+/*
+ * Common header for all keystore block types.
+ * A few of these fields are deliberately omitted from the CRC.
+ */
+
+typedef struct {
+ uint8_t block_type;
+ uint8_t block_status;
+ hal_crc32_t crc;
+} hal_ks_block_header_t;
+
+/*
+ * Key block. Tail end of "der" field (after der_len) used for attributes.
+ */
+
+typedef struct {
+ hal_ks_block_header_t header;
+ hal_uuid_t name;
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ size_t der_len;
+ unsigned attributes_len;
+ uint8_t der[]; /* Must be last field -- C99 "flexible array member" */
+} hal_ks_key_block_t;
+
+#define SIZEOF_KS_KEY_BLOCK_DER \
+ (HAL_KS_BLOCK_SIZE - offsetof(hal_ks_key_block_t, der))
+
+/*
+ * PIN block. Also includes space for backing up the KEK when
+ * HAL_MKM_FLASH_BACKUP_KLUDGE is enabled.
+ */
+
+typedef struct {
+ hal_ks_block_header_t header;
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
+ uint32_t kek_set;
+ uint8_t kek[KEK_LENGTH];
+#endif
+} hal_ks_pin_block_t;
+
+#define FLASH_KEK_SET 0x33333333
+
+/*
+ * One keystore block.
+ */
+
+typedef union {
+ uint8_t bytes[HAL_KS_BLOCK_SIZE];
+ hal_ks_block_header_t header;
+ hal_ks_key_block_t key;
+ hal_ks_pin_block_t pin;
+} hal_ks_block_t;
+
+/*
+ * In-memory cache.
+ */
+
+typedef struct {
+ unsigned blockno;
+ unsigned lru;
+ hal_ks_block_t block;
+} hal_ks_cache_block_t;
+
+/*
+ * Keystore object. hal_internal.h typedefs this to hal_ks_t.
+ *
+ * We expect this to be a static variable, but we expect the arrays in
+ * it to be allocated at runtime using hal_allocate_static_memory()
+ * because they can get kind of large.
+ *
+ * Driver-specific stuff is handled by a form of subclassing: the
+ * driver embeds the hal_ks_t structure at the head of whatever else
+ * it needs, and performs (controlled, type-safe) casts as needed.
+ *
+ * Core of this is the keystore index. This is intended to be usable
+ * by both memory-based and flash-based keystores. Some of the
+ * features aren't necessary for memory-based keystores, but should be
+ * harmless, and let us keep the drivers simple.
+ *
+ * General approach is multiple arrays, all but one of which are
+ * indexed by "block" numbers, where a block number might be a slot in
+ * yet another static array, the number of a flash sub-sector, or
+ * whatever is the appropriate unit for holding one keystore record.
+ *
+ * The index array only contains block numbers. This is a small data
+ * structure so that moving data within it is relatively cheap.
+ *
+ * The index array is divided into two portions: the index proper, and
+ * the free queue. The index proper is ordered according to the names
+ * (UUIDs) of the corresponding blocks; the free queue is a FIFO, to
+ * support a simplistic form of wear leveling in flash-based keystores.
+ *
+ * Key names are kept in a separate array, indexed by block number.
+ *
+ * The all-zeros UUID, which (by definition) cannot be a valid key
+ * UUID, is reserved for the (non-key) block used to stash PINs and
+ * other small data which aren't really part of the keystore proper
+ * but are kept with it because the keystore is the flash we have.
+ *
+ * Note that this API deliberately says nothing about how the keys
+ * themselves are stored, that's up to the keystore driver.
+ */
+
+typedef struct hal_ks_driver hal_ks_driver_t;
+
+struct hal_ks {
+ const hal_ks_driver_t *driver;/* Must be first */
+ unsigned size; /* Blocks in keystore */
+ unsigned used; /* How many blocks are in use */
+ uint16_t *index; /* Index/freelist array */
+ hal_uuid_t *names; /* Keyname array */
+ unsigned cache_lru; /* Cache LRU counter */
+ unsigned cache_size; /* Size (how many blocks) in cache */
+ hal_ks_cache_block_t *cache; /* Cache */
+};
+
+/*
+ * Keystore driver.
+ */
+
+struct hal_ks_driver {
+ hal_error_t (*init) (hal_ks_t *ks, const int alloc);
+ hal_error_t (*read) (hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block);
+ hal_error_t (*write) (hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block);
+ hal_error_t (*deprecate) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*zero) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*erase) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*erase_maybe) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*set_owner) (hal_ks_t *ks, const unsigned blockno,
+ const hal_client_handle_t client, const hal_session_handle_t session);
+ hal_error_t (*test_owner) (hal_ks_t *ks, const unsigned blockno,
+ const hal_client_handle_t client, const hal_session_handle_t session);
+ hal_error_t (*copy_owner) (hal_ks_t *ks, const unsigned source, const unsigned target);
+ hal_error_t (*logout) (hal_ks_t *ks, const hal_client_handle_t client);
+};
+
+/*
+ * Wrappers around keystore driver methods.
+ *
+ * hal_ks_init() and hal_ks_logout() are missing here because we
+ * expose them to the rest of libhal.
+ */
+
+static inline hal_error_t hal_ks_block_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->read == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->read(ks, blockno, block);
+}
+
+static inline hal_error_t hal_ks_block_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->write == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->write(ks, blockno, block);
+}
+
+static inline hal_error_t hal_ks_block_deprecate(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->deprecate == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->deprecate(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_zero(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->zero == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->zero(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_erase(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->erase == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->erase(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_erase_maybe(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->erase_maybe == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->erase_maybe(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_set_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->set_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->set_owner(ks, blockno, client, session);
+}
+
+static inline hal_error_t hal_ks_block_test_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->test_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->test_owner(ks, blockno, client, session);
+}
+
+static inline hal_error_t hal_ks_block_copy_owner(hal_ks_t *ks,
+ const unsigned source,
+ const unsigned target)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->copy_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->copy_owner(ks, source, target);
+}
+
+/*
+ * Type safe casts.
+ */
+
+static inline hal_ks_block_type_t hal_ks_block_get_type(const hal_ks_block_t * const block)
+{
+ return block == NULL ? HAL_KS_BLOCK_TYPE_UNKNOWN :
+ (hal_ks_block_type_t) block->header.block_type;
+}
+
+static inline hal_ks_block_status_t hal_ks_block_get_status(const hal_ks_block_t * const block)
+{
+ return block == NULL ? HAL_KS_BLOCK_STATUS_UNKNOWN :
+ (hal_ks_block_status_t) block->header.block_status;
+}
+
+/*
+ * Keystore utilities. Some or all of these may end up static within ks.c.
+ */
+
+extern hal_error_t hal_ks_alloc_common(hal_ks_t *ks,
+ const unsigned ks_blocks,
+ const unsigned cache_blocks,
+ void **extra,
+ const size_t extra_len);
+
+extern hal_error_t hal_ks_init_common(hal_ks_t *ks);
+
+extern hal_crc32_t hal_ks_block_calculate_crc(const hal_ks_block_t * const block);
+
+extern hal_error_t hal_ks_index_heapsort(hal_ks_t *ks);
+
+extern hal_error_t hal_ks_index_find(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_add(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_delete(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_replace(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_fsck(hal_ks_t *ks);
+
+extern const size_t hal_ks_attribute_header_size;
+
+extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ size_t *total_len);
+
+extern hal_error_t hal_ks_attribute_delete(uint8_t *bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type);
+
+extern hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type,
+ const uint8_t * const value,
+ const size_t value_len);
+
+extern hal_ks_block_t *hal_ks_cache_pick_lru(hal_ks_t *ks);
+
+extern hal_ks_block_t *hal_ks_cache_find_block(const hal_ks_t * const ks,
+ const unsigned blockno);
+
+extern void hal_ks_cache_mark_used(hal_ks_t *ks,
+ const hal_ks_block_t * const block,
+ const unsigned blockno);
+
+extern void hal_ks_cache_release(hal_ks_t *ks,
+ const hal_ks_block_t * const block);
+
+extern hal_error_t hal_ks_block_read_cached(hal_ks_t *ks,
+ const unsigned blockno,
+ hal_ks_block_t **block);
+
+extern hal_error_t hal_ks_block_update(hal_ks_t *ks,
+ const unsigned b1,
+ hal_ks_block_t *block,
+ const hal_uuid_t * const uuid,
+ int *hint);
+
+#endif /* _KS_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */