aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--hal.h27
-rw-r--r--hal_internal.h266
-rw-r--r--ks_flash.c653
-rw-r--r--ks_volatile.c269
-rw-r--r--rpc_api.c39
-rw-r--r--rpc_client.c116
-rw-r--r--rpc_pkey.c289
-rw-r--r--rpc_server.c107
-rw-r--r--uuid.c75
10 files changed, 1241 insertions, 603 deletions
diff --git a/Makefile b/Makefile
index 190466b..b9d1558 100644
--- a/Makefile
+++ b/Makefile
@@ -75,6 +75,7 @@ endif
OBJ += errorstrings.o hash.o asn1.o ecdsa.o rsa.o ${KS_OBJ} xdr.o slip.o
OBJ += rpc_api.o rpc_hash.o rpc_misc.o rpc_pkey.o rpc_client.o rpc_server.o
+OBJ += uuid.o
# Object files to build when we're on a platform with direct access
# to our hardware (Verilog) cores.
@@ -113,7 +114,7 @@ endif
# Default at the moment is mmap, since that should work on the Novena
# and we haven't yet written the flash code for the bridge board.
-KS_OBJ = ks.o
+#KS_OBJ = ks.o
ifeq "${KS}" "mmap"
KS_OBJ += ks_mmap.o
diff --git a/hal.h b/hal.h
index 9d5a32b..f6573a4 100644
--- a/hal.h
+++ b/hal.h
@@ -143,6 +143,7 @@
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_NOT_SET, "Master key (Key Encryption Key) not set") \
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_FAIL, "Master key generic failure") \
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_BAD_LENGTH, "Master key of unacceptable length") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KS_DRIVER_NOT_FOUND, "Keystore driver not found") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -675,7 +676,7 @@ extern hal_error_t hal_rpc_hash_finalize(const hal_hash_handle_t hash,
* a session handle and which ones don't...).
*/
-#define HAL_RPC_PKEY_NAME_MAX 128
+typedef struct { uint8_t uuid[16]; } hal_uuid_t;
typedef struct { uint32_t handle; } hal_pkey_handle_t;
@@ -684,14 +685,14 @@ typedef uint32_t hal_key_flags_t;
#define HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE (1 << 0)
#define HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT (1 << 1)
#define HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT (1 << 2)
-#define HAL_KEY_FLAG_PROXIMATE (1 << 3)
+#define HAL_KEY_FLAG_TOKEN (1 << 3)
extern hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags);
@@ -699,13 +700,13 @@ extern hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags);
extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags);
@@ -713,7 +714,7 @@ extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
extern hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags);
@@ -721,9 +722,6 @@ extern hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey);
extern hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey);
-extern hal_error_t hal_rpc_pkey_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len);
-
extern hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *type);
@@ -751,8 +749,7 @@ typedef struct {
hal_key_type_t type;
hal_curve_name_t curve;
hal_key_flags_t flags;
- char name[HAL_RPC_PKEY_NAME_MAX];
- size_t name_len;
+ hal_uuid_t name;
/* ... */
} hal_pkey_info_t;
@@ -762,10 +759,16 @@ extern hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result,
hal_key_flags_t flags);
extern hal_error_t hal_rpc_client_init(void);
+
extern hal_error_t hal_rpc_client_close(void);
+
extern hal_error_t hal_rpc_server_init(void);
+
extern hal_error_t hal_rpc_server_close(void);
-extern hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen);
+
+extern hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen,
+ uint8_t * const obuf, size_t * const olen);
+
extern void hal_rpc_server_main(void);
#endif /* _HAL_H_ */
diff --git a/hal_internal.h b/hal_internal.h
index 5e08c4e..ff7381f 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -36,6 +36,8 @@
#ifndef _HAL_INTERNAL_H_
#define _HAL_INTERNAL_H_
+#include <string.h>
+
#include "hal.h"
#include "verilog_constants.h"
@@ -169,7 +171,7 @@ typedef struct {
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags);
@@ -177,13 +179,13 @@ typedef struct {
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags);
hal_error_t (*generate_rsa)(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags);
@@ -191,7 +193,7 @@ typedef struct {
hal_error_t (*generate_ec)(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags);
@@ -199,9 +201,6 @@ typedef struct {
hal_error_t (*delete)(const hal_pkey_handle_t pkey);
- hal_error_t (*rename)(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len);
-
hal_error_t (*get_key_type)(const hal_pkey_handle_t pkey,
hal_key_type_t *key_type);
@@ -241,7 +240,7 @@ extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote
* See code in rpc_pkey.c for how this flag fits into the pkey handle.
*/
-#define HAL_PKEY_HANDLE_PROXIMATE_FLAG (1 << 31)
+#define HAL_PKEY_HANDLE_TOKEN_FLAG (1 << 31)
/*
* Mostly used by the local_pkey code, but the mixed_pkey code needs
@@ -256,14 +255,27 @@ extern hal_error_t hal_rpc_pkey_pkcs1_construct_digestinfo(const hal_hash_handle
const size_t digest_info_max);
/*
+ * UUID stuff. All UUIDs we use (or are likely to use) are type 4 "random" UUIDs
+ */
+
+static inline int hal_uuid_cmp(const hal_uuid_t * const a, const hal_uuid_t * const b)
+{
+ return memcmp(a, b, sizeof(hal_uuid_t));
+}
+
+extern hal_error_t hal_uuid_gen(hal_uuid_t *uuid);
+
+/*
* Keystore API.
- *
- * The original design for this subsystem used two separate tables,
- * one for RSA keys, one for EC keys, because the RSA keys are so much
- * larger than the EC keys. This led to unnecessarily complex and
- * duplicated code, so for now we treat all keys the same, and waste
- * the unneeded space in the case of EC keys.
- *
+ */
+
+/*
+ * 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:
*
@@ -278,29 +290,26 @@ extern hal_error_t hal_rpc_pkey_pkcs1_construct_digestinfo(const hal_hash_handle
* wrapped form (see hal_aes_keywrap_cyphertext_length()).
*
* We also need to store PINs somewhere, so they go into the keystore
- * data structure even though they're not keys. Like keys, they're
- * stored in a relatively safe form (PBKDF2), so while we would prefer
- * to keep them private, they don't require tamper-protected RAM.
+ * even though they're not keys. Like keys, they're stored in a
+ * relatively safe form (PBKDF2), so while we would prefer to keep
+ * them private, they don't require tamper-protected RAM.
*/
#define HAL_KS_WRAPPED_KEYSIZE ((4655 + 15) & ~7)
-#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
-#define HAL_STATIC_PKEY_STATE_BLOCKS 0
-#endif
-
-/* This struct is ordered such that all metadata appears before the
+/*
+ * 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.
*/
+
typedef struct {
hal_key_type_t type;
hal_curve_name_t curve;
hal_key_flags_t flags;
uint8_t in_use;
- size_t name_len;
size_t der_len;
- uint8_t name[HAL_RPC_PKEY_NAME_MAX];
+ hal_uuid_t name;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
} hal_ks_key_t;
@@ -314,37 +323,6 @@ typedef struct {
uint8_t salt[HAL_PIN_SALT_LENGTH];
} hal_ks_pin_t;
-typedef struct {
-
-#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
- hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
-#else
- #warning No keys in keydb
-#endif
-
- hal_ks_pin_t wheel_pin;
- hal_ks_pin_t so_pin;
- hal_ks_pin_t user_pin;
-
-} hal_ks_keydb_t;
-
-extern hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client,
- const uint32_t iterations);
-
-/*
- * Internal functions within the keystore implementation. Think of
- * these as concrete methods for the keystore API subclassed onto
- * various storage technologies.
- */
-
-extern const hal_ks_keydb_t *hal_ks_get_keydb(void);
-
-extern hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating);
-
-extern hal_error_t hal_ks_del_keydb(const int loc);
-
extern hal_error_t hal_ks_get_kek(uint8_t *kek,
size_t *kek_len,
const size_t kek_max);
@@ -359,38 +337,154 @@ extern hal_error_t hal_ks_get_kek(uint8_t *kek,
* Unclear whether these should also call the ASN.1 encode/decode
* functions. For the moment, the answer is no, but we may need to
* revisit this as the underlying Verilog API evolves.
+ *
+ * hal_pkey_slot_t is defined here too, so that keystore drivers can
+ * piggyback on the pkey database for storage related to keys on which
+ * the user currently has an active pkey handle. Nothing outside the
+ * pkey and keystore code should touch this.
*/
-extern 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);
-
-extern hal_error_t hal_ks_exists(const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
- int *hint);
-
-extern 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);
-
-extern hal_error_t hal_ks_delete(const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
- int *hint);
-
-extern 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);
-
-extern hal_error_t hal_ks_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max);
+typedef struct {
+ hal_client_handle_t client_handle;
+ hal_session_handle_t session_handle;
+ hal_pkey_handle_t pkey_handle;
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ hal_uuid_t name;
+
+ /*
+ * We used to stash a "hint" value here for the keystore driver to
+ * speed things up when we had multiple operations on the same key.
+ * Removed as premature optimization during keystore rewrite, but we
+ * may want to put something like this back once the new API has
+ * stablized. If so, form would probably be a union containing
+ * keystore-driver-specific data, which everything else (including
+ * the pkey code) should treat as opaque: making it really opaque
+ * would complicate memory allocation and isn't worth it for an
+ * internal API.
+ */
+
+ /*
+ * This might be where we'd stash a (hal_core_t *) pointing to a
+ * core which has already been loaded with the key, if we were
+ * trying to be clever about using multiple signing cores. Moot
+ * point (ie, no way we could possibly test such a thing) as long as
+ * the FPGA is too small to hold more than one modexp core and ECDSA
+ * is entirely software, so skip it for now, but the implied
+ * semantics are interesting: a pkey handle starts to resemble an
+ * initialized signing core, and once all the cores are in use, one
+ * can't load another key without closing an existing pkey handle.
+ */
+} hal_pkey_slot_t;
+
+typedef struct hal_ks_driver hal_ks_driver_t;
+
+typedef struct hal_ks hal_ks_t;
+
+struct hal_ks_driver {
+
+ hal_error_t (*open)(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks);
+
+ hal_error_t (*close)(hal_ks_t *ks);
+
+ hal_error_t (*store)(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot,
+ const uint8_t * const der, const size_t der_len);
+
+ hal_error_t (*fetch)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+ hal_error_t (*delete)(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot);
+
+ hal_error_t (*list)(hal_ks_t *ks,
+ hal_pkey_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max);
+};
+
+
+struct hal_ks {
+ const hal_ks_driver_t *driver;
+ /*
+ * Any other common portions of hal_ks_t go here.
+ */
+
+ /*
+ * Driver-specific stuff is handled by a form of subclassing:
+ * driver module embeds this structure at the head of whatever
+ * else it needs, and performs casts as needed.
+ */
+};
+
+extern const hal_ks_driver_t hal_ks_volatile_driver[1];
+
+static inline hal_error_t hal_ks_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ if (driver == NULL || driver->open == NULL || ks == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return driver->open(driver, ks);
+}
+
+static inline hal_error_t hal_ks_close(hal_ks_t *ks)
+{
+ if (ks == NULL || ks->driver == NULL || ks->driver->close == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return ks->driver->close(ks);
+}
+
+static inline hal_error_t hal_ks_store(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (ks == NULL || ks->driver == NULL || ks->driver->store == NULL || slot == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return ks->driver->store(ks, slot, der, der_len);
+}
+
+static inline hal_error_t hal_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 || ks->driver == NULL || ks->driver->fetch == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return ks->driver->fetch(ks, slot, der, der_len, der_max);
+}
+
+static inline hal_error_t hal_ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot)
+{
+ if (ks == NULL || ks->driver == NULL || ks->driver->delete == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return ks->driver->delete(ks, slot);
+}
+
+static inline hal_error_t hal_ks_list(hal_ks_t *ks,
+ hal_pkey_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max)
+{
+ if (ks == NULL || ks->driver == NULL || ks->driver->list == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return ks->driver->list(ks, result, result_len, result_max);
+}
+
+/*
+ * 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_ks_get_pin(const hal_user_t user,
const hal_ks_pin_t **pin);
diff --git a/ks_flash.c b/ks_flash.c
index 9ba342a..c51ece9 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -49,234 +49,511 @@
#define PAGE_SIZE_MASK (KEYSTORE_PAGE_SIZE - 1)
/*
- * 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.
+ * 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.
*/
-static hal_ks_keydb_t db[1];
+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;
+
+#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;
+
+static db_t db;
#define FLASH_SECTOR_1_OFFSET (0 * KEYSTORE_SECTOR_SIZE)
#define FLASH_SECTOR_2_OFFSET (1 * KEYSTORE_SECTOR_SIZE)
-uint32_t _active_sector_offset()
+static inline uint32_t _active_sector_offset()
{
- /* XXX Load status bytes from both sectors and decide which is current. */
- #warning Have not implemented two flash sectors yet
- return FLASH_SECTOR_1_OFFSET;
+ /* XXX Load status bytes from both sectors and decide which is current. */
+#warning Have not implemented two flash sectors yet
+ return FLASH_SECTOR_1_OFFSET;
}
-uint32_t _get_key_offset(uint32_t num)
+static inline uint32_t _get_key_offset(uint32_t num)
{
- /* Reserve first two pages for flash sector state, PINs and future additions.
- * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252).
- */
- uint32_t offset = KEYSTORE_PAGE_SIZE * 2;
- uint32_t key_size = sizeof(*db->keys);
- uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1);
- offset += num * bytes_per_key;
- return offset;
+ /*
+ * Reserve first two pages for flash sector state, PINs and future additions.
+ * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252).
+ */
+ uint32_t offset = KEYSTORE_PAGE_SIZE * 2;
+ uint32_t key_size = sizeof(*db.keys);
+ uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1);
+ offset += num * bytes_per_key;
+ return offset;
}
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
+static hal_error_t ks_init(void)
{
- uint32_t offset, i, idx = 0, active_sector_offset;
- hal_ks_key_t *key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
-
- memset(db, 0, sizeof(*db));
-
- if (keystore_check_id() != 1) return NULL;
-
- active_sector_offset = _active_sector_offset();
-
- /* The PINs are in the second page of the sector. */
- offset = active_sector_offset + KEYSTORE_PAGE_SIZE;
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
- offset = 0;
- memcpy(&db->wheel_pin, page_buf + offset, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(&db->so_pin, page_buf + offset, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(&db->user_pin, page_buf + offset, sizeof(db->user_pin));
-
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- idx++;
- continue;
- }
-
- offset += active_sector_offset;
-
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
-
- key = (hal_ks_key_t *) page_buf;
- if (key->in_use == 0xff) {
- /* unprogrammed data */
- idx++;
- continue;
- }
-
- if (key->in_use == 1) {
- uint8_t *dst = (uint8_t *) &db->keys[idx];
- uint32_t to_read = sizeof(*db->keys);
-
- /* We already have the first page in page_buf. Put it into place. */
- memcpy(dst, page_buf, sizeof(page_buf));
- to_read -= sizeof(page_buf);
- dst += sizeof(page_buf);
-
- /* Read as many more full pages as possible */
- if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1) return NULL;
- dst += to_read & ~PAGE_SIZE_MASK;
- to_read &= PAGE_SIZE_MASK;
-
- if (to_read) {
- /* Partial last page. We can only read full pages so load it into page_buf. */
- if (keystore_read_data(offset + sizeof(*db->keys) - to_read, page_buf, sizeof(page_buf)) != 1) return NULL;
- memcpy(dst, page_buf, to_read);
- }
- }
- idx++;
+ if (db.ks.driver == hal_ks_flash_driver)
+ return LIBHAL_OK;
+
+ if (db.ks.driver != NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t idx = 0; /* Current index into db.keys[] */
+
+ memset(db, 0, sizeof(*db));
+
+ if (keystore_check_id() != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ uint32_t active_sector_offset = _active_sector_offset();
+
+ /*
+ * The PINs are in the second page of the sector.
+ * Caching all of these these makes some sense in any case.
+ */
+
+ uint32_t offset = active_sector_offset + KEYSTORE_PAGE_SIZE;
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ offset = 0;
+ memcpy(&db.wheel_pin, page_buf + offset, sizeof(db.wheel_pin));
+
+ offset += sizeof(db.wheel_pin);
+ memcpy(&db.so_pin, page_buf + offset, sizeof(db.so_pin));
+
+ offset += sizeof(db.so_pin);
+ memcpy(&db.user_pin, page_buf + offset, sizeof(db.user_pin));
+
+ /*
+ * Now read out all the keys. This is a temporary hack, in the long
+ * run we want to pull these as they're needed, although depending
+ * on how we organize the flash we might still need an initial scan
+ * on startup to build some kind of in-memory index.
+ */
+
+ for (int i = 0; i < sizeof(db.keys) / sizeof(*db.keys); i++) {
+
+ if ((offset = _get_key_offset(i)) > KEYSTORE_SECTOR_SIZE) {
+ idx++;
+ continue;
}
- return db;
-}
+ offset += active_sector_offset;
-hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len)
-{
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t to_write = len;
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
- if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
+ const hal_ks_key_t *key = (const hal_ks_key_t *) page_buf;
+
+ if (key->in_use == 0xff) {
+ /* unprogrammed data */
+ idx++;
+ continue;
}
- to_write &= PAGE_SIZE_MASK;
- if (to_write) {
- /* Use page_buf to write the remaining bytes, since we must write a full page each time. */
- memset(page_buf, 0xff, sizeof(page_buf));
- memcpy(page_buf, data + len - to_write, to_write);
- if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
+
+ if (key->in_use == 1) {
+ uint8_t *dst = (uint8_t *) &db.keys[idx];
+ uint32_t to_read = sizeof(*db.keys);
+
+ /* We already have the first page in page_buf. Put it into place. */
+ memcpy(dst, page_buf, sizeof(page_buf));
+ to_read -= sizeof(page_buf);
+ dst += sizeof(page_buf);
+
+ /* Read as many more full pages as possible */
+ if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ dst += to_read & ~PAGE_SIZE_MASK;
+ to_read &= PAGE_SIZE_MASK;
+
+ if (to_read) {
+ /* Partial last page. We can only read full pages so load it into page_buf. */
+ if (keystore_read_data(offset + sizeof(*db.keys) - to_read, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ memcpy(dst, page_buf, to_read);
+ }
}
+ idx++;
+ }
- return LIBHAL_OK;
+ db.ks.driver = hal_ks_flash_driver;
+
+ return LIBHAL_OK;
+}
+
+static hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len)
+{
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t to_write = len;
+
+ if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ to_write &= PAGE_SIZE_MASK;
+ if (to_write) {
+ /*
+ * Use page_buf to write the remaining bytes, since we must write a full page each time.
+ */
+ memset(page_buf, 0xff, sizeof(page_buf));
+ memcpy(page_buf, data + len - to_write, to_write);
+ if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ }
+
+ return LIBLIBHAL_OK;
}
/*
* Write the full DB to flash, PINs and all.
*/
-hal_error_t _write_db_to_flash(const uint32_t sector_offset)
+
+static hal_error_t _write_db_to_flash(const uint32_t sector_offset)
{
- hal_error_t status;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t i, offset;
+ hal_error_t status;
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t i, offset;
- if (sizeof(db->wheel_pin) + sizeof(db->so_pin) + sizeof(db->user_pin) > sizeof(page_buf)) {
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ if (sizeof(db.wheel_pin) + sizeof(db.so_pin) + sizeof(db.user_pin) > sizeof(page_buf))
+ return HAL_ERROR_BAD_ARGUMENTS;
- /* Put the three PINs into page_buf */
- offset = 0;
- memcpy(page_buf + offset, &db->wheel_pin, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(page_buf + offset, &db->so_pin, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(page_buf + offset, &db->user_pin, sizeof(db->user_pin));
-
- /* Write PINs into the second of the two reserved pages at the start of the sector. */
- offset = sector_offset + KEYSTORE_PAGE_SIZE;
- if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK) {
- return status;
- }
+ /* Put the three PINs into page_buf */
+ offset = 0;
+ memcpy(page_buf + offset, &db.wheel_pin, sizeof(db.wheel_pin));
+ offset += sizeof(db.wheel_pin);
+ memcpy(page_buf + offset, &db.so_pin, sizeof(db.so_pin));
+ offset += sizeof(db.so_pin);
+ memcpy(page_buf + offset, &db.user_pin, sizeof(db.user_pin));
+
+ /* Write PINs into the second of the two reserved pages at the start of the sector. */
+ offset = sector_offset + KEYSTORE_PAGE_SIZE;
+ if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK)
+ return status;
+
+ for (i = 0; i < sizeof(db.keys) / sizeof(*db.keys); i++) {
+ offset = _get_key_offset(i);
+ if (offset > KEYSTORE_SECTOR_SIZE)
+ return HAL_ERROR_BAD_ARGUMENTS;
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ offset += sector_offset;
- offset += sector_offset;
+ if ((status =_write_data_to_flash(offset, (uint8_t *) &db.keys[i], sizeof(*db.keys))) != LIBHAL_OK)
+ return status;
+ }
- if ((status =_write_data_to_flash(offset, (uint8_t *) &db->keys[i], sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
- }
- }
+ return LIBHAL_OK;
+}
- return LIBHAL_OK;
+static hal_error_t ks_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ hal_error_t err;
+
+ if (driver != hal_ks_flash_driver || ks == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if ((err = ks_init()) != LIBHAL_OK)
+ return err;
+
+ *ks = &db.ks;
+ return LIBHAL_OK;
}
-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_close(hal_ks_t *ks)
{
- hal_error_t status;
- uint32_t offset, active_sector_offset;
- hal_ks_key_t *tmp_key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ if (ks != NULL && ks != &db.ks)
+ return HAL_ERROR_BAD_ARGUMENTS;
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
- return HAL_ERROR_BAD_ARGUMENTS;
+ return LIBHAL_OK;
+}
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) return HAL_ERROR_BAD_ARGUMENTS;
+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;
+ }
+}
- active_sector_offset = _active_sector_offset();
+static inline hal_ks_key_t *find(const hal_key_type_t type,
+ const hal_uuid_t * const name)
+{
+ assert(name != NULL && acceptable_key_type(type));
- offset += active_sector_offset;
+ for (int i = 0; i < sizeof(db.keys)/sizeof(*db.keys); i++)
+ if (db.keys[i].in_use && db.keys[i].type == type && hal_uuid_cmp(&db.keys[i].name, name) == 0)
+ return &db.keys[i];
- if (keystore_check_id() != 1) return HAL_ERROR_KEYSTORE_ACCESS;
+ return NULL;
+}
- /* Check if there is a key occupying this slot in the flash already.
- * Don't trust the in-memory representation since it would mean data
- * corruption in flash if it had been altered.
- */
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- tmp_key = (hal_ks_key_t *) page_buf;
-
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
-
- if (tmp_key->in_use == 0xff) {
- /* Key slot was unused in flash. Write the new key there. */
- if ((status = _write_data_to_flash(offset, (uint8_t *) key, sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
- }
- } else {
- /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
- if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- if ((status =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK) {
- return status;
- }
- }
+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 != &db.ks || slot == NULL || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
- return LIBHAL_OK;
+ const hal_ks_key_t * const k = find(slot->type, &slot->name);
+
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ slot->curve = k->curve;
+ slot->flags = k->flags;
+
+ 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))) == LIBHAL_OK)
+ err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len);
+
+ memset(kek, 0, sizeof(kek));
+
+ if (err != LIBHAL_OK)
+ return err;
+ }
+
+ return LIBHAL_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 != &db.ks || result == NULL || result_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *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 = db.keys[i].name;
+ ++ *result_len;
+ }
+
+ return LIBHAL_OK;
}
-hal_error_t hal_ks_del_keydb(const int loc)
+/*
+ * This function in particular really needs to be rewritten to take
+ * advantage of the new keystore API.
+ */
+
+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)
{
- uint32_t offset;
+ if (ks != &db.ks || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (find(slot->type, &slot->name) != NULL)
+ return HAL_ERROR_KEY_NAME_IN_USE;
+
+ int loc = -1;
+
+ for (int i = 0; i < sizeof(db.keys)/sizeof(*db.keys); i++)
+ if (!db.keys[i].in_use && loc < 0)
+ loc = i;
+
+ 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;
+
+ hal_error_t err;
+
+ if ((err = hal_ks_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);
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+ memset(kek, 0, sizeof(kek));
+
+ if (err != LIBHAL_OK)
+ return err;
+
+ k.name = slot->name;
+ k.type = slot->type;
+ k.curve = slot->curve;
+ k.flags = slot->flags;
+
+ uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+
+ uint32_t offset = _get_key_offset(loc);
+
+ if (offset > KEYSTORE_SECTOR_SIZE)
return HAL_ERROR_BAD_ARGUMENTS;
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
+ uint32_t active_sector_offset = _active_sector_offset();
+
+ offset += active_sector_offset;
+
+ if (keystore_check_id() != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ /*
+ * Check if there is a key occupying this slot in the flash already.
+ * This includes the case where we've zeroed a former key without
+ * erasing the flash sector, so we have to check the flash itself,
+ * we can't just look at the in-memory representation.
+ */
+
+ if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ const int unused_since_erasure = ((hal_ks_key_t *) page_buf)->in_use == 0xFF;
+
+ db.keys[loc] = k;
+ db.keys[loc].in_use = 1;
+
+ if (unused_since_erasure) {
+
+ /*
+ * Key slot was unused in flash, so we can just write the new key there.
+ */
+
+ if ((err = _write_data_to_flash(offset, (uint8_t *) &k, sizeof(k))) != LIBHAL_OK)
+ return err;
+
+ } else {
+
+ /*
+ * Key slot in flash has been used. We should be more clever than
+ * this, but for now we just rewrite the whole freaking keystore.
+ */
+
+ /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
+
+ if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
+ active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK)
+ return err;
}
+ return LIBHAL_OK;
+}
+
+static hal_error_t ks_delete(hal_ks_t *ks,
+ const hal_pkey_slot_t * const slot)
+{
+ if (ks != &db.ks || slot == NULL || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_ks_key_t *k = find(slot->type, &slot->name);
+
+ if (k == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ const int loc = k - db.keys
+ uint32_t offset = _get_key_offset(loc);
+
+ if (loc < 0 || offset > KEYSTORE_SECTOR_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
offset += _active_sector_offset();
- memset(&db->keys[loc], 0, sizeof(*db->keys));
+ memset(k, 0, sizeof(*k));
+
+ /*
+ * Setting bits to 0 never requires erasing flash. Just write it.
+ */
- /* Setting bits to 0 never requires erasing flash. Just write it. */
- return _write_data_to_flash(offset, (uint8_t *) &db->keys[loc], sizeof(*db->keys));
+ return _write_data_to_flash(offset, (uint8_t *) k, sizeof(*k));
+}
+
+const hal_ks_driver_t hal_ks_flash_driver[1] = {{
+ ks_flash_open,
+ ks_flash_close,
+ ks_store,
+ ks_fetch,
+ ks_delete,
+ ks_list
+}};
+
+/*
+ * The remaining functions aren't really part of the keystore API per se,
+ * but they all involve non-key data which we keep in the keystore
+ * because it's the flash we've got.
+ */
+
+hal_error_t hal_ks_get_pin(const hal_user_t user,
+ const hal_ks_pin_t **pin)
+{
+ if (pin == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+
+ if ((err = ks_init()) != LIBHAL_OK)
+ return err;
+
+ 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;
+ }
+
+ /*
+ * 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.
+ */
+
+ 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 LIBHAL_OK;
}
hal_error_t hal_ks_set_pin(const hal_user_t user,
@@ -290,9 +567,9 @@ hal_error_t hal_ks_set_pin(const hal_user_t user,
hal_ks_pin_t *p = NULL;
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;
+ 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;
}
@@ -306,9 +583,9 @@ hal_error_t hal_ks_set_pin(const hal_user_t user,
/* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
+ active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
return _write_db_to_flash(active_sector_offset);
}
@@ -325,16 +602,19 @@ hal_error_t hal_ks_get_kek(uint8_t *kek,
bitsToBytes(256));
hal_error_t err = masterkey_volatile_read(kek, len);
+
if (err == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
+ *kek_len = len;
+ return LIBHAL_OK;
}
+
if (masterkey_flash_read(kek, len) == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
+ *kek_len = len;
+ return LIBHAL_OK;
}
- /* Both keystores returned an error, probably HAL_ERROR_MASTERKEY_NOT_SET.
+ /*
+ * 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.
@@ -343,7 +623,6 @@ hal_error_t hal_ks_get_kek(uint8_t *kek,
}
-
/*
* Local variables:
* indent-tabs-mode: nil
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
diff --git a/rpc_api.c b/rpc_api.c
index a19bdb4..2fe7e63 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -75,7 +75,7 @@ static inline int check_pkey_flags(const hal_key_flags_t flags)
return (flags &~ (HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE |
HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT |
HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT |
- HAL_KEY_FLAG_PROXIMATE)) == 0;
+ HAL_KEY_FLAG_TOKEN)) == 0;
}
static inline int check_pkey_type_curve_flags(const hal_key_type_t type,
@@ -218,36 +218,31 @@ hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- if (pkey == NULL || name == NULL || der == NULL || der_len == 0 ||
- !check_pkey_type_curve_flags(type, curve, flags))
+ if (pkey == NULL || name == NULL || der == NULL || der_len == 0 || !check_pkey_type_curve_flags(type, curve, flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->load(client, session, pkey, type, curve, name, name_len, der, der_len, flags);
+ return hal_rpc_pkey_dispatch->load(client, session, pkey, type, curve, name, der, der_len, flags);
}
hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
if (pkey == NULL || name == NULL || !check_pkey_type(type))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->find(client, session, pkey, type, name, name_len, flags);
+ return hal_rpc_pkey_dispatch->find(client, session, pkey, type, name, flags);
}
hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_len,
const uint8_t * const exp, const size_t exp_len,
const hal_key_flags_t flags)
@@ -255,24 +250,20 @@ hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
if (pkey == NULL || name == NULL || key_len == 0 || (key_len & 7) != 0 ||
exp == NULL || exp_len == 0 || !check_pkey_flags(flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->generate_rsa(client, session, pkey, name, name_len, key_len, exp, exp_len, flags);
+ return hal_rpc_pkey_dispatch->generate_rsa(client, session, pkey, name, key_len, exp, exp_len, flags);
}
hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
if (pkey == NULL || name == NULL ||
!check_pkey_type_curve_flags(HAL_KEY_TYPE_EC_PRIVATE, curve, flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, name_len, curve, flags);
+ return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, curve, flags);
}
hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey)
@@ -285,16 +276,6 @@ hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey)
return hal_rpc_pkey_dispatch->delete(pkey);
}
-hal_error_t hal_rpc_pkey_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- if (name == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->rename(pkey, name, name_len);
-}
-
hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *type)
{
diff --git a/rpc_client.c b/rpc_client.c
index a952a6e..98d6abe 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -411,13 +411,14 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(8) + pad(name_len) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(7) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
@@ -425,7 +426,6 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, type));
check(hal_xdr_encode_int(&optr, olimit, curve));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_buffer(&optr, olimit, der, der_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -433,8 +433,13 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_LOAD, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
@@ -443,10 +448,10 @@ static hal_error_t pkey_remote_find(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t outbuf[nargs(6) + pad(sizeof(name->uuid))], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
hal_error_t rpc_ret;
@@ -455,13 +460,14 @@ static hal_error_t pkey_remote_find(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, type));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+ check(hal_xdr_encode_buffer(&optr, olimit, name->uuid, sizeof(name->uuid)));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_PKEY_FIND, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+
if (rpc_ret == HAL_OK)
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
@@ -471,20 +477,20 @@ static hal_error_t pkey_remote_find(const hal_client_handle_t client,
static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_len,
const uint8_t * const exp, const size_t exp_len,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(7) + pad(name_len) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(6) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_int(&optr, olimit, key_len));
check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
@@ -493,8 +499,13 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_GENERATE_RSA, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
@@ -502,19 +513,19 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(5)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_int(&optr, olimit, curve));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -522,8 +533,13 @@ static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_GENERATE_EC, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
@@ -566,28 +582,6 @@ static hal_error_t pkey_remote_delete(const hal_pkey_handle_t pkey)
return rpc_ret;
}
-static hal_error_t pkey_remote_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- uint8_t outbuf[nargs(4) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(3)];
- const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- hal_client_handle_t dummy_client = {0};
- hal_error_t rpc_ret;
-
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_RENAME));
- check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
- check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
- check(hal_rpc_send(outbuf, optr - outbuf));
-
- check(read_matching_packet(RPC_FUNC_PKEY_RENAME, inbuf, sizeof(inbuf), &iptr, &ilimit));
-
- check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- return rpc_ret;
-}
-
-
static hal_error_t pkey_remote_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *type)
{
@@ -750,12 +744,17 @@ static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
static hal_error_t hal_xdr_decode_pkey_info(const uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info)
{
- uint32_t i32;
+ uint32_t u32;
+
+ check(hal_xdr_decode_int(iptr, ilimit, &u32)); info->type = u32;
+ check(hal_xdr_decode_int(iptr, ilimit, &u32)); info->curve = u32;
+ check(hal_xdr_decode_int(iptr, ilimit, &u32)); info->flags = u32;
+
+ u32 = sizeof(info->name.uuid);
+ check(hal_xdr_decode_buffer(iptr, ilimit, info->name.uuid, &u32));
+ if (u32 != sizeof(info->name.uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->type = i32;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->curve = i32;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->flags = i32;
- check(hal_xdr_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32;
return HAL_OK;
}
@@ -907,46 +906,43 @@ static hal_error_t pkey_mixed_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- return mixed_flags_dispatch(flags)->load(client, session, pkey, type, curve,
- name, name_len, der, der_len, flags);
+ return mixed_flags_dispatch(flags)->load(client, session, pkey, type, curve, name, der, der_len, flags);
}
static hal_error_t pkey_mixed_find(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- return mixed_flags_dispatch(flags)->find(client, session, pkey, type,
- name, name_len, flags);
+ return mixed_flags_dispatch(flags)->find(client, session, pkey, type, name, flags);
}
static hal_error_t pkey_mixed_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags)
{
- return mixed_flags_dispatch(flags)->generate_rsa(client, session, pkey,
- name, name_len, key_length,
+ return mixed_flags_dispatch(flags)->generate_rsa(client, session, pkey, name, key_length,
public_exponent, public_exponent_len, flags);
}
static hal_error_t pkey_mixed_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
- return mixed_flags_dispatch(flags)->generate_ec(client, session, pkey, name, name_len, curve, flags);
+ return mixed_flags_dispatch(flags)->generate_ec(client, session, pkey, name, curve, flags);
}
static hal_error_t pkey_mixed_close(const hal_pkey_handle_t pkey)
@@ -959,12 +955,6 @@ static hal_error_t pkey_mixed_delete(const hal_pkey_handle_t pkey)
return mixed_handle_dispatch(pkey)->delete(pkey);
}
-static hal_error_t pkey_mixed_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- return mixed_handle_dispatch(pkey)->rename(pkey, name, name_len);
-}
-
static hal_error_t pkey_mixed_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *key_type)
{
@@ -1027,7 +1017,6 @@ const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
pkey_remote_generate_ec,
pkey_remote_close,
pkey_remote_delete,
- pkey_remote_rename,
pkey_remote_get_key_type,
pkey_remote_get_key_flags,
pkey_remote_get_public_key_len,
@@ -1045,7 +1034,6 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
pkey_mixed_generate_ec,
pkey_mixed_close,
pkey_mixed_delete,
- pkey_mixed_rename,
pkey_mixed_get_key_type,
pkey_mixed_get_key_flags,
pkey_mixed_get_public_key_len,
diff --git a/rpc_pkey.c b/rpc_pkey.c
index d6efbe7..6de3a9b 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -39,35 +39,12 @@
#include "hal.h"
#include "hal_internal.h"
-typedef struct {
- hal_client_handle_t client_handle;
- hal_session_handle_t session_handle;
- hal_pkey_handle_t pkey_handle;
- hal_key_type_t type;
- hal_curve_name_t curve;
- hal_key_flags_t flags;
- uint8_t name[HAL_RPC_PKEY_NAME_MAX];
- size_t name_len;
- int ks_hint;
- /*
- * This might be where we'd stash a (hal_core_t *) pointing to a
- * core which has already been loaded with the key, if we were
- * trying to be clever about using multiple signing cores. Moot
- * point (ie, no way we could possibly test such a thing) as long as
- * the FPGA is too small to hold more than one modexp core and ECDSA
- * is entirely software, so skip it for now, but the implied
- * semantics are interesting: a pkey handle starts to resemble an
- * initialized signing core, and once all the cores are in use, one
- * can't load another key without closing an existing pkey handle.
- */
-} pkey_slot_t;
-
#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
#define HAL_STATIC_PKEY_STATE_BLOCKS 0
#endif
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
-static pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
+static hal_pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
#endif
/*
@@ -82,23 +59,23 @@ static pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
* handlers to route calls to the appropriate destination.
*/
-static inline pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
+static inline hal_pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
{
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
static uint16_t next_glop = 0;
uint32_t glop = ++next_glop << 16;
next_glop %= 0x7FFF;
- assert((glop & HAL_PKEY_HANDLE_PROXIMATE_FLAG) == 0);
+ assert((glop & HAL_PKEY_HANDLE_TOKEN_FLAG) == 0);
- if ((flags & HAL_KEY_FLAG_PROXIMATE) != 0)
- glop |= HAL_PKEY_HANDLE_PROXIMATE_FLAG;
+ if ((flags & HAL_KEY_FLAG_TOKEN) != 0)
+ glop |= HAL_PKEY_HANDLE_TOKEN_FLAG;
for (int i = 0; i < sizeof(pkey_handle)/sizeof(*pkey_handle); i++) {
if (pkey_handle[i].type != HAL_KEY_TYPE_NONE)
continue;
+ memset(&pkey_handle[i], 0, sizeof(pkey_handle[i]));
pkey_handle[i].pkey_handle.handle = i | glop;
- pkey_handle[i].ks_hint = -1;
return &pkey_handle[i];
}
#endif
@@ -111,7 +88,7 @@ static inline pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
* the right glop. Returns slot pointer on success, NULL otherwise.
*/
-static inline pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
+static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
{
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
const int i = (int) (handle.handle & 0xFFFF);
@@ -129,12 +106,10 @@ static inline pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
* Need to check detailed PKCS #11 rules, but, from memory, we may be supposed to allow
* access to non-token objects even when not logged in. Maybe. Rules are complex.
*
- * I think the libhal translation of this resolves around what we've
- * been calling the PROXIMATE flags (which probably ought to be
- * renamed to *_NONTOKEN_*, slightly less confusing name). For token
- * objects, we insist on being logged in properly; for non-token
- * objects, we do whatever silly thing PKCS #11 wants us to do,
- * probably defaulting to requiring login if PKCS #11 gives us a choice.
+ * I think the libhal translation of this resolves around HAL_KEY_FLAG_TOKEN.
+ * For token objects, we insist on being logged in properly; for non-token
+ * objects, we do whatever silly thing PKCS #11 wants us to do, probably
+ * defaulting to requiring login if PKCS #11 gives us a choice.
*/
/*
@@ -223,6 +198,27 @@ static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len
}
/*
+ * Given key flags, open appropriate keystore driver.
+ */
+
+static inline hal_error_t ks_open_from_flags(hal_ks_t **ks, const hal_key_flags_t flags)
+{
+ if ((flags & HAL_KEY_FLAG_TOKEN) == 0)
+ return hal_ks_open(hal_ks_volatile_driver, ks);
+
+#if 0
+
+ return hal_ks_open(hal_ks_token_driver, ks);
+
+#else
+#warning This needs to open hal_ks_token_driver here, once we get around to writing that driver
+
+ return HAL_ERROR_KS_DRIVER_NOT_FOUND;
+
+#endif
+}
+
+/*
* Receive key from application, store it with supplied name, return a key handle.
*/
@@ -231,30 +227,39 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
- hal_error_t err;
+ assert(pkey != NULL && name != NULL);
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- if ((err = hal_ks_store(type, curve, flags, name, name_len, der, der_len, &slot->ks_hint)) != HAL_OK)
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
return err;
- memcpy(slot->name, name, name_len);
slot->client_handle = client;
slot->session_handle = session;
slot->type = type;
slot->curve = curve;
slot->flags = flags;
- slot->name_len = name_len;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err != HAL_OK)
+ return err;
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -266,25 +271,31 @@ static hal_error_t pkey_local_find(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
- hal_error_t err;
+ assert(pkey != NULL && name != NULL);
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- if ((err = hal_ks_fetch(type, name, name_len, &slot->curve, &slot->flags, NULL, NULL, 0, &slot->ks_hint)) != HAL_OK)
- return err;
-
- memcpy(slot->name, name, name_len);
+ slot->name = *name;
slot->client_handle = client;
slot->session_handle = session;
slot->type = type;
- slot->name_len = name_len;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, NULL, NULL, 0)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err != HAL_OK)
+ return err;
*pkey = slot->pkey_handle;
return HAL_OK;
@@ -297,21 +308,30 @@ static hal_error_t pkey_local_find(const hal_client_handle_t client,
static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
- hal_error_t err;
+ assert(pkey != NULL && name != NULL && (key_length & 7) == 0);
- assert(sizeof(slot->name) >= name_len && pkey != NULL && (key_length & 7) == 0);
+ uint8_t keybuf[hal_rsa_key_t_size];
+ hal_rsa_key_t *key = NULL;
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- uint8_t keybuf[hal_rsa_key_t_size];
- hal_rsa_key_t *key = NULL;
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
+ return err;
+
+ slot->client_handle = client;
+ slot->session_handle = session;
+ slot->type = HAL_KEY_TYPE_RSA_PRIVATE;
+ slot->curve = HAL_CURVE_NONE;
+ slot->flags = flags;
if ((err = hal_rsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), key_length / 8,
public_exponent, public_exponent_len)) != HAL_OK)
@@ -320,9 +340,12 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
uint8_t der[hal_rsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_store(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, flags,
- name, name_len, der, der_len, &slot->ks_hint);
+ if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
+ (err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -330,15 +353,8 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
if (err != HAL_OK)
return err;
- memcpy(slot->name, name, name_len);
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = HAL_KEY_TYPE_RSA_PRIVATE;
- slot->curve = HAL_CURVE_NONE;
- slot->flags = flags;
- slot->name_len = name_len;
-
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -350,20 +366,29 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
- hal_error_t err;
+ assert(pkey != NULL && name != NULL);
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ uint8_t keybuf[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *key = NULL;
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- uint8_t keybuf[hal_ecdsa_key_t_size];
- hal_ecdsa_key_t *key = NULL;
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
+ return err;
+
+ slot->client_handle = client;
+ slot->session_handle = session;
+ slot->type = HAL_KEY_TYPE_EC_PRIVATE;
+ slot->curve = curve;
+ slot->flags = flags;
if ((err = hal_ecdsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), curve)) != HAL_OK)
return err;
@@ -371,9 +396,12 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
uint8_t der[hal_ecdsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_store(HAL_KEY_TYPE_EC_PRIVATE, curve, flags,
- name, name_len, der, der_len, &slot->ks_hint);
+ if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
+ (err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -381,15 +409,8 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
if (err != HAL_OK)
return err;
- memcpy(slot->name, name, name_len);
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = HAL_KEY_TYPE_EC_PRIVATE;
- slot->curve = curve;
- slot->flags = flags;
- slot->name_len = name_len;
-
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -399,7 +420,7 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
static hal_error_t pkey_local_close(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot;
+ hal_pkey_slot_t *slot;
if ((slot = find_handle(pkey)) == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -415,12 +436,19 @@ static hal_error_t pkey_local_close(const hal_pkey_handle_t pkey)
static hal_error_t pkey_local_delete(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- hal_error_t err = hal_ks_delete(slot->type, slot->name, slot->name_len, &slot->ks_hint);
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_delete(ks, slot)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK || err == HAL_ERROR_KEY_NOT_FOUND)
memset(slot, 0, sizeof(*slot));
@@ -429,30 +457,6 @@ static hal_error_t pkey_local_delete(const hal_pkey_handle_t pkey)
}
/*
- * Rename a key in the key store, given its key handle and a new name.
- */
-
-static hal_error_t pkey_local_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- pkey_slot_t *slot = find_handle(pkey);
-
- if (slot == NULL)
- return HAL_ERROR_KEY_NOT_FOUND;
-
- hal_error_t err = hal_ks_rename(slot->type, slot->name, slot->name_len, name, name_len, &slot->ks_hint);
-
- if (err == HAL_OK) {
- assert(name_len <= sizeof(slot->name));
- memcpy(slot->name, name, name_len);
- memset(slot->name + name_len, 0, sizeof(slot->name) - name_len);
- slot->name_len = name_len;
- }
-
- return err;
-}
-
-/*
* Get type of key associated with handle.
*/
@@ -462,7 +466,7 @@ static hal_error_t pkey_local_get_key_type(const hal_pkey_handle_t pkey,
if (type == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -482,7 +486,7 @@ static hal_error_t pkey_local_get_key_flags(const hal_pkey_handle_t pkey,
if (flags == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -498,7 +502,7 @@ static hal_error_t pkey_local_get_key_flags(const hal_pkey_handle_t pkey,
static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return 0;
@@ -510,9 +514,16 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
- if (hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL,
- der, &der_len, sizeof(der), &slot->ks_hint) == HAL_OK) {
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -548,7 +559,7 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
uint8_t *der, size_t *der_len, const size_t der_max)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -558,10 +569,16 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t buf[HAL_KS_WRAPPED_KEYSIZE];
size_t buf_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL,
- buf, &buf_len, sizeof(buf), &slot->ks_hint)) == HAL_OK) {
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, buf, &buf_len, sizeof(buf))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -678,7 +695,7 @@ static hal_error_t pkey_local_sign(const hal_session_handle_t session,
const uint8_t * const input, const size_t input_len,
uint8_t * signature, size_t *signature_len, const size_t signature_max)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -703,9 +720,14 @@ static hal_error_t pkey_local_sign(const hal_session_handle_t session,
uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint);
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK)
err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len, signature_max);
@@ -820,7 +842,7 @@ static hal_error_t pkey_local_verify(const hal_session_handle_t session,
const uint8_t * const input, const size_t input_len,
const uint8_t * const signature, const size_t signature_len)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -847,9 +869,14 @@ static hal_error_t pkey_local_verify(const hal_session_handle_t session,
uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint);
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK)
err = verifier(keybuf, sizeof(keybuf), slot->type, der, der_len, hash, input, input_len, signature, signature_len);
@@ -870,7 +897,16 @@ static hal_error_t pkey_local_list(hal_pkey_info_t *result,
const unsigned result_max,
hal_key_flags_t flags)
{
- return hal_ks_list(result, result_len, result_max);
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_list(ks, result, result_len, result_max)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ return err;
}
const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
@@ -880,7 +916,6 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
pkey_local_generate_ec,
pkey_local_close,
pkey_local_delete,
- pkey_local_rename,
pkey_local_get_key_type,
pkey_local_get_key_flags,
pkey_local_get_public_key_len,
diff --git a/rpc_server.c b/rpc_server.c
index a0de42d..9694ab8 100644
--- a/rpc_server.c
+++ b/rpc_server.c
@@ -55,6 +55,7 @@ static hal_error_t get_version(const uint8_t **iptr, const uint8_t * const ilimi
/* call the local function */
ret = hal_rpc_local_misc_dispatch.get_version(&version);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, version));
@@ -102,6 +103,7 @@ static hal_error_t set_pin(const uint8_t **iptr, const uint8_t * const ilimit,
/* call the local function */
ret = hal_rpc_local_misc_dispatch.set_pin(client, user, (const char * const)pin, pin_len);
+
return ret;
}
@@ -120,6 +122,7 @@ static hal_error_t login(const uint8_t **iptr, const uint8_t * const ilimit,
/* call the local function */
ret = hal_rpc_local_misc_dispatch.login(client, user, (const char * const)pin, pin_len);
+
return ret;
}
@@ -133,6 +136,7 @@ static hal_error_t logout(const uint8_t **iptr, const uint8_t * const ilimit,
/* call the local function */
ret = hal_rpc_local_misc_dispatch.logout(client);
+
return ret;
}
@@ -146,6 +150,7 @@ static hal_error_t logout_all(const uint8_t **iptr, const uint8_t * const ilimit
/* call the local function */
ret = hal_rpc_local_misc_dispatch.logout_all();
+
return ret;
}
@@ -161,6 +166,7 @@ static hal_error_t is_logged_in(const uint8_t **iptr, const uint8_t * const ilim
/* call the local function */
ret = hal_rpc_local_misc_dispatch.is_logged_in(client, user);
+
return ret;
}
@@ -177,8 +183,10 @@ static hal_error_t hash_get_digest_len(const uint8_t **iptr, const uint8_t * con
/* call the local function */
ret = hal_rpc_local_hash_dispatch.get_digest_length(alg, &length);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, length));
+
return ret;
}
@@ -228,8 +236,10 @@ static hal_error_t hash_get_algorithm(const uint8_t **iptr, const uint8_t * cons
/* call the local function */
ret = hal_rpc_local_hash_dispatch.get_algorithm(hash, &alg);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, alg));
+
return ret;
}
@@ -251,8 +261,10 @@ static hal_error_t hash_initialize(const uint8_t **iptr, const uint8_t * const i
/* call the local function */
ret = hal_rpc_local_hash_dispatch.initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, hash.handle));
+
return ret;
}
@@ -271,6 +283,7 @@ static hal_error_t hash_update(const uint8_t **iptr, const uint8_t * const ilimi
/* call the local function */
ret = hal_rpc_local_hash_dispatch.update(hash, data, (size_t)length);
+
return ret;
}
@@ -309,8 +322,9 @@ static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
hal_pkey_handle_t pkey;
uint32_t type;
uint32_t curve;
- const uint8_t *name, *der;
- uint32_t name_len, der_len;
+ hal_uuid_t name;
+ const uint8_t *der;
+ uint32_t der_len;
hal_key_flags_t flags;
hal_error_t ret;
@@ -318,14 +332,19 @@ static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
check(hal_xdr_decode_int(iptr, ilimit, &type));
check(hal_xdr_decode_int(iptr, ilimit, &curve));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &der, &der_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.load(client, session, &pkey, type, curve, name, name_len, der, der_len, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_local_pkey_dispatch.load(client, session, &pkey, type, curve, &name, der, der_len, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
@@ -336,7 +355,7 @@ static hal_error_t pkey_find(const uint8_t **iptr, const uint8_t * const ilimit,
hal_session_handle_t session;
hal_pkey_handle_t pkey;
uint32_t type;
- const uint8_t *name;
+ const uint8_t *name_ptr;
uint32_t name_len;
hal_key_flags_t flags;
hal_error_t ret;
@@ -344,13 +363,18 @@ static hal_error_t pkey_find(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
check(hal_xdr_decode_int(iptr, ilimit, &type));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+ check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name_ptr, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
+ if (name_len != sizeof(hal_uuid_t))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.find(client, session, &pkey, type, name, name_len, flags);
+ ret = hal_rpc_local_pkey_dispatch.find(client, session, &pkey, type, (const hal_uuid_t *) name_ptr, flags);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+
return ret;
}
@@ -360,8 +384,7 @@ static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const
hal_client_handle_t client;
hal_session_handle_t session;
hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
+ hal_uuid_t name;
uint32_t key_len;
const uint8_t *exp;
uint32_t exp_len;
@@ -370,15 +393,20 @@ static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &key_len));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.generate_rsa(client, session, &pkey, name, name_len, key_len, exp, exp_len, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_local_pkey_dispatch.generate_rsa(client, session, &pkey, &name, key_len, exp, exp_len, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
@@ -388,22 +416,26 @@ static hal_error_t pkey_generate_ec(const uint8_t **iptr, const uint8_t * const
hal_client_handle_t client;
hal_session_handle_t session;
hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
+ hal_uuid_t name;
uint32_t curve;
hal_key_flags_t flags;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &curve));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.generate_ec(client, session, &pkey, name, name_len, curve, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_local_pkey_dispatch.generate_ec(client, session, &pkey, &name, curve, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
@@ -419,6 +451,7 @@ static hal_error_t pkey_close(const uint8_t **iptr, const uint8_t * const ilimit
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.close(pkey);
+
return ret;
}
@@ -434,24 +467,7 @@ static hal_error_t pkey_delete(const uint8_t **iptr, const uint8_t * const ilimi
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.delete(pkey);
- return ret;
-}
-
-static hal_error_t pkey_rename(const uint8_t **iptr, const uint8_t * const ilimit,
- uint8_t **optr, const uint8_t * const olimit)
-{
- hal_client_handle_t client __attribute__((unused));
- hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
-
- /* call the local function */
- ret = hal_rpc_local_pkey_dispatch.rename(pkey, name, name_len);
return ret;
}
@@ -468,8 +484,10 @@ static hal_error_t pkey_get_key_type(const uint8_t **iptr, const uint8_t * const
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.get_key_type(pkey, &type);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, type));
+
return ret;
}
@@ -486,8 +504,10 @@ static hal_error_t pkey_get_key_flags(const uint8_t **iptr, const uint8_t * cons
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.get_key_flags(pkey, &flags);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, flags));
+
return ret;
}
@@ -503,7 +523,9 @@ static hal_error_t pkey_get_public_key_len(const uint8_t **iptr, const uint8_t *
/* call the local function */
len = hal_rpc_local_pkey_dispatch.get_public_key_len(pkey);
+
check(hal_xdr_encode_int(optr, olimit, len));
+
return HAL_OK;
}
@@ -598,6 +620,7 @@ static hal_error_t pkey_remote_verify(const uint8_t **iptr, const uint8_t * cons
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.verify(session, pkey, hash, input, input_len, sig, sig_len);
+
return ret;
}
@@ -609,12 +632,11 @@ static hal_error_t hal_xdr_encode_pkey_info(uint8_t **optr, const uint8_t * cons
if ((ret = hal_xdr_encode_int(optr, olimit, info->type)) != HAL_OK ||
(ret = hal_xdr_encode_int(optr, olimit, info->curve)) != HAL_OK ||
(ret = hal_xdr_encode_int(optr, olimit, info->flags)) != HAL_OK ||
- (ret = hal_xdr_encode_buffer(optr, olimit, (uint8_t *)&info->name[0], info->name_len)) != HAL_OK)
+ (ret = hal_xdr_encode_buffer(optr, olimit, info->name.uuid, sizeof(info->name.uuid))) != HAL_OK)
*optr = optr_orig;
return ret;
}
-
static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
@@ -633,6 +655,7 @@ static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
/* call the local function */
ret = hal_rpc_local_pkey_dispatch.list(result, &result_len, result_max, flags);
+
if (ret == HAL_OK) {
int i;
check(hal_xdr_encode_int(optr, olimit, result_len));
@@ -643,6 +666,7 @@ static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
}
}
}
+
return ret;
}
@@ -739,9 +763,6 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
case RPC_FUNC_PKEY_LIST:
ret = pkey_list(&iptr, ilimit, &optr, olimit);
break;
- case RPC_FUNC_PKEY_RENAME:
- ret = pkey_rename(&iptr, ilimit, &optr, olimit);
- break;
default:
ret = HAL_ERROR_RPC_BAD_FUNCTION;
break;
diff --git a/uuid.c b/uuid.c
new file mode 100644
index 0000000..04410c0
--- /dev/null
+++ b/uuid.c
@@ -0,0 +1,75 @@
+/*
+ * uuid.c
+ * ------
+ * UUID support for keystore database.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+hal_error_t hal_uuid_gen(hal_uuid_t *uuid)
+{
+ hal_error_t err;
+
+ if (uuid == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Generate a version 4 UUID as specified in RFC 4122.
+ * This is basically a 122-bit random number.
+ */
+
+ if ((err = hal_rpc_get_random(uuid->uuid, sizeof(uuid->uuid))) != HAL_OK)
+ return err;
+
+ /*
+ * Set high order bits of clock_seq_hi_and_reserved and
+ * time_hi_and_version fields to magic values as specified by RFC
+ * 4122 section 4.4.
+ *
+ * Not recommended reading if you've eaten recently.
+ */
+
+ uuid->uuid[6] &= 0x0f;
+ uuid->uuid[6] |= 0x40;
+ uuid->uuid[8] &= 0x3f;
+ uuid->uuid[8] |= 0x80;
+
+ return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */