[Cryptech-Commits] [sw/libhal] 01/11: RPC server stuff mostly written. Compiles, not yet tested. RPC public key extraction functions on hold pending ASN.1 cleanup.

git at cryptech.is git at cryptech.is
Wed Dec 23 07:22:20 UTC 2015


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

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

commit 86b35d757048aaa122237e1cb8fb33de9d53292d
Author: Rob Austein <sra at hactrn.net>
Date:   Sun Dec 20 17:59:29 2015 -0500

    RPC server stuff mostly written.  Compiles, not yet tested.  RPC
    public key extraction functions on hold pending ASN.1 cleanup.
---
 GNUmakefile                      |  24 +-
 ecdsa.c                          |  42 +--
 hal.h                            | 254 ++++++++++++--
 rpc_internal.h => hal_internal.h | 137 +++++++-
 hal_rpc.h                        | 243 -------------
 ks.c                             | 280 +++++++++++++++
 ks_flash.c                       |  71 ++++
 ks_mmap.c                        | 115 ++++++
 ks_volatile.c                    |  74 ++++
 hal_rpc.c => rpc.c               |  82 +++--
 rpc_client.c                     |  53 +--
 rpc_hash.c                       |  30 +-
 rpc_pkey.c                       | 736 +++++++++++++++++++++++++++++++++++++++
 rsa.c                            |  22 +-
 tests/test-ecdsa.c               |  14 +-
 tests/test-ecdsa.h               |   6 +-
 16 files changed, 1776 insertions(+), 407 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile
index 8fc0d14..e0b4730 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -27,22 +27,24 @@
 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Number of static hash and HMAC state blocks to allocate
+# Number of static hash and HMAC state blocks to allocate.
+# Numbers pulled out of a hat, just testing.
 
 STATIC_HASH_STATE_BLOCKS = 10
 STATIC_HMAC_STATE_BLOCKS = 4
+STATIC_PKEY_STATE_BLOCKS = 6
 
-INC		= hal.h
+INC		= hal.h hal_internal.h
 LIB		= libhal.a
 OBJ		= ${IO_OBJ} core.o csprng.o hash.o aes_keywrap.o pbkdf2.o \
-		  modexp.o rsa.o ecdsa.o asn1.o errorstrings.o ${RPC_OBJ}
+		  modexp.o rsa.o ecdsa.o asn1.o errorstrings.o ${RPC_OBJ} ${KS_OBJ}
 IO_OBJ_EIM	= hal_io_eim.o novena-eim.o
 IO_OBJ_I2C 	= hal_io_i2c.o
 
 # Default I/O bus is EIM, override this to use I2C instead
 IO_OBJ		= ${IO_OBJ_EIM}
 
-RPC_OBJ_COMMON	= hal_rpc.o rpc_hash.o
+RPC_OBJ_COMMON	= rpc.o rpc_hash.o
 RPC_OBJ_CLIENT	= ${RPC_OBJ_COMMON} rpc_client.o
 RPC_OBJ_SERVER	= ${RPC_OBJ_COMMON} rpc_misc.o rpc_pkey.o
 
@@ -51,12 +53,20 @@ RPC_OBJ_SERVER	= ${RPC_OBJ_COMMON} rpc_misc.o rpc_pkey.o
 # needing a makefile conditional to handle all this properly
 RPC_OBJ		= ${RPC_OBJ_CLIENT}
 
+# XXX temporary
+$(warning TEMPORARY KLUDGE TO TEST rpc_pkey)
+RPC_OBJ		+= rpc_pkey.o
+
+# XXX temporary
+KS_OBJ		= ks.o ks_mmap.o
+
 TFMDIR		:= $(abspath ../thirdparty/libtfm)
 CFLAGS		+= -g3 -Wall -fPIC -std=c99 -I${TFMDIR} -DHAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM=1
 LDFLAGS		:= -g3 -L${TFMDIR} -ltfm
 
 CFLAGS		+= -DHAL_STATIC_HASH_STATE_BLOCKS=${STATIC_HASH_STATE_BLOCKS}
 CFLAGS		+= -DHAL_STATIC_HMAC_STATE_BLOCKS=${STATIC_HMAC_STATE_BLOCKS}
+CFLAGS		+= -DHAL_STATIC_PKEY_STATE_BLOCKS=${STATIC_PKEY_STATE_BLOCKS}
 
 all: ${LIB}
 	cd tests; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@
@@ -67,9 +77,9 @@ ${OBJ}: ${INC}
 ${LIB}: ${OBJ}
 	${AR} rcs $@ $^
 
-asn1.o rsa.o ecdsa.o: asn1_internal.h
-
-ecdsa.o: ecdsa_curves.h
+asn1.o rsa.o ecdsa.o:		asn1_internal.h
+ecdsa.o:			ecdsa_curves.h
+novena-eim.o hal_io_eim.o:	novena-eim.h
 
 test: all
 	cd tests; ${MAKE} -k $@
diff --git a/ecdsa.c b/ecdsa.c
index eeab252..703849b 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -150,8 +150,8 @@ typedef struct {
 } ec_point_t;
 
 struct hal_ecdsa_key {
-  hal_ecdsa_key_type_t type;            /* Public or private is */
-  hal_ecdsa_curve_t curve;              /* Curve descriptor */
+  hal_key_type_t type;                  /* Public or private */
+  hal_curve_name_t curve;               /* Curve descriptor */
   ec_point_t Q[1];                      /* Public key */
   fp_int d[1];                          /* Private key */
 };
@@ -181,7 +181,7 @@ const size_t hal_ecdsa_key_t_size = sizeof(struct hal_ecdsa_key);
  * first time anything asks for any of them.
  */
 
-static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve)
+static const ecdsa_curve_t * const get_curve(const hal_curve_name_t curve)
 {
   static ecdsa_curve_t curve_p256, curve_p384, curve_p521;
   static int initialized = 0;
@@ -230,10 +230,10 @@ static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve)
   }
 
   switch (curve) {
-  case HAL_ECDSA_CURVE_P256: return &curve_p256;
-  case HAL_ECDSA_CURVE_P384: return &curve_p384;
-  case HAL_ECDSA_CURVE_P521: return &curve_p521;
-  default:                   return NULL;
+  case HAL_CURVE_P256:  return &curve_p256;
+  case HAL_CURVE_P384:  return &curve_p384;
+  case HAL_CURVE_P521:  return &curve_p521;
+  default:              return NULL;
   }
 }
 
@@ -831,7 +831,7 @@ static int point_is_on_curve(const ec_point_t * const P,
 hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
                               hal_ecdsa_key_t **key_,
                               void *keybuf, const size_t keybuf_len,
-                              const hal_ecdsa_curve_t curve_)
+                              const hal_curve_name_t curve_)
 {
   const ecdsa_curve_t * const curve = get_curve(curve_);
   hal_ecdsa_key_t *key = keybuf;
@@ -842,7 +842,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
 
   memset(keybuf, 0, keybuf_len);
 
-  key->type = HAL_ECDSA_PRIVATE;
+  key->type = HAL_KEY_TYPE_EC_PRIVATE;
   key->curve = curve_;
 
   if ((err = point_pick_random(curve, key->d, key->Q)) != HAL_OK)
@@ -859,7 +859,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
  */
 
 hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
-                                   hal_ecdsa_key_type_t *key_type)
+                                   hal_key_type_t *key_type)
 {
   if (key == NULL || key_type == NULL)
     return HAL_ERROR_BAD_ARGUMENTS;
@@ -873,7 +873,7 @@ hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
  */
 
 hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key,
-                                    hal_ecdsa_curve_t *curve)
+                                    hal_curve_name_t *curve)
 {
   if (key == NULL || curve == NULL)
     return HAL_ERROR_BAD_ARGUMENTS;
@@ -929,7 +929,7 @@ void hal_ecdsa_key_clear(hal_ecdsa_key_t *key)
 
 hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
                                       void *keybuf, const size_t keybuf_len,
-                                      const hal_ecdsa_curve_t curve_,
+                                      const hal_curve_name_t curve_,
                                       const uint8_t * const x, const size_t x_len,
                                       const uint8_t * const y, const size_t y_len)
 {
@@ -941,7 +941,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
 
   memset(keybuf, 0, keybuf_len);
 
-  key->type = HAL_ECDSA_PUBLIC;
+  key->type = HAL_KEY_TYPE_EC_PUBLIC;
   key->curve = curve_;
 
   fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(x), x_len);
@@ -966,7 +966,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_,
 
 hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_,
                                        void *keybuf, const size_t keybuf_len,
-                                       const hal_ecdsa_curve_t curve_,
+                                       const hal_curve_name_t curve_,
                                        const uint8_t * const x, const size_t x_len,
                                        const uint8_t * const y, const size_t y_len,
                                        const uint8_t * const d, const size_t d_len)
@@ -980,7 +980,7 @@ hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_,
   if ((err = hal_ecdsa_key_load_public(key_, keybuf, keybuf_len, curve_, x, x_len, y, y_len)) != HAL_OK)
     return err;
 
-  key->type = HAL_ECDSA_PRIVATE;
+  key->type = HAL_KEY_TYPE_EC_PRIVATE;
   fp_read_unsigned_bin(key->d, unconst_uint8_t(d), d_len);
   return HAL_OK;
 }
@@ -1052,7 +1052,7 @@ size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key)
 hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
                                        void *keybuf, const size_t keybuf_len,
                                        const uint8_t * const der, const size_t der_len,
-                                       const hal_ecdsa_curve_t curve)
+                                       const hal_curve_name_t curve)
 {
   hal_ecdsa_key_t *key = keybuf;
 
@@ -1060,7 +1060,7 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
     return HAL_ERROR_BAD_ARGUMENTS;
 
   memset(keybuf, 0, keybuf_len);
-  key->type = HAL_ECDSA_PUBLIC;
+  key->type = HAL_KEY_TYPE_EC_PUBLIC;
   key->curve = curve;
 
   size_t hlen, vlen;
@@ -1106,7 +1106,7 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
 hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
                                  uint8_t *der, size_t *der_len, const size_t der_max)
 {
-  if (key == NULL || key->type != HAL_ECDSA_PRIVATE)
+  if (key == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE)
     return HAL_ERROR_BAD_ARGUMENTS;
 
   const ecdsa_curve_t * const curve = get_curve(key->curve);
@@ -1215,7 +1215,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
     return HAL_ERROR_BAD_ARGUMENTS;
 
   memset(keybuf, 0, keybuf_len);
-  key->type = HAL_ECDSA_PRIVATE;
+  key->type = HAL_KEY_TYPE_EC_PRIVATE;
 
   size_t hlen, vlen;
   hal_error_t err;
@@ -1248,7 +1248,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_,
   if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, vlen, &hlen, &vlen)) != HAL_OK)
     return err;
   d += hlen;
-  for (key->curve = (hal_ecdsa_curve_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++)
+  for (key->curve = (hal_curve_name_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++)
     if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0)
       break;
   if (curve == NULL)
@@ -1427,7 +1427,7 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core,
                            uint8_t *signature, size_t *signature_len, const size_t signature_max,
                            const hal_ecdsa_signature_format_t signature_format)
 {
-  if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_ECDSA_PRIVATE)
+  if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE)
     return HAL_ERROR_BAD_ARGUMENTS;
 
   const ecdsa_curve_t * const curve = get_curve(key->curve);
diff --git a/hal.h b/hal.h
index 1ccc491..4a1ef75 100644
--- a/hal.h
+++ b/hal.h
@@ -36,15 +36,19 @@
 #ifndef _HAL_H_
 #define _HAL_H_
 
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
 /*
  * A handy macro from cryptlib.
  */
 #ifndef bitsToBytes
-#define bitsToBytes(x)          (x / 8)
+#define bitsToBytes(x)          ((x) / 8)
 #endif
 
 /*
- * Current name and version values.
+ * Current name and version values for crypto cores.
  *
  * Should these even be here?  Dunno.
  * Should the versions be here even if the names should be?
@@ -114,6 +118,10 @@
   DEFINE_HAL_ERROR(HAL_ERROR_KEY_NOT_ON_CURVE,          "EC key is not on its purported curve")         \
   DEFINE_HAL_ERROR(HAL_ERROR_INVALID_SIGNATURE,         "Invalid signature")                            \
   DEFINE_HAL_ERROR(HAL_ERROR_CORE_NOT_FOUND,            "Requested core not found")                     \
+  DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_ACCESS,           "Could not access keystore")                    \
+  DEFINE_HAL_ERROR(HAL_ERROR_KEY_NOT_FOUND,             "Key not found")                                \
+  DEFINE_HAL_ERROR(HAL_ERROR_KEY_NAME_IN_USE,           "Key name in use")                              \
+  DEFINE_HAL_ERROR(HAL_ERROR_NO_KEY_SLOTS_AVAILABLE,    "No key slots available")                       \
   END_OF_HAL_ERROR_LIST
 
 /* Marker to forestall silly line continuation errors */
@@ -125,24 +133,21 @@ typedef enum { HAL_ERROR_LIST N_HAL_ERRORS } hal_error_t;
 #undef  DEFINE_HAL_ERROR
 
 /*
- * Public functions.
+ * Error translation.
  */
 
-#include <stdint.h>
-#include <sys/types.h>
+extern const char *hal_error_string(const hal_error_t err);
 
 /*
- * Typedef to isolate code from our current choice of representation
- * for a Cryptech bus address.
+ * Very low level public API for working directly with crypto cores.
  */
 
-typedef off_t hal_addr_t;
-
 /*
- * Error translation.
+ * Typedef to isolate code from our current choice of representation
+ * for a Cryptech bus address.
  */
 
-extern const char *hal_error_string(const hal_error_t err);
+typedef off_t hal_addr_t;
 
 /*
  * Opaque structure representing a core.
@@ -186,7 +191,7 @@ extern hal_addr_t hal_core_base(const hal_core_t *core);
 extern const hal_core_t * hal_core_iterate(const hal_core_t *core);
 
 /*
- * Higher level public API.
+ * Slightly higher level public API, still working directly with cores.
  */
 
 /*
@@ -340,10 +345,27 @@ extern hal_error_t hal_modexp(const hal_core_t *core,
 
 
 /*
- * RSA.
+ * Key types and curves, used in various places.
  */
 
-typedef enum { HAL_RSA_PRIVATE, HAL_RSA_PUBLIC } hal_rsa_key_type_t;
+typedef enum {
+  HAL_KEY_TYPE_NONE,
+  HAL_KEY_TYPE_RSA_PRIVATE,
+  HAL_KEY_TYPE_RSA_PUBLIC,
+  HAL_KEY_TYPE_EC_PRIVATE,
+  HAL_KEY_TYPE_EC_PUBLIC
+} hal_key_type_t;
+
+typedef enum {
+  HAL_CURVE_NONE,
+  HAL_CURVE_P256,
+  HAL_CURVE_P384,
+  HAL_CURVE_P521
+} hal_curve_name_t;
+
+/*
+ * RSA.
+ */
 
 typedef struct hal_rsa_key hal_rsa_key_t;
 
@@ -370,7 +392,7 @@ extern hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key,
                                            const uint8_t * const e,  const size_t e_len);
 
 extern hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key,
-                                        hal_rsa_key_type_t *key_type);
+                                        hal_key_type_t *key_type);
 
 extern hal_error_t hal_rsa_key_get_modulus(const hal_rsa_key_t * const key,
                                            uint8_t *modulus,
@@ -413,10 +435,6 @@ extern hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key,
  * ECDSA.
  */
 
-typedef enum { HAL_ECDSA_PRIVATE, HAL_ECDSA_PUBLIC } hal_ecdsa_key_type_t;
-
-typedef enum { HAL_ECDSA_CURVE_P256, HAL_ECDSA_CURVE_P384, HAL_ECDSA_CURVE_P521 } hal_ecdsa_curve_t;
-
 typedef enum { HAL_ECDSA_SIGNATURE_FORMAT_ASN1, HAL_ECDSA_SIGNATURE_FORMAT_PKCS11 } hal_ecdsa_signature_format_t;
 
 typedef struct hal_ecdsa_key hal_ecdsa_key_t;
@@ -427,22 +445,22 @@ extern void hal_ecdsa_set_debug(const int onoff);
 
 extern hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key,
                                               void *keybuf, const size_t keybuf_len,
-                                              const hal_ecdsa_curve_t curve,
+                                              const hal_curve_name_t curve,
                                               const uint8_t * const x, const size_t x_len,
                                               const uint8_t * const y, const size_t y_len,
                                               const uint8_t * const d, const size_t d_len);
 
 extern hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key,
                                              void *keybuf, const size_t keybuf_len,
-                                             const hal_ecdsa_curve_t curve,
+                                             const hal_curve_name_t curve,
                                              const uint8_t * const x, const size_t x_len,
                                              const uint8_t * const y, const size_t y_len);
 
 extern hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key,
-                                          hal_ecdsa_key_type_t *key_type);
+                                          hal_key_type_t *key_type);
 
 extern hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key,
-                                           hal_ecdsa_curve_t *curve);
+                                           hal_curve_name_t *curve);
 
 extern hal_error_t hal_ecdsa_key_get_public(const hal_ecdsa_key_t * const key,
                                             uint8_t *x, size_t *x_len, const size_t x_max,
@@ -453,7 +471,7 @@ extern void hal_ecdsa_key_clear(hal_ecdsa_key_t *key);
 extern hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
                                      hal_ecdsa_key_t **key,
                                      void *keybuf, const size_t keybuf_len,
-                                     const hal_ecdsa_curve_t curve);
+                                     const hal_curve_name_t curve);
 
 extern hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key,
                                         uint8_t *der, size_t *der_len, const size_t der_max);
@@ -472,7 +490,7 @@ extern size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key);
 extern hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key,
                                               void *keybuf, const size_t keybuf_len,
                                               const uint8_t * const der, const size_t der_len,
-                                              const hal_ecdsa_curve_t curve);
+                                              const hal_curve_name_t curve);
 
 extern hal_error_t hal_ecdsa_sign(const hal_core_t *core,
                                   const hal_ecdsa_key_t * const key,
@@ -486,6 +504,192 @@ extern hal_error_t hal_ecdsa_verify(const hal_core_t *core,
                                     const uint8_t * const signature, const size_t signature_len,
                                     const hal_ecdsa_signature_format_t signature_format);
 
+/*
+ * Higher level RPC-based mechanism for working with HSM at arm's
+ * length, using handles instead of direct access to the cores.
+ *
+ * Session handles are pretty much as in PKCS #11: from our viewpoint,
+ * a session is a lock-step stream of operations, so while operations
+ * from different sessions can interleave, operations within a single
+ * session cannot.
+ *
+ * Client handles are a small extension to the PKCS #11 model,
+ * intended to support multiple PKCS #11 using applications sharing a
+ * single HSM.  Technically, sessions are per-client, but in practice
+ * there's no sane reason why we'd use the same session handle
+ * concurrently in multiple clients.  Mostly, the client abstraction
+ * is to handle login and logout against the HSM's PIN.  Clients add
+ * nothing whatsoever to the security model (the HSM has no way of
+ * knowing whether the host is lumping multiple applications into a
+ * single "client"), the point of the exercise is just to make the
+ * C_Login()/C_Logout() semantics work as expected in the presence of
+ * multiple applications.
+ *
+ * NB: Unlike the other handles used in this protocol, session and
+ * client handles are created by the client (host) side of the RPC
+ * mechanism, not the server (HSM) side.
+ */
+
+typedef struct { uint32_t handle; } hal_rpc_client_handle_t;
+typedef struct { uint32_t handle; } hal_rpc_session_handle_t;
+
+typedef enum { HAL_RPC_USER_NONE, HAL_RPC_USER_NORMAL, HAL_RPC_USER_SO } hal_rpc_user_t;
+
+extern hal_error_t hal_rpc_set_pin(const hal_rpc_user_t which,
+                                   const char * const newpin, const size_t newpin_len);
+
+extern hal_error_t hal_rpc_login(const hal_rpc_client_handle_t client,
+                                 const hal_rpc_user_t user,
+                                 const char * const pin, const size_t pin_len);
+
+extern hal_error_t hal_rpc_logout(const hal_rpc_client_handle_t client);
+
+/*
+ * Get random bytes.
+ */
+
+extern hal_error_t hal_rpc_get_random(void *buffer, const size_t length);
+
+/*
+ * Combined hash and HMAC functions: pass NULL key for plain hashing.
+ */
+
+typedef struct { uint32_t handle; } hal_rpc_hash_handle_t;
+
+extern const hal_rpc_hash_handle_t hal_rpc_hash_handle_none;
+
+extern hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, size_t *length);
+
+extern hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg,
+                                                        uint8_t *id, size_t *len, const size_t len_max);
+
+extern hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg);
+
+/*
+ * Once started, a hash or HMAC operation is bound to a particular
+ * session, so we only need the client and session arguments to initialize.
+ */
+
+extern hal_error_t hal_rpc_hash_initialize(const hal_rpc_client_handle_t client,
+                                           const hal_rpc_session_handle_t session,
+                                           hal_rpc_hash_handle_t *hash,
+                                           const hal_digest_algorithm_t alg,
+                                           const uint8_t * const key, const size_t key_length);
+
+extern hal_error_t hal_rpc_hash_update(const hal_rpc_hash_handle_t hash,
+                                       const uint8_t * data, const size_t length);
+
+extern hal_error_t hal_rpc_hash_finalize(const hal_rpc_hash_handle_t hash,
+                                         uint8_t *digest, const size_t length);
+
+/*
+ * Public key functions.
+ *
+ * The _sign() and _verify() methods accept a hash OR an input string;
+ * either "hash" should be hal_rpc_hash_handle_none or input should be NULL,
+ * but not both.
+ *
+ * Use of client and session handles here needs a bit more thought.
+ *
+ * Client handles are straightforward: basically, anything that
+ * creates a new pkey handle should take a client handle, which should
+ * suffice, as object handles never cross clients.
+ *
+ * Session handles are more interesting, as PKCS #11's versions of
+ * session and object handles do in effect allow one session to hand
+ * an object handle to another session.  So any action which can do
+ * significant work (ie, which is complicated enough that we can't
+ * guarantee an immediate response) needs to take a session handle.
+ *
+ * There will probably be a few cases where a session handle isn't
+ * strictly required but we ask for one anyway because the API turns
+ * out to be easier to understand that way (eg, we probably want to
+ * ask for a session handle anywhere we ask for a client handle,
+ * whether we need the session handle or not, so that users of this
+ * API don't have to remember which pkey-handle-creating calls require
+ * a session handle and which ones don't...).
+ */
+
+#define	HAL_RPC_PKEY_NAME_MAX 128
+
+typedef struct { uint32_t handle; } hal_rpc_pkey_handle_t;
+
+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)
+
+extern hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client,
+                                     const hal_rpc_session_handle_t session,
+                                     hal_rpc_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,
+                                     const uint8_t * const der, const size_t der_len,
+                                     const hal_key_flags_t flags);
+
+extern hal_error_t hal_rpc_pkey_find(const hal_rpc_client_handle_t client,
+                                     const hal_rpc_session_handle_t session,
+                                     hal_rpc_pkey_handle_t *pkey,
+                                     const hal_key_type_t type,
+                                     const uint8_t * const name, const size_t name_len);
+
+extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_rpc_client_handle_t client,
+                                             const hal_rpc_session_handle_t session,
+                                             hal_rpc_pkey_handle_t *pkey,
+                                             const uint8_t * const name, const size_t name_len,
+                                             const unsigned key_length,
+                                             const uint8_t * const public_exponent, const size_t public_exponent_len,
+                                             const hal_key_flags_t flags);
+
+extern hal_error_t hal_rpc_pkey_generate_ec(const hal_rpc_client_handle_t client,
+                                            const hal_rpc_session_handle_t session,
+                                            hal_rpc_pkey_handle_t *pkey,
+                                            const uint8_t * const name, const size_t name_len,
+                                            const hal_curve_name_t curve,
+                                            const hal_key_flags_t flags);
+
+extern hal_error_t hal_rpc_pkey_close(const hal_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_delete(const hal_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
+                                             hal_key_type_t *type);
+
+extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
+                                              hal_key_flags_t *flags);
+
+extern size_t hal_rpc_pkey_get_public_key_len(const hal_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_get_public_key(const hal_rpc_pkey_handle_t pkey,
+                                               uint8_t *der, size_t *der_len, const size_t der_len_max);
+
+extern hal_error_t hal_rpc_pkey_sign(const hal_rpc_session_handle_t session,
+                                     const hal_rpc_pkey_handle_t pkey,
+                                     const hal_rpc_hash_handle_t hash,
+                                     const uint8_t * const input,  const size_t input_len,
+                                     uint8_t * signature, size_t *signature_len, const size_t signature_max);
+
+extern hal_error_t hal_rpc_pkey_verify(const hal_rpc_session_handle_t session,
+                                       const hal_rpc_pkey_handle_t pkey,
+                                       const hal_rpc_hash_handle_t hash,
+                                       const uint8_t * const input, const size_t input_len,
+                                       const uint8_t * const signature, const size_t signature_len);
+
+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_rpc_pkey_key_info_t;
+
+extern hal_error_t hal_rpc_pkey_list(hal_rpc_pkey_key_info_t *result,
+                                     unsigned *result_len,
+                                     const unsigned result_max);
+
 #endif /* _HAL_H_ */
 
 /*
diff --git a/rpc_internal.h b/hal_internal.h
similarity index 62%
rename from rpc_internal.h
rename to hal_internal.h
index b861ec7..3f7f600 100644
--- a/rpc_internal.h
+++ b/hal_internal.h
@@ -1,7 +1,7 @@
 /*
- * rpc_internal.h
+ * hal_internal.h
  * --------------
- * Internal (not public API) declarations for HAL RPC mechanism.
+ * Internal API declarations for libhal.
  *
  * Authors: Rob Austein, Paul Selkirk
  * Copyright (c) 2015, NORDUnet A/S All rights reserved.
@@ -33,10 +33,10 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _HAL_RPC_INTERNAL_H_
-#define _HAL_RPC_INTERNAL_H_
+#ifndef _HAL_INTERNAL_H_
+#define _HAL_INTERNAL_H_
 
-#include "hal_rpc.h"
+#include "hal.h"
 
 /*
  * Everything in this file is part of the internal API, that is,
@@ -119,16 +119,16 @@ typedef struct {
   hal_error_t  (*load)(const hal_rpc_client_handle_t client,
                        const hal_rpc_session_handle_t session,
                        hal_rpc_pkey_handle_t *pkey,
-                       const hal_rpc_pkey_key_type_t type,
-                       const hal_rpc_pkey_curve_t curve,
+                       const hal_key_type_t type,
+                       const hal_curve_name_t curve,
                        const uint8_t * const name, const size_t name_len,
                        const uint8_t * const der, const size_t der_len,
-                       const hal_rpc_pkey_flags_t flags);
+                       const hal_key_flags_t flags);
 
   hal_error_t  (*find)(const hal_rpc_client_handle_t client,
                        const hal_rpc_session_handle_t session,
                        hal_rpc_pkey_handle_t *pkey,
-                       const hal_rpc_pkey_key_type_t type,
+                       const hal_key_type_t type,
                        const uint8_t * const name, const size_t name_len);
 
   hal_error_t  (*generate_rsa)(const hal_rpc_client_handle_t client,
@@ -137,22 +137,24 @@ typedef struct {
                                const uint8_t * const name, const size_t name_len,
                                const unsigned key_length,
                                const uint8_t * const public_exponent, const size_t public_exponent_len,
-                               const hal_rpc_pkey_flags_t flags);
+                               const hal_key_flags_t flags);
 
   hal_error_t  (*generate_ec)(const hal_rpc_client_handle_t client,
                               const hal_rpc_session_handle_t session,
                               hal_rpc_pkey_handle_t *pkey,
                               const uint8_t * const name, const size_t name_len,
-                              const hal_rpc_pkey_curve_t curve,
-                              const hal_rpc_pkey_flags_t flags);
+                              const hal_curve_name_t curve,
+                              const hal_key_flags_t flags);
+
+  hal_error_t  (*close)(const hal_rpc_pkey_handle_t pkey);
 
   hal_error_t  (*delete)(const hal_rpc_pkey_handle_t pkey);
 
   hal_error_t  (*get_key_type)(const hal_rpc_pkey_handle_t pkey,
-                               hal_rpc_pkey_key_type_t *key_type);
+                               hal_key_type_t *key_type);
 
   hal_error_t  (*get_key_flags)(const hal_rpc_pkey_handle_t pkey,
-                                hal_rpc_pkey_flags_t *flags);
+                                hal_key_flags_t *flags);
 
   size_t (*get_public_key_len)(const hal_rpc_pkey_handle_t pkey);
 
@@ -163,13 +165,13 @@ typedef struct {
                        const hal_rpc_pkey_handle_t pkey,
                        const hal_rpc_hash_handle_t hash,
                        const uint8_t * const input,  const size_t input_len,
-                       uint8_t * output, const size_t output_len);
+                       uint8_t * signature, size_t *signature_len, const size_t signature_max);
 
   hal_error_t  (*verify)(const hal_rpc_session_handle_t session,
                          const hal_rpc_pkey_handle_t pkey,
                          const hal_rpc_hash_handle_t hash,
                          const uint8_t * const input, const size_t input_len,
-                         uint8_t * output, const size_t output_len);
+                         const uint8_t * const signature, const size_t signature_len);
 
   hal_error_t  (*list)(hal_rpc_pkey_key_info_t *result,
                        unsigned *result_len,
@@ -182,7 +184,108 @@ extern const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch, hal_rpc_remote
 extern const hal_rpc_hash_dispatch_t hal_rpc_local_hash_dispatch, hal_rpc_remote_hash_dispatch;
 extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote_pkey_dispatch, hal_rpc_mixed_pkey_dispatch;
 
-#endif /* _HAL_RPC_INTERNAL_H_ */
+/*
+ * 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 unneded space in the case of EC keys.
+ *
+ * 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:
+ *
+ * 2048-bit RSA:        1194 bytes
+ * 4096-bit RSA:        2351 bytes
+ * 8192-bit RSA:	4655 bytes
+ * EC P-256:		 121 bytes
+ * EC P-384:		 167 bytes
+ * EC P-521:             223 bytes
+ *
+ * Plus we need a bit of AES-keywrap overhead, since we're storing the
+ * wrapped form (see hal_aes_keywrap_cyphertext_length()).
+ */
+
+#define	HAL_KS_WRAPPED_KEYSIZE  ((4655 + 15) & ~7)
+
+#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
+#define HAL_STATIC_PKEY_STATE_BLOCKS 0
+#endif
+
+typedef struct {
+  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;
+  uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
+  size_t der_len;
+  uint8_t in_use;
+} hal_ks_key_t;
+
+typedef struct {
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+  hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
+#endif
+} hal_ks_keydb_t;
+
+/*
+ * 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);
+
+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);
+
+/*
+ * Keystore API for use by the pkey implementation.
+ *
+ * In an attempt to emulate what current theory says will eventually
+ * be the behavior of the underlying Cryptech Verilog "hardware",
+ * these functions automatically apply the AES keywrap transformations.
+ *
+ * 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.
+ */
+
+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_list(hal_rpc_pkey_key_info_t *result,
+                               unsigned *result_len,
+                               const unsigned result_max);
+
+#endif /* _HAL_INTERNAL_H_ */
 
 /*
  * Local variables:
diff --git a/hal_rpc.h b/hal_rpc.h
deleted file mode 100644
index 553fb6b..0000000
--- a/hal_rpc.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * hal_rpc.h
- * ---------
- * Remote procedure call API to extrude libhal across the green/yellow boundary.
- *
- * Authors: Rob Austein, Paul Selkirk
- * Copyright (c) 2015, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- *   be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _HAL_RPC_H_
-#define _HAL_RPC_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include "hal.h"
-
-/*
- * Session handles are pretty much as in PKCS #11: from our viewpoint,
- * a session is a lock-step stream of operations, so while operations
- * from different sessions can interleave, operations within a single
- * session cannot.
- *
- * Client handles are a small extension to the PKCS #11 model,
- * intended to support multiple PKCS #11 using applications sharing a
- * single HSM.  Technically, sessions are per-client, but in practice
- * there's no sane reason why we'd use the same session handle
- * concurrently in multiple clients.  Mostly, the client abstraction
- * is to handle login and logout against the HSM's PIN.  Clients add
- * nothing whatsoever to the security model (the HSM has no way of
- * knowing whether the host is lumping multiple applications into a
- * single "client"), the point of the exercise is just to make the
- * C_Login()/C_Logout() semantics work as expected in the presence of
- * multiple applications.
- *
- * NB: Unlike other handles used in this protocol, session and client
- * handles are created by the client (host) side of the RPC mechanism,
- * not the server (HSM) side.
- */
-
-typedef struct { uint32_t handle; } hal_rpc_client_handle_t;
-typedef struct { uint32_t handle; } hal_rpc_session_handle_t;
-
-typedef enum { HAL_RPC_USER_NONE, HAL_RPC_USER_NORMAL, HAL_RPC_USER_SO } hal_rpc_user_t;
-
-extern hal_error_t hal_rpc_set_pin(const hal_rpc_user_t which,
-                                   const char * const newpin, const size_t newpin_len);
-
-extern hal_error_t hal_rpc_login(const hal_rpc_client_handle_t client,
-                                 const hal_rpc_user_t user,
-                                 const char * const pin, const size_t pin_len);
-
-extern hal_error_t hal_rpc_logout(const hal_rpc_client_handle_t client);
-
-/*
- * Get random bytes.
- */
-
-extern hal_error_t hal_rpc_get_random(void *buffer, const size_t length);
-
-/*
- * Combined hash and HMAC functions: pass NULL key for plain hashing.
- */
-
-typedef struct { uint32_t handle; } hal_rpc_hash_handle_t;
-
-extern const hal_rpc_hash_handle_t hal_rpc_hash_handle_none;
-
-extern hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, size_t *length);
-
-extern hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg,
-                                                        uint8_t *id, size_t *len, const size_t len_max);
-
-extern hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg);
-
-/*
- * Once started, a hash or HMAC operation is bound to a particular
- * session, so we only need the client and session arguments to initialize.
- */
-
-extern hal_error_t hal_rpc_hash_initialize(const hal_rpc_client_handle_t client,
-                                           const hal_rpc_session_handle_t session,
-                                           hal_rpc_hash_handle_t *hash,
-                                           const hal_digest_algorithm_t alg,
-                                           const uint8_t * const key, const size_t key_length);
-
-extern hal_error_t hal_rpc_hash_update(const hal_rpc_hash_handle_t hash,
-                                       const uint8_t * data, const size_t length);
-
-extern hal_error_t hal_rpc_hash_finalize(const hal_rpc_hash_handle_t hash,
-                                         uint8_t *digest, const size_t length);
-
-/*
- * Public key functions.
- *
- * The _sign() and _verify() methods accept a hash OR an input string;
- * either "hash" should be hal_rpc_hash_handle_none or input should be NULL,
- * but not both.
- *
- * Use of client and session handles here needs a bit more thought.
- *
- * Client handles are straightforward: basically, anything that
- * creates a new pkey handle should take a client handle, which should
- * suffice, as object handles never cross clients.
- *
- * Session handles are more interesting, as PKCS #11's versions of
- * session and object handles do in effect allow one session to hand
- * an object handle to another session.  So any action which can do
- * significant work (ie, which is complicated enough that we can't
- * guarantee an immediate response) needs to take a session handle.
- *
- * There will probably be a few cases where a session handle isn't
- * strictly required but we ask for one anyway because the API turns
- * out to be easier to understand that way (eg, we probably want to
- * ask for a session handle anywhere we ask for a client handle,
- * whether we need the session handle or not, so that users of this
- * API don't have to remember which pkey-handle-creating calls require
- * a session handle and which ones don't...).
- */
-
-#define	HAL_RPC_PKEY_NAME_MAX 128
-
-typedef enum {
-  HAL_RPC_PKEY_RSA_PRIVATE,
-  HAL_RPC_PKEY_RSA_PUBLIC,
-  HAL_RPC_PKEY_ECDSA_PRIVATE,
-  HAL_RPC_PKEY_ECDSA_PUBLIC
-} hal_rpc_pkey_key_type_t;
-
-typedef enum {
-  HAL_RPC_PKEY_CURVE_NONE,
-  HAL_RPC_PKEY_CURVE_ECDSA_P256,
-  HAL_RPC_PKEY_CURVE_ECDSA_P384,
-  HAL_RPC_PKEY_CURVE_ECDSA_P521
-} hal_rpc_pkey_curve_t;
-
-typedef struct { uint32_t handle; } hal_rpc_pkey_handle_t;
-
-typedef uint32_t hal_rpc_pkey_flags_t;
-
-#define	HAL_RPC_PKEY_FLAG_USAGE_DIGITALSIGNATURE	(1 << 0)
-#define	HAL_RPC_PKEY_FLAG_USAGE_KEYENCIPHERMENT         (1 << 1)
-#define	HAL_RPC_PKEY_FLAG_USAGE_DATAENCIPHERMENT	(1 << 2)
-
-extern hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client,
-                                     const hal_rpc_session_handle_t session,
-                                     hal_rpc_pkey_handle_t *pkey,
-                                     const hal_rpc_pkey_key_type_t type,
-                                     const hal_rpc_pkey_curve_t curve,
-                                     const uint8_t * const name, const size_t name_len,
-                                     const uint8_t * const der, const size_t der_len,
-                                     const hal_rpc_pkey_flags_t flags);
-
-extern hal_error_t hal_rpc_pkey_find(const hal_rpc_client_handle_t client,
-                                     const hal_rpc_session_handle_t session,
-                                     hal_rpc_pkey_handle_t *pkey,
-                                     const hal_rpc_pkey_key_type_t type,
-                                     const uint8_t * const name, const size_t name_len);
-
-extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_rpc_client_handle_t client,
-                                             const hal_rpc_session_handle_t session,
-                                             hal_rpc_pkey_handle_t *pkey,
-                                             const uint8_t * const name, const size_t name_len,
-                                             const unsigned key_length,
-                                             const uint8_t * const public_exponent, const size_t public_exponent_len,
-                                             const hal_rpc_pkey_flags_t flags);
-
-extern hal_error_t hal_rpc_pkey_generate_ec(const hal_rpc_client_handle_t client,
-                                            const hal_rpc_session_handle_t session,
-                                            hal_rpc_pkey_handle_t *pkey,
-                                            const uint8_t * const name, const size_t name_len,
-                                            const hal_rpc_pkey_curve_t curve,
-                                            const hal_rpc_pkey_flags_t flags);
-
-extern hal_error_t hal_rpc_pkey_delete(const hal_rpc_pkey_handle_t pkey);
-
-extern hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
-                                             hal_rpc_pkey_key_type_t *type);
-
-extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
-                                              hal_rpc_pkey_flags_t *flags);
-
-extern size_t hal_rpc_pkey_get_public_key_len(const hal_rpc_pkey_handle_t pkey);
-
-extern hal_error_t hal_rpc_pkey_get_public_key(const hal_rpc_pkey_handle_t pkey,
-                                               uint8_t *der, size_t *der_len, const size_t der_len_max);
-
-extern hal_error_t hal_rpc_pkey_sign(const hal_rpc_session_handle_t session,
-                                     const hal_rpc_pkey_handle_t pkey,
-                                     const hal_rpc_hash_handle_t hash,
-                                     const uint8_t * const input,  const size_t input_len,
-                                     uint8_t * output, const size_t output_len);
-
-extern hal_error_t hal_rpc_pkey_verify(const hal_rpc_session_handle_t session,
-                                       const hal_rpc_pkey_handle_t pkey,
-                                       const hal_rpc_hash_handle_t hash,
-                                       const uint8_t * const input, const size_t input_len,
-                                       uint8_t * output, const size_t output_len);
-
-typedef struct {
-  hal_rpc_pkey_key_type_t type;
-  hal_rpc_pkey_curve_t curve;
-  hal_rpc_pkey_flags_t flags;
-  char name[HAL_RPC_PKEY_NAME_MAX];
-  /* ... */
-} hal_rpc_pkey_key_info_t;
-
-extern hal_error_t hal_rpc_pkey_list(hal_rpc_pkey_key_info_t *result,
-                                     unsigned *result_len,
-                                     const unsigned result_max);
-
-#endif /* _HAL_RPC_H_ */
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/ks.c b/ks.c
new file mode 100644
index 0000000..072c624
--- /dev/null
+++ b/ks.c
@@ -0,0 +1,280 @@
+/*
+ * ks.c
+ * ----
+ * Keystore API.  This is internal within libhal.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+#define KEK_LENGTH (bitsToBytes(256))
+
+static inline int acceptable_key_type(const hal_key_type_t type)
+{
+  switch (type) {
+  case HAL_KEY_TYPE_RSA_PRIVATE:
+  case HAL_KEY_TYPE_RSA_PUBLIC:
+  case HAL_KEY_TYPE_EC_PRIVATE:
+  case HAL_KEY_TYPE_EC_PUBLIC:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+hal_error_t hal_ks_store(const hal_key_type_t type,
+                         const hal_curve_name_t curve,
+                         const hal_key_flags_t flags,
+                         const uint8_t * const name, const size_t name_len,
+                         const uint8_t * const der,  const size_t der_len,
+                         int *hint)
+{
+  if (name == NULL || name_len == 0 || der == NULL || der_len == 0 || !acceptable_key_type(type))
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  if (name_len > HAL_RPC_PKEY_NAME_MAX)
+    return HAL_ERROR_RESULT_TOO_LONG;
+
+  const hal_ks_keydb_t * const db = hal_ks_get_keydb();
+  hal_error_t err;
+  int hint_;
+
+  if (db == NULL)
+    return HAL_ERROR_KEYSTORE_ACCESS;
+
+  if (hint == NULL)
+    hint = &hint_;
+
+  *hint = -1;
+
+  for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) {
+    if (!db->keys[i].in_use && *hint < 0)
+      *hint = i;
+    if (db->keys[i].in_use &&
+        db->keys[i].type == type &&
+        db->keys[i].name_len == name_len && memcmp(db->keys[i].name, name, name_len) == 0)
+      return HAL_ERROR_KEY_NAME_IN_USE;
+  }
+
+  if (*hint < 0)
+    return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;    
+
+  hal_ks_key_t k;
+  memset(&k, 0, sizeof(k));
+
+  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;
+  
+  assert(name_len <= sizeof(k.name));
+  memcpy(k.name, name, name_len);
+  k.name_len = name_len;
+  k.type = type;
+  k.curve = curve;
+  k.flags = flags;
+
+  if ((err = hal_ks_set_keydb(&k, *hint)) != HAL_OK)
+    return err;
+
+  return HAL_OK;
+}
+
+static int find(const hal_ks_keydb_t * const db,
+                const hal_key_type_t type,
+                const uint8_t * const name, const size_t name_len,
+                int *hint)
+{
+  assert(db != NULL && name != NULL && name_len > 0 && acceptable_key_type(type));
+
+  if (hint != NULL && *hint >= 0 && *hint < sizeof(db->keys)/sizeof(*db->keys) &&
+      db->keys[*hint].in_use &&
+      db->keys[*hint].type == type &&
+      db->keys[*hint].name_len == name_len && memcmp(db->keys[*hint].name, name, name_len) == 0)
+    return 1;
+
+  for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) {
+    if (!db->keys[i].in_use ||
+        (hint != NULL && i == *hint) ||
+        db->keys[i].type != type ||
+        db->keys[i].name_len != name_len || memcmp(db->keys[i].name, name, name_len) != 0)
+      continue;
+    if (hint != NULL)
+      *hint = i;
+    return 1;
+  }
+
+  return 0;
+}
+
+hal_error_t hal_ks_exists(const hal_key_type_t type,
+                          const uint8_t * const name, const size_t name_len,
+                          int *hint)
+{
+  if (name == NULL || name_len == 0 || !acceptable_key_type(type))
+    return HAL_ERROR_BAD_ARGUMENTS;
+  
+  const hal_ks_keydb_t * const db = hal_ks_get_keydb();
+
+  if (db == NULL)
+    return HAL_ERROR_KEYSTORE_ACCESS;
+
+  if (find(db, type, name, name_len, hint))
+    return HAL_OK;
+  else
+    return HAL_ERROR_KEY_NOT_FOUND;
+}
+
+hal_error_t hal_ks_fetch(const hal_key_type_t type,
+                         const uint8_t * const name, const size_t name_len,
+                         hal_curve_name_t *curve,
+                         hal_key_flags_t *flags,
+                         uint8_t *der, size_t *der_len, const size_t der_max,
+                         int *hint)
+{
+  if (name == NULL || name_len == 0 || !acceptable_key_type(type))
+    return HAL_ERROR_BAD_ARGUMENTS;
+  
+  const hal_ks_keydb_t * const db = hal_ks_get_keydb();
+  int hint_ = -1;
+  
+  if (db == NULL)
+    return HAL_ERROR_KEYSTORE_ACCESS;
+
+  if (hint == NULL)
+    hint = &hint_;
+
+  if (!find(db, type, name, name_len, hint))
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  const hal_ks_key_t * const k = &db->keys[*hint];
+
+  if (curve != NULL)
+    *curve = k->curve;
+
+  if (flags != NULL)
+    *flags = k->flags;
+
+  if (der == NULL && der_len != NULL)
+    *der_len = k->der_len;
+
+  if (der != NULL) {
+    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;
+  }
+
+  return HAL_OK;
+}
+
+hal_error_t hal_ks_delete(const hal_key_type_t type,
+                          const uint8_t * const name, const size_t name_len,
+                          int *hint)
+{
+  if (name == NULL || name_len == 0 || !acceptable_key_type(type))
+    return HAL_ERROR_BAD_ARGUMENTS;
+  
+  const hal_ks_keydb_t * const db = hal_ks_get_keydb();
+  int hint_ = -1;
+  
+  if (db == NULL)
+    return HAL_ERROR_KEYSTORE_ACCESS;
+
+  if (hint == NULL)
+    hint = &hint_;
+
+  if (!find(db, type, name, name_len, hint))
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  return hal_ks_del_keydb(*hint);
+}
+
+hal_error_t hal_ks_list(hal_rpc_pkey_key_info_t *result,
+                        unsigned *result_len,
+                        const unsigned result_max)
+{
+  if (result == NULL || result_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  const hal_ks_keydb_t * const db = hal_ks_get_keydb();
+  
+  if (db == NULL)
+    return HAL_ERROR_KEYSTORE_ACCESS;
+
+  *result_len = 0;
+
+  for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) {
+
+    if (!db->keys[i].in_use)
+      continue;
+
+    if (*result_len == result_max)
+      return HAL_ERROR_RESULT_TOO_LONG;
+
+    result[*result_len].type = db->keys[i].type;
+    result[*result_len].curve = db->keys[i].curve;
+    result[*result_len].flags = db->keys[i].flags;
+    result[*result_len].name_len = db->keys[i].name_len;
+    memcpy(result[*result_len].name, db->keys[i].name, db->keys[i].name_len);
+    ++result_len;
+  }
+
+  return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_flash.c b/ks_flash.c
new file mode 100644
index 0000000..ad9d2fe
--- /dev/null
+++ b/ks_flash.c
@@ -0,0 +1,71 @@
+/*
+ * ks_flash.c
+ * ----------
+ * Keystore implementation in flash memory.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hal.h"
+#include "hal_internal.h"
+
+static hal_ks_keydb_t *db;
+
+const hal_ks_keydb_t *hal_ks_get_keydb(void)
+{
+
+#error Not sure what goes here yet
+
+}
+
+hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
+                             const int loc)
+{
+  if (key == NULL || loc < 0 || loc >= sizeof(db.keys)/sizeof(*db.keys) || key->in_use)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+#error Not sure what goes here yet either
+
+}
+
+hal_error_t hal_ks_del_keydb(const int loc)
+{
+  if (loc < 0 || loc >= sizeof(db.keys)/sizeof(*db.keys))
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+#error Or what goes here
+
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_mmap.c b/ks_mmap.c
new file mode 100644
index 0000000..3ff06a3
--- /dev/null
+++ b/ks_mmap.c
@@ -0,0 +1,115 @@
+/*
+ * ks_mmap.c
+ * ---------
+ * Keystore implementation over POSIX mmap().
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+#ifndef HAL_KS_MMAP_FILE
+#define HAL_KS_MMAP_FILE ".cryptech_hal_keystore"
+#endif
+
+static hal_ks_keydb_t *db;
+
+const hal_ks_keydb_t *hal_ks_get_keydb(void)
+{
+  if (db != NULL)
+    return db;
+
+  const char * const env  = getenv("CRYPTECH_KEYSTORE");
+  const char * const home = getenv("HOME");
+  const char * const base = HAL_KS_MMAP_FILE;
+  const unsigned pagemask = getpagesize() - 1;
+  const size_t len = (sizeof(hal_ks_keydb_t) + pagemask) & ~pagemask;
+
+  char fn_[strlen(base) + (home == NULL ? 0 : strlen(home)) + 2];
+  const char *fn = fn_;
+  int fd;
+
+  if (env != NULL)
+    fn = env;
+  else if (home == NULL)
+    fn = base;
+  else
+    strcat(strcat(strcpy(fn_, home), "/"), base);
+    
+  if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) {
+    uint8_t zeros[len];
+    memset(zeros, 0, sizeof(zeros));
+    (void) write(fd, zeros, sizeof(zeros));
+  }
+  else if (errno == EEXIST) {
+    fd = open(fn, O_RDWR | O_CREAT, 0600);
+  }
+
+  if (fd >= 0)
+    db = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
+
+  (void) close(fd);
+
+  return db;
+}
+
+hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
+                             const int loc)
+{
+  if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || key->in_use)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  db->keys[loc] = *key;
+  db->keys[loc].in_use = 1;
+  return HAL_OK;
+}
+
+hal_error_t hal_ks_del_keydb(const int loc)
+{
+  if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  db->keys[loc].in_use = 0;
+  memset(&db->keys[loc], 0, sizeof(db->keys[loc]));
+  return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_volatile.c b/ks_volatile.c
new file mode 100644
index 0000000..756cd13
--- /dev/null
+++ b/ks_volatile.c
@@ -0,0 +1,74 @@
+/*
+ * ks_volatile.c
+ * -------------
+ * Keystore implementation in normal volatile internal memory.
+ *
+ * NB: This is only suitable for cases where you do not want the keystore
+ *     to survive library exit, eg, for storing PKCS #11 session keys.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hal.h"
+#include "hal_internal.h"
+
+static hal_ks_keydb_t db;
+
+const hal_ks_keydb_t *hal_ks_get_keydb(void)
+{
+  return &db;
+}
+
+hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
+                             const int loc)
+{
+  if (key == NULL || loc < 0 || loc >= sizeof(db.keys)/sizeof(*db.keys) || key->in_use)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  db.keys[loc] = *key;
+  db.keys[loc].in_use = 1;
+  return HAL_OK;
+}
+
+hal_error_t hal_ks_del_keydb(const int loc)
+{
+  if (loc < 0 || loc >= sizeof(db.keys)/sizeof(*db.keys))
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  memset(&db.keys[loc], 0, sizeof(db.keys[loc]));
+  return HAL_OK;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/hal_rpc.c b/rpc.c
similarity index 84%
rename from hal_rpc.c
rename to rpc.c
index 6ad198e..e0cb869 100644
--- a/hal_rpc.c
+++ b/rpc.c
@@ -33,7 +33,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "rpc_internal.h"
+#include "hal.h"
+#include "hal_internal.h"
 
 #ifndef HAL_RPC_IS_CLIENT
 #warning HAL_RPC_IS_CLIENT not set, assuming we're building for the HSM
@@ -63,45 +64,45 @@ static const hal_rpc_pkey_dispatch_t * const pkey_dispatch = &hal_rpc_local_pkey
 
 const hal_rpc_hash_handle_t hal_rpc_hash_handle_none = {0};
 
-static inline int check_pkey_type(const hal_rpc_pkey_key_type_t type)
+static inline int check_pkey_type(const hal_key_type_t type)
 {
   switch (type) {
-  case HAL_RPC_PKEY_RSA_PRIVATE:
-  case HAL_RPC_PKEY_RSA_PUBLIC:
-  case HAL_RPC_PKEY_ECDSA_PRIVATE:
-  case HAL_RPC_PKEY_ECDSA_PUBLIC:
+  case HAL_KEY_TYPE_RSA_PRIVATE:
+  case HAL_KEY_TYPE_RSA_PUBLIC:
+  case HAL_KEY_TYPE_EC_PRIVATE:
+  case HAL_KEY_TYPE_EC_PUBLIC:
     return 1;
   default:
     return 0;
   }
 }
 
-static inline int check_pkey_flags(const hal_rpc_pkey_flags_t flags)
+static inline int check_pkey_flags(const hal_key_flags_t flags)
 {
-  return (flags &~ (HAL_RPC_PKEY_FLAG_USAGE_DIGITALSIGNATURE |
-		    HAL_RPC_PKEY_FLAG_USAGE_KEYENCIPHERMENT  |
-		    HAL_RPC_PKEY_FLAG_USAGE_DATAENCIPHERMENT)) == 0;
+  return (flags &~ (HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE |
+		    HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT  |
+		    HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT)) == 0;
 }
 
-static inline int check_pkey_type_curve_flags(const hal_rpc_pkey_key_type_t type,
-					      const hal_rpc_pkey_curve_t curve,
-					      const hal_rpc_pkey_flags_t flags)
+static inline int check_pkey_type_curve_flags(const hal_key_type_t type,
+					      const hal_curve_name_t curve,
+					      const hal_key_flags_t flags)
 {
   if (!check_pkey_flags(flags))
     return 0;
 
   switch (type) {
 
-  case HAL_RPC_PKEY_RSA_PRIVATE:
-  case HAL_RPC_PKEY_RSA_PUBLIC:
-    return curve == HAL_RPC_PKEY_CURVE_NONE;
+  case HAL_KEY_TYPE_RSA_PRIVATE:
+  case HAL_KEY_TYPE_RSA_PUBLIC:
+    return curve == HAL_CURVE_NONE;
 
-  case HAL_RPC_PKEY_ECDSA_PRIVATE:
-  case HAL_RPC_PKEY_ECDSA_PUBLIC:
+  case HAL_KEY_TYPE_EC_PRIVATE:
+  case HAL_KEY_TYPE_EC_PUBLIC:
     switch (curve) {
-    case HAL_RPC_PKEY_CURVE_ECDSA_P256:
-    case HAL_RPC_PKEY_CURVE_ECDSA_P384:
-    case HAL_RPC_PKEY_CURVE_ECDSA_P521:
+    case HAL_CURVE_P256:
+    case HAL_CURVE_P384:
+    case HAL_CURVE_P521:
       return 1;
     default:
       return 0;
@@ -198,11 +199,11 @@ hal_error_t hal_rpc_hash_finalize(const hal_rpc_hash_handle_t hash,
 hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client,
 			      const hal_rpc_session_handle_t session,
 			      hal_rpc_pkey_handle_t *pkey,
-			      const hal_rpc_pkey_key_type_t type,
-			      const hal_rpc_pkey_curve_t curve,
+			      const hal_key_type_t type,
+			      const hal_curve_name_t curve,
 			      const uint8_t * const name, const size_t name_len,
 			      const uint8_t * const der, const size_t der_len,
-			      const hal_rpc_pkey_flags_t flags)
+			      const hal_key_flags_t flags)
 {
   if (pkey == NULL ||
       name == NULL || name_len == 0 ||
@@ -215,7 +216,7 @@ hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client,
 hal_error_t hal_rpc_pkey_find(const hal_rpc_client_handle_t client,
 			      const hal_rpc_session_handle_t session,
 			      hal_rpc_pkey_handle_t *pkey,
-			      const hal_rpc_pkey_key_type_t type,
+			      const hal_key_type_t type,
 			      const uint8_t * const name, const size_t name_len)
 {
   if (pkey == NULL || name == NULL || name_len == 0 || !check_pkey_type(type))
@@ -229,9 +230,9 @@ hal_error_t hal_rpc_pkey_generate_rsa(const hal_rpc_client_handle_t client,
 				      const uint8_t * const name, const size_t name_len,
 				      const unsigned key_len,
 				      const uint8_t * const exp, const size_t exp_len,
-				      const hal_rpc_pkey_flags_t flags)
+				      const hal_key_flags_t flags)
 {
-  if (pkey == NULL || name == NULL || name_len == 0 || key_len == 0 ||
+  if (pkey == NULL || name == NULL || name_len == 0 || key_len == 0 || (key_len & 7) != 0 ||
       exp == NULL || exp_len == 0 || !check_pkey_flags(flags))
     return HAL_ERROR_BAD_ARGUMENTS;
   return pkey_dispatch->generate_rsa(client, session, pkey, name, name_len, key_len, exp, exp_len, flags);
@@ -241,22 +242,27 @@ hal_error_t hal_rpc_pkey_generate_ec(const hal_rpc_client_handle_t client,
 				     const hal_rpc_session_handle_t session,
 				     hal_rpc_pkey_handle_t *pkey,
 				     const uint8_t * const name, const size_t name_len,
-				     const hal_rpc_pkey_curve_t curve,
-				     const hal_rpc_pkey_flags_t flags)
+				     const hal_curve_name_t curve,
+				     const hal_key_flags_t flags)
 {
   if (pkey == NULL || name == NULL || name_len == 0 ||
-      !check_pkey_type_curve_flags(HAL_RPC_PKEY_ECDSA_PRIVATE, curve, flags))
+      !check_pkey_type_curve_flags(HAL_KEY_TYPE_EC_PRIVATE, curve, flags))
     return HAL_ERROR_BAD_ARGUMENTS;
   return pkey_dispatch->generate_ec(client, session, pkey, name, name_len, curve, flags);
 }
 
+hal_error_t hal_rpc_pkey_close(const hal_rpc_pkey_handle_t pkey)
+{
+  return pkey_dispatch->close(pkey);
+}
+
 hal_error_t hal_rpc_pkey_delete(const hal_rpc_pkey_handle_t pkey)
 {
   return pkey_dispatch->delete(pkey);
 }
 
 hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
-				      hal_rpc_pkey_key_type_t *type)
+				      hal_key_type_t *type)
 {
   if (type == NULL)
     return HAL_ERROR_BAD_ARGUMENTS;
@@ -264,7 +270,7 @@ hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
 }
 
 hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
-				       hal_rpc_pkey_flags_t *flags)
+				       hal_key_flags_t *flags)
 {
   if (flags == NULL)
     return HAL_ERROR_BAD_ARGUMENTS;
@@ -288,24 +294,24 @@ hal_error_t hal_rpc_pkey_sign(const hal_rpc_session_handle_t session,
 			      const hal_rpc_pkey_handle_t pkey,
 			      const hal_rpc_hash_handle_t hash,
 			      const uint8_t * const input,  const size_t input_len,
-			      uint8_t * output, const size_t output_len)
+			      uint8_t * signature, size_t *signature_len, const size_t signature_max)
 {
-  if (output == NULL || output_len == 0 ||
+  if (signature == NULL || signature_len == NULL || signature_max == 0 ||
       (hash.handle == hal_rpc_hash_handle_none.handle) == (input == NULL || input_len == 0))
     return HAL_ERROR_BAD_ARGUMENTS;
-  return pkey_dispatch->sign(session, pkey, hash, input,  input_len, output, output_len);
+  return pkey_dispatch->sign(session, pkey, hash, input,  input_len, signature, signature_len, signature_max);
 }
 
 hal_error_t hal_rpc_pkey_verify(const hal_rpc_session_handle_t session,
 				const hal_rpc_pkey_handle_t pkey,
 				const hal_rpc_hash_handle_t hash,
 				const uint8_t * const input, const size_t input_len,
-				uint8_t * output, const size_t output_len)
+				const uint8_t * const signature, const size_t signature_len)
 {
-  if (output == NULL || output_len == 0 ||
+  if (signature == NULL || signature_len == 0 ||
       (hash.handle == hal_rpc_hash_handle_none.handle) == (input == NULL || input_len == 0))
     return HAL_ERROR_BAD_ARGUMENTS;
-  return pkey_dispatch->verify(session, pkey, hash, input, input_len, output, output_len);
+  return pkey_dispatch->verify(session, pkey, hash, input, input_len, signature, signature_len);
 }
 
 hal_error_t hal_rpc_pkey_list(hal_rpc_pkey_key_info_t *result,
diff --git a/rpc_client.c b/rpc_client.c
index 20cc26f..0b13e58 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -33,7 +33,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "rpc_internal.h"
+#include "hal.h"
+#include "hal_internal.h"
 
 /*
  * RPC calls.  Not implemented yet.
@@ -104,11 +105,11 @@ static hal_error_t hash_finalize(const hal_rpc_hash_handle_t hash,
 static hal_error_t pkey_load(const hal_rpc_client_handle_t client,
                              const hal_rpc_session_handle_t session,
                              hal_rpc_pkey_handle_t *pkey,
-                             const hal_rpc_pkey_key_type_t type,
-                             const hal_rpc_pkey_curve_t curve,
+                             const hal_key_type_t type,
+                             const hal_curve_name_t curve,
                              const uint8_t * const name, const size_t name_len,
                              const uint8_t * const der, const size_t der_len,
-                             const hal_rpc_pkey_flags_t flags)
+                             const hal_key_flags_t flags)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -116,7 +117,7 @@ static hal_error_t pkey_load(const hal_rpc_client_handle_t client,
 static hal_error_t pkey_find(const hal_rpc_client_handle_t client,
                              const hal_rpc_session_handle_t session,
                              hal_rpc_pkey_handle_t *pkey,
-                             const hal_rpc_pkey_key_type_t type,
+                             const hal_key_type_t type,
                              const uint8_t * const name, const size_t name_len)
 {
   return HAL_ERROR_IMPOSSIBLE;
@@ -128,7 +129,7 @@ static hal_error_t pkey_generate_rsa(const hal_rpc_client_handle_t client,
                                      const uint8_t * const name, const size_t name_len,
                                      const unsigned key_len,
                                      const uint8_t * const exp, const size_t exp_len,
-                                     const hal_rpc_pkey_flags_t flags)
+                                     const hal_key_flags_t flags)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -137,8 +138,13 @@ static hal_error_t pkey_generate_ec(const hal_rpc_client_handle_t client,
                                     const hal_rpc_session_handle_t session,
                                     hal_rpc_pkey_handle_t *pkey,
                                     const uint8_t * const name, const size_t name_len,
-                                    const hal_rpc_pkey_curve_t curve,
-                                    const hal_rpc_pkey_flags_t flags)
+                                    const hal_curve_name_t curve,
+                                    const hal_key_flags_t flags)
+{
+  return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_close(const hal_rpc_pkey_handle_t pkey)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -149,13 +155,13 @@ static hal_error_t pkey_delete(const hal_rpc_pkey_handle_t pkey)
 }
 
 static hal_error_t pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
-                                     hal_rpc_pkey_key_type_t *type)
+                                     hal_key_type_t *type)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
 
 static hal_error_t pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
-                                      hal_rpc_pkey_flags_t *flags)
+                                      hal_key_flags_t *flags)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -175,7 +181,7 @@ static hal_error_t pkey_remote_sign(const hal_rpc_session_handle_t session,
                                     const hal_rpc_pkey_handle_t pkey,
                                     const hal_rpc_hash_handle_t hash,
                                     const uint8_t * const input,  const size_t input_len,
-                                    uint8_t * output, const size_t output_len)
+                                    uint8_t * signature, size_t *signature_len, const size_t signature_max)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -184,7 +190,7 @@ static hal_error_t pkey_remote_verify(const hal_rpc_session_handle_t session,
                                       const hal_rpc_pkey_handle_t pkey,
                                       const hal_rpc_hash_handle_t hash,
                                       const uint8_t * const input, const size_t input_len,
-                                      uint8_t * output, const size_t output_len)
+                                      const uint8_t * const signature, const size_t signature_len)
 {
   return HAL_ERROR_IMPOSSIBLE;
 }
@@ -208,10 +214,11 @@ static hal_error_t pkey_mixed_sign(const hal_rpc_session_handle_t session,
                                    const hal_rpc_pkey_handle_t pkey,
                                    const hal_rpc_hash_handle_t hash,
                                    const uint8_t * const input,  const size_t input_len,
-                                   uint8_t * output, const size_t output_len)
+                                   uint8_t * signature, size_t *signature_len, const size_t signature_max)
 {
   if (input != NULL)
-    return pkey_remote_sign(session, pkey, hash, input,  input_len, output, output_len);
+    return pkey_remote_sign(session, pkey, hash, input, input_len,
+                            signature, signature_len, signature_max);
 
   hal_digest_algorithm_t alg;
   size_t digest_len;
@@ -226,17 +233,19 @@ static hal_error_t pkey_mixed_sign(const hal_rpc_session_handle_t session,
   if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK)
     return err;
 
-  return pkey_remote_sign(session, pkey, hal_rpc_hash_handle_none, digest, digest_len, output, output_len);
+  return pkey_remote_sign(session, pkey, hal_rpc_hash_handle_none, digest, digest_len,
+                          signature, signature_len, signature_max);
 }
 
 static hal_error_t pkey_mixed_verify(const hal_rpc_session_handle_t session,
                                      const hal_rpc_pkey_handle_t pkey,
                                      const hal_rpc_hash_handle_t hash,
                                      const uint8_t * const input, const size_t input_len,
-                                     uint8_t * output, const size_t output_len)
+                                     const uint8_t * const signature, const size_t signature_len)
 {
   if (input != NULL)
-    return pkey_remote_verify(session, pkey, hash, input,  input_len, output, output_len);
+    return pkey_remote_verify(session, pkey, hash, input, input_len,
+                              signature, signature_len);
 
   hal_digest_algorithm_t alg;
   size_t digest_len;
@@ -251,7 +260,8 @@ static hal_error_t pkey_mixed_verify(const hal_rpc_session_handle_t session,
   if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK)
     return err;
 
-  return pkey_remote_verify(session, pkey, hal_rpc_hash_handle_none, digest, digest_len, output, output_len);
+  return pkey_remote_verify(session, pkey, hal_rpc_hash_handle_none, digest, digest_len,
+                            signature, signature_len);
 }
 
 /*
@@ -263,18 +273,19 @@ const hal_rpc_misc_dispatch_t hal_rpc_remote_misc_dispatch = {
 };
 
 const hal_rpc_hash_dispatch_t hal_rpc_remote_hash_dispatch = {
-  hash_get_digest_len, hash_get_digest_algorithm_id, hash_get_algorithm, hash_initialize, hash_update, hash_finalize
+  hash_get_digest_len, hash_get_digest_algorithm_id, hash_get_algorithm,
+  hash_initialize, hash_update, hash_finalize
 };
 
 const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
-  pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_delete,
+  pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_close, pkey_delete,
   pkey_get_key_type, pkey_get_key_flags, pkey_get_public_key_len, pkey_get_public_key,
   pkey_remote_sign, pkey_remote_verify,
   pkey_list
 };
 
 const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
-  pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_delete,
+  pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_close, pkey_delete,
   pkey_get_key_type, pkey_get_key_flags, pkey_get_public_key_len, pkey_get_public_key,
   pkey_mixed_sign, pkey_mixed_verify,
   pkey_list
diff --git a/rpc_hash.c b/rpc_hash.c
index 4ceadb6..86b8ae0 100644
--- a/rpc_hash.c
+++ b/rpc_hash.c
@@ -36,7 +36,7 @@
 #include <string.h>
 
 #include "hal.h"
-#include "rpc_internal.h"
+#include "hal_internal.h"
 
 /*
  * Need table and handle allocation, including some kind of in_use
@@ -94,10 +94,10 @@ static inline handle_slot_t *alloc_handle(const int is_hmac)
 #if HAL_STATIC_HASH_STATE_BLOCKS > 0
   if (!is_hmac) {
     for (int i = 0; i < sizeof(hash_handle)/sizeof(*hash_handle); i++) {
-      if (hash_handle[i].state.hash == NULL) {
-        hash_handle[i].hash_handle.handle = i | glop;
-        return &hash_handle[i];
-      }
+      if (hash_handle[i].state.hash != NULL)
+        continue;
+      hash_handle[i].hash_handle.handle = i | glop;
+      return &hash_handle[i];
     }
   }
 #endif
@@ -105,10 +105,10 @@ static inline handle_slot_t *alloc_handle(const int is_hmac)
 #if HAL_STATIC_HMAC_STATE_BLOCKS > 0
   if (is_hmac) {
     for (int i = 0; i < sizeof(hmac_handle)/sizeof(*hmac_handle); i++) {
-      if (hmac_handle[i].state.hmac == NULL) {
-        hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC;
-        return &hmac_handle[i];
-      }
+      if (hmac_handle[i].state.hmac != NULL)
+        continue;
+      hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC;
+      return &hmac_handle[i];
     }
   }
 #endif
@@ -134,7 +134,7 @@ static inline handle_slot_t *find_handle(const hal_rpc_hash_handle_t handle)
     return &hash_handle[i];
 #endif
 
-#if HAL_STATIC_HASH_STATE_BLOCKS > 0
+#if HAL_STATIC_HMAC_STATE_BLOCKS > 0
   if (is_hmac && i < sizeof(hmac_handle)/sizeof(*hmac_handle) &&
       hmac_handle[i].hash_handle.handle == handle.handle && hmac_handle[i].state.hmac != NULL)
     return &hmac_handle[i];
@@ -227,10 +227,10 @@ static hal_error_t get_algorithm(const hal_rpc_hash_handle_t handle, hal_digest_
 }
 
 static hal_error_t initialize(const hal_rpc_client_handle_t client,
-                       const hal_rpc_session_handle_t session,
-                       hal_rpc_hash_handle_t *hash,
-                       const hal_digest_algorithm_t alg,
-                       const uint8_t * const key, const size_t key_len)
+                              const hal_rpc_session_handle_t session,
+                              hal_rpc_hash_handle_t *hash,
+                              const hal_digest_algorithm_t alg,
+                              const uint8_t * const key, const size_t key_len)
 {
   const hal_hash_descriptor_t *descriptor;
   handle_slot_t *slot;
@@ -254,7 +254,7 @@ static hal_error_t initialize(const hal_rpc_client_handle_t client,
 }
 
 static hal_error_t update(const hal_rpc_hash_handle_t handle,
-                   const uint8_t * data, const size_t length)
+                          const uint8_t * data, const size_t length)
 {
   handle_slot_t *slot = find_handle(handle);
 
diff --git a/rpc_pkey.c b/rpc_pkey.c
new file mode 100644
index 0000000..8fece44
--- /dev/null
+++ b/rpc_pkey.c
@@ -0,0 +1,736 @@
+/*
+ * rpc_pkey.c
+ * ----------
+ * Remote procedure call server-side public key implementation.
+ *
+ * Authors: Rob Austein
+ * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+typedef struct {
+  hal_rpc_client_handle_t client_handle;
+  hal_rpc_session_handle_t session_handle;
+  hal_rpc_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];
+#endif
+
+/*
+ * Handle allocation is simple: we look for an unused (name_len == 0)
+ * slot in the table, and, assuming we find one, construct a composite
+ * handle consisting of the index into the table and a counter whose
+ * sole purpose is to keep the same handle from reoccurring anytime
+ * soon, to help identify use-after-free bugs in calling code.
+ */
+
+static inline pkey_slot_t *alloc_slot(void)
+{
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+  static uint16_t next_glop = 0;
+  uint32_t glop = ++next_glop << 16;
+  next_glop %= 0xFFFF;
+
+  for (int i = 0; i < sizeof(pkey_handle)/sizeof(*pkey_handle); i++) {
+    if (pkey_handle[i].name_len > 0)
+      continue;
+    pkey_handle[i].pkey_handle.handle = i | glop;
+    pkey_handle[i].ks_hint = -1;
+    return &pkey_handle[i];
+  }
+#endif
+
+  return NULL;
+}
+
+/*
+ * Check a caller-supplied handle.  Must be in range, in use, and have
+ * the right glop.  Returns slot pointer on success, NULL otherwise.
+ */
+
+static inline pkey_slot_t *find_handle(const hal_rpc_pkey_handle_t handle)
+{
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+  const int i = (int) (handle.handle & 0xFFFF);
+
+  if (i < sizeof(pkey_handle)/sizeof(*pkey_handle) && pkey_handle[i].pkey_handle.handle == handle.handle)
+    return &pkey_handle[i];
+#endif
+
+  return NULL;
+}
+
+/*
+ * Construct a PKCS #1 DigestInfo object.  This requires some (very
+ * basic) ASN.1 encoding, which we perform inline.
+ */
+
+static hal_error_t pkcs1_construct_digestinfo(const hal_rpc_hash_handle_t handle,
+                                              uint8_t *digest_info, size_t *digest_info_len, const size_t digest_info_max)
+{
+  assert(digest_info != NULL && digest_info_len != NULL);
+
+  hal_digest_algorithm_t alg;
+  size_t len, alg_len;
+  hal_error_t err;
+
+  if ((err = hal_rpc_hash_get_algorithm(handle, &alg))                     != HAL_OK ||
+      (err = hal_rpc_hash_get_digest_length(alg, &len))                    != HAL_OK ||
+      (err = hal_rpc_hash_get_digest_algorithm_id(alg, NULL, &alg_len, 0)) != HAL_OK)
+    return err;
+
+  *digest_info_len = len + alg_len + 4;
+
+  if (*digest_info_len >= digest_info_max)
+    return HAL_ERROR_RESULT_TOO_LONG;
+
+  assert(*digest_info_len < 130);
+
+  uint8_t *d = digest_info;
+
+  *d++ = 0x30;                /* SEQUENCE */
+  *d++ = (uint8_t) (*digest_info_len - 2);
+
+  if ((err = hal_rpc_hash_get_digest_algorithm_id(alg, d, NULL, alg_len)) != HAL_OK)
+    return err;
+  d += alg_len;
+
+  *d++ = 0x04;                /* OCTET STRING */
+  *d++ = (uint8_t) len;
+
+  assert(digest_info + *digest_info_len == d + len);
+
+  return hal_rpc_hash_finalize(handle, d, len);
+}
+
+/*
+ * Pad an octet string with PKCS #1.5 padding for use with RSA.
+ *
+ * For the moment, this only handles type 01 encryption blocks, thus
+ * is only suitable for use with signature and verification.  If and
+ * when we add support for encryption and decryption, this function
+ * should be extended to take an argument specifying the block type
+ * and include support for generating type 02 encryption blocks.
+ * Other than the block type code, the only difference is the padding
+ * value: for type 01 it's constant (0xFF), for type 02 it should be
+ * non-zero random bytes from the CSPRNG.
+ *
+ * We use memmove() instead of memcpy() so that the caller can
+ * construct the data to be padded in the same buffer.
+ */
+
+static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len,
+                               uint8_t *block, const size_t block_len)
+{
+  assert(data != NULL && block != NULL);
+
+  /*
+   * Congregation will now please turn to RFC 2313 8.1 as we
+   * construct a PKCS #1.5 type 01 encryption block.
+   */
+
+  if (data_len > block_len - 11)
+    return HAL_ERROR_RESULT_TOO_LONG;
+
+  memmove(block + block_len - data_len, data, data_len);
+
+  block[0] = 0x00;
+  block[1] = 0x01;
+
+  /* This is where we'd use non-zero random bytes if constructing a type 02 block. */
+  memset(block + 2, 0xFF, block_len - 3 - data_len);
+
+  block[block_len - data_len - 1] = 0x00;
+
+  return HAL_OK;
+}
+
+/*
+ * Receive key from application, store it with supplied name, return a key handle.
+ */
+
+static hal_error_t load(const hal_rpc_client_handle_t client,
+                        const hal_rpc_session_handle_t session,
+                        hal_rpc_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,
+                        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(sizeof(slot->name) >= name_len && pkey != NULL);
+
+  if ((slot = alloc_slot()) == 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)
+    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;
+
+  *pkey = slot->pkey_handle;
+  return HAL_OK;
+}
+
+/*
+ * Look up a key given its name, return a key handle.
+ */
+
+static hal_error_t find(const hal_rpc_client_handle_t client,
+                        const hal_rpc_session_handle_t session,
+                        hal_rpc_pkey_handle_t *pkey,
+                        const hal_key_type_t type,
+                        const uint8_t * const name, const size_t name_len)
+{
+  pkey_slot_t *slot;
+  hal_error_t err;
+
+  assert(sizeof(slot->name) >= name_len && pkey != NULL);
+
+  if ((slot = alloc_slot()) == 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->client_handle = client;
+  slot->session_handle = session;
+  slot->type = type;
+  slot->name_len = name_len;
+
+  *pkey = slot->pkey_handle;
+  return HAL_OK;
+}
+
+/*
+ * Generate a new RSA key with supplied name, return a key handle.
+ */
+
+static hal_error_t generate_rsa(const hal_rpc_client_handle_t client,
+                                const hal_rpc_session_handle_t session,
+                                hal_rpc_pkey_handle_t *pkey,
+                                const uint8_t * const name, const size_t name_len,
+                                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(sizeof(slot->name) >= name_len && pkey != NULL && (key_length & 7) == 0);
+
+  if ((slot = alloc_slot()) == 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_rsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), key_length / 8,
+                             public_exponent, public_exponent_len)) != HAL_OK)
+    return err;
+
+  uint8_t der[hal_rsa_key_to_der_len(key)];
+  size_t der_len;
+
+  if ((err = hal_rsa_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);
+
+  memset(keybuf, 0, sizeof(keybuf));
+  memset(der, 0, sizeof(der));
+
+  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;
+  return HAL_OK;
+}
+
+/*
+ * Generate a new EC key with supplied name, return a key handle.
+ * At the moment, EC key == ECDSA key, but this is subject to change.
+ */
+
+static hal_error_t generate_ec(const hal_rpc_client_handle_t client,
+                               const hal_rpc_session_handle_t session,
+                               hal_rpc_pkey_handle_t *pkey,
+                               const uint8_t * const name, const size_t name_len,
+                               const hal_curve_name_t curve,
+                               const hal_key_flags_t flags)
+{
+  pkey_slot_t *slot;
+  hal_error_t err;
+
+  assert(sizeof(slot->name) >= name_len && pkey != NULL);
+
+  if ((slot = alloc_slot()) == 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_ecdsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), curve)) != HAL_OK)
+    return err;
+
+  uint8_t der[hal_ecdsa_key_to_der_len(key)];
+  size_t der_len;
+
+  if ((err = hal_ecdsa_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);
+
+  memset(keybuf, 0, sizeof(keybuf));
+  memset(der, 0, sizeof(der));
+
+  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;
+  return HAL_OK;
+}
+
+/*
+ * Discard key handle, leaving key intact.
+ */
+
+static hal_error_t close(const hal_rpc_pkey_handle_t pkey)
+{
+  pkey_slot_t *slot;
+
+  if ((slot = find_handle(pkey)) == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  memset(slot, 0, sizeof(*slot));
+
+  return HAL_OK;
+}
+
+/*
+ * Delete a key from the store, given its key handle.
+ */
+
+static hal_error_t delete(const hal_rpc_pkey_handle_t pkey)
+{
+  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);
+
+  if (err == HAL_OK || err == HAL_ERROR_KEY_NOT_FOUND)
+    memset(slot, 0, sizeof(*slot));    
+
+  return err;
+}
+
+/*
+ * Get type of key associated with handle.
+ */
+
+static hal_error_t get_key_type(const hal_rpc_pkey_handle_t pkey,
+                                hal_key_type_t *type)
+{
+  if (type == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  pkey_slot_t *slot = find_handle(pkey);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  *type = slot->type;
+
+  return HAL_OK;
+}
+
+/*
+ * Get flags of key associated with handle.
+ */
+
+static hal_error_t get_key_flags(const hal_rpc_pkey_handle_t pkey,
+                                 hal_key_flags_t *flags)
+{
+  if (flags == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  pkey_slot_t *slot = find_handle(pkey);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  *flags = slot->flags;
+
+  return HAL_OK;
+}
+
+/*
+ * Get length of public key associated with handle.
+ */
+
+static size_t get_public_key_len(const hal_rpc_pkey_handle_t pkey)
+{
+  return 0;
+}
+
+/*
+ * Get public key associated with handle.
+ */
+
+static hal_error_t get_public_key(const hal_rpc_pkey_handle_t pkey,
+                                  uint8_t *der, size_t *der_len, const size_t der_len_max)
+{
+  /*
+   * Still missing some of the public key format ASN.1 stuff, apparently.  Feh.
+   */
+  return HAL_ERROR_IMPOSSIBLE;
+#warning get_public_key() not implemented
+}
+
+/*
+ * Sign something using private key associated with handle.
+ *
+ * RSA has enough quirks that it's simplest to split this out into
+ * algorithm-specific functions.
+ */
+
+static hal_error_t sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
+                            const uint8_t * const der, const size_t der_len,
+                            const hal_rpc_hash_handle_t hash,
+                            const uint8_t * input, size_t input_len,
+                            uint8_t * signature, size_t *signature_len, const size_t signature_max)
+{
+  hal_rsa_key_t *key = NULL;
+  hal_error_t err;
+
+  assert(signature != NULL && signature_len != NULL);
+  assert((hash.handle == hal_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+  if ((err = hal_rsa_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK ||
+      (err = hal_rsa_key_get_modulus(key, NULL, signature_len, 0))         != HAL_OK)
+    return err;
+
+  if (*signature_len > signature_max)
+    return HAL_ERROR_RESULT_TOO_LONG;
+
+  if (input == NULL) {
+    if ((err = pkcs1_construct_digestinfo(hash, signature, &input_len, *signature_len)) != HAL_OK)
+      return err;
+    input = signature;
+  }
+
+  if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len))                         != HAL_OK ||
+      (err = hal_rsa_decrypt(NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK)
+    return err;
+
+  return HAL_OK;
+}
+
+static hal_error_t sign_ecdsa(uint8_t *keybuf, const size_t keybuf_len,
+                              const uint8_t * const der, const size_t der_len,
+                              const hal_rpc_hash_handle_t hash,
+                              const uint8_t * input, size_t input_len,
+                              uint8_t * signature, size_t *signature_len, const size_t signature_max)
+{
+  hal_ecdsa_key_t *key = NULL;
+  hal_error_t err;
+
+  assert(signature != NULL && signature_len != NULL);
+  assert((hash.handle == hal_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+  if ((err = hal_ecdsa_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
+    return err;
+
+  if (input == NULL) {
+    hal_digest_algorithm_t alg;
+
+    if ((err = hal_rpc_hash_get_algorithm(hash, &alg))          != HAL_OK ||
+        (err = hal_rpc_hash_get_digest_length(alg, &input_len)) != HAL_OK)
+      return err;
+
+    if (input_len < signature_max)
+      return HAL_ERROR_RESULT_TOO_LONG;
+
+    if ((err = hal_rpc_hash_finalize(hash, signature, input_len)) != HAL_OK)
+      return err;
+
+    input = signature;
+  }
+
+  if ((err = hal_ecdsa_sign(NULL, key, input, input_len, signature, signature_len, signature_max,
+                            HAL_ECDSA_SIGNATURE_FORMAT_PKCS11)) != HAL_OK)
+    return err;
+
+  return HAL_OK;
+}
+
+static hal_error_t sign(const hal_rpc_session_handle_t session,
+                        const hal_rpc_pkey_handle_t pkey,
+                        const hal_rpc_hash_handle_t hash,
+                        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);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  hal_error_t (*signer)(uint8_t *keybuf, const size_t keybuf_len,
+                        const uint8_t * const der, const size_t der_len,
+                        const hal_rpc_hash_handle_t hash,
+                        const uint8_t * const input,  const size_t input_len,
+                        uint8_t * signature, size_t *signature_len, const size_t signature_max);
+
+  switch (slot->type) {
+  case HAL_KEY_TYPE_RSA_PRIVATE:
+    signer = sign_rsa;
+    break;
+  case HAL_KEY_TYPE_EC_PRIVATE:
+    signer = sign_ecdsa;
+    break;
+  default:
+    return HAL_ERROR_UNSUPPORTED_KEY;
+  }
+
+  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_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 == HAL_OK)
+    err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len, signature_max);
+
+  memset(keybuf, 0, sizeof(keybuf));
+  memset(der,    0, sizeof(der));
+
+  return err;
+}
+
+/*
+ * Verify something using private key associated with handle.
+ *
+ * RSA has enough quirks that it's simplest to split this out into
+ * algorithm-specific functions.
+ */
+
+static hal_error_t verify_rsa(uint8_t *keybuf, const size_t keybuf_len,
+                              const uint8_t * const der, const size_t der_len,
+                              const hal_rpc_hash_handle_t hash,
+                              const uint8_t * input, size_t input_len,
+                              const uint8_t * const signature, const size_t signature_len)
+{
+  uint8_t expected[signature_len], received[signature_len];
+  hal_rsa_key_t *key = NULL;
+  hal_error_t err;
+
+  assert(signature != NULL && signature_len > 0);
+  assert((hash.handle == hal_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+  if ((err = hal_rsa_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
+    return err;
+
+  if (input == NULL) {
+    if ((err = pkcs1_construct_digestinfo(hash, expected, &input_len, sizeof(expected))) != HAL_OK)
+      return err;
+    input = expected;
+  }
+
+  if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected)))                        != HAL_OK ||
+      (err = hal_rsa_encrypt(NULL, key, signature, signature_len, received, sizeof(received))) != HAL_OK)
+    return err;
+
+  unsigned diff = 0;
+  for (int i = 0; i < signature_len; i++)
+    diff |= expected[i] ^ received[i];
+
+  if (diff != 0)
+    return HAL_ERROR_INVALID_SIGNATURE;
+
+  return HAL_OK;
+}
+
+static hal_error_t verify_ecdsa(uint8_t *keybuf, const size_t keybuf_len,
+                                const uint8_t * const der, const size_t der_len,
+                                const hal_rpc_hash_handle_t hash,
+                                const uint8_t * input, size_t input_len,
+                                const uint8_t * const signature, const size_t signature_len)
+{
+  uint8_t digest[signature_len];
+  hal_ecdsa_key_t *key = NULL;
+  hal_error_t err;
+
+  assert(signature != NULL && signature_len > 0);
+  assert((hash.handle == hal_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+  if ((err = hal_ecdsa_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
+    return err;
+
+  if (input == NULL) {
+    hal_digest_algorithm_t alg;
+
+    if ((err = hal_rpc_hash_get_algorithm(hash, &alg))              != HAL_OK ||
+        (err = hal_rpc_hash_get_digest_length(alg, &input_len))     != HAL_OK ||
+        (err = hal_rpc_hash_finalize(hash, digest, sizeof(digest))) != HAL_OK)
+      return err;
+
+    input = digest;
+  }
+
+  if ((err = hal_ecdsa_verify(NULL, key, input, input_len, signature, signature_len,
+                            HAL_ECDSA_SIGNATURE_FORMAT_PKCS11)) != HAL_OK)
+    return err;
+
+  return HAL_OK;
+}
+
+static hal_error_t verify(const hal_rpc_session_handle_t session,
+                          const hal_rpc_pkey_handle_t pkey,
+                          const hal_rpc_hash_handle_t hash,
+                          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);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  hal_error_t (*verifier)(uint8_t *keybuf, const size_t keybuf_len,
+                          const uint8_t * const der, const size_t der_len,
+                          const hal_rpc_hash_handle_t hash,
+                          const uint8_t * const input,  const size_t input_len,
+                          const uint8_t * const signature, const size_t signature_len);
+
+  switch (slot->type) {
+  case HAL_KEY_TYPE_RSA_PRIVATE:
+  case HAL_KEY_TYPE_RSA_PUBLIC:
+    verifier = verify_rsa;
+    break;
+  case HAL_KEY_TYPE_EC_PRIVATE:
+  case HAL_KEY_TYPE_EC_PUBLIC:
+    verifier = verify_ecdsa;
+    break;
+  default:
+    return HAL_ERROR_UNSUPPORTED_KEY;
+  }
+
+  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_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 == HAL_OK)
+    err = verifier(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len);
+
+  memset(keybuf, 0, sizeof(keybuf));
+  memset(der,    0, sizeof(der));
+
+  return err;
+}
+
+
+/*
+ * List keys in the key store.
+ */
+
+static hal_error_t list(hal_rpc_pkey_key_info_t *result,
+                        unsigned *result_len,
+                        const unsigned result_max)
+{
+  return hal_ks_list(result, result_len, result_max);
+}
+
+const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
+  load, find, generate_rsa, generate_ec, close, delete,
+  get_key_type, get_key_flags, get_public_key_len, get_public_key,
+  sign, verify, list
+};
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/rsa.c b/rsa.c
index a03b41a..a901b24 100644
--- a/rsa.c
+++ b/rsa.c
@@ -116,7 +116,7 @@ void hal_rsa_set_blinding(const int onoff)
  */
 
 struct hal_rsa_key {
-  hal_rsa_key_type_t type;      /* What kind of key this is */
+  hal_key_type_t type;      /* What kind of key this is */
   fp_int n[1];                  /* The modulus */
   fp_int e[1];                  /* Public exponent */
   fp_int d[1];                  /* Private exponent */
@@ -454,7 +454,7 @@ void hal_rsa_key_clear(hal_rsa_key_t *key)
  * calculate everything else from them.
  */
 
-static hal_error_t load_key(const hal_rsa_key_type_t type,
+static hal_error_t load_key(const hal_key_type_t type,
                             hal_rsa_key_t **key_,
                             void *keybuf, const size_t keybuf_len,
                             const uint8_t * const n,  const size_t n_len,
@@ -477,12 +477,14 @@ static hal_error_t load_key(const hal_rsa_key_type_t type,
 
 #define _(x) do { fp_init(key->x); if (x == NULL) goto fail; fp_read_unsigned_bin(key->x, unconst_uint8_t(x), x##_len); } while (0)
   switch (type) {
-  case HAL_RSA_PRIVATE:
+  case HAL_KEY_TYPE_RSA_PRIVATE:
     _(d); _(p); _(q); _(u); _(dP); _(dQ);
-  case HAL_RSA_PUBLIC:
+  case HAL_KEY_TYPE_RSA_PUBLIC:
     _(n); _(e);
     *key_ = key;
     return HAL_OK;
+  default:
+    goto fail;
   }
 #undef _
 
@@ -506,7 +508,7 @@ hal_error_t hal_rsa_key_load_private(hal_rsa_key_t **key_,
                                      const uint8_t * const dP, const size_t dP_len,
                                      const uint8_t * const dQ, const size_t dQ_len)
 {
-  return load_key(HAL_RSA_PRIVATE, key_, keybuf, keybuf_len,
+  return load_key(HAL_KEY_TYPE_RSA_PRIVATE, key_, keybuf, keybuf_len,
                   n, n_len, e, e_len,
                   d, d_len, p, p_len, q, q_len, u, u_len, dP, dP_len, dQ, dQ_len);
 }
@@ -516,7 +518,7 @@ hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key_,
                                     const uint8_t * const n,  const size_t n_len,
                                     const uint8_t * const e,  const size_t e_len)
 {
-  return load_key(HAL_RSA_PUBLIC, key_, keybuf, keybuf_len,
+  return load_key(HAL_KEY_TYPE_RSA_PUBLIC, key_, keybuf, keybuf_len,
                   n, n_len, e, e_len,
                   NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
 }
@@ -526,7 +528,7 @@ hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key_,
  */
 
 hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key,
-                                 hal_rsa_key_type_t *key_type)
+                                 hal_key_type_t *key_type)
 {
   if (key == NULL || key_type == NULL)
     return HAL_ERROR_BAD_ARGUMENTS;
@@ -625,7 +627,7 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core,
     return HAL_ERROR_BAD_ARGUMENTS;
 
   memset(keybuf, 0, keybuf_len);
-  key->type = HAL_RSA_PRIVATE;
+  key->type = HAL_KEY_TYPE_RSA_PRIVATE;
   fp_read_unsigned_bin(key->e, (uint8_t *) public_exponent, public_exponent_len);
 
   if (key_length < bitsToBytes(1024) || key_length > bitsToBytes(8192))
@@ -690,7 +692,7 @@ hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key,
 {
   hal_error_t err = HAL_OK;
 
-  if (key == NULL || der_len == NULL || key->type != HAL_RSA_PRIVATE)
+  if (key == NULL || der_len == NULL || key->type != HAL_KEY_TYPE_RSA_PRIVATE)
     return HAL_ERROR_BAD_ARGUMENTS;
 
   fp_int version[1] = INIT_FP_INT;
@@ -748,7 +750,7 @@ hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key_,
 
   hal_rsa_key_t *key = keybuf;
 
-  key->type = HAL_RSA_PRIVATE;
+  key->type = HAL_KEY_TYPE_RSA_PRIVATE;
 
   hal_error_t err = HAL_OK;
   size_t hlen, vlen;
diff --git a/tests/test-ecdsa.c b/tests/test-ecdsa.c
index ce8aee1..ae99616 100644
--- a/tests/test-ecdsa.c
+++ b/tests/test-ecdsa.c
@@ -203,7 +203,7 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc)
  * Run one keygen/sign/verify test with a newly generated key.
  */
 
-static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve)
+static int test_keygen_sign_verify(const hal_curve_name_t curve)
 
 {
   const hal_hash_descriptor_t *hash_descriptor = NULL;
@@ -213,17 +213,17 @@ static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve)
 
   switch (curve) {
 
-  case HAL_ECDSA_CURVE_P256:
+  case HAL_CURVE_P256:
     printf("ECDSA P-256 key generation / signature / verification test\n");
     hash_descriptor = hal_hash_sha256;
     break;
 
-  case HAL_ECDSA_CURVE_P384:
+  case HAL_CURVE_P384:
     printf("ECDSA P-384 key generation / signature / verification test\n");
     hash_descriptor = hal_hash_sha384;
     break;
 
-  case HAL_ECDSA_CURVE_P521:
+  case HAL_CURVE_P521:
     printf("ECDSA P-521 key generation / signature / verification test\n");
     hash_descriptor = hal_hash_sha512;
     break;
@@ -339,12 +339,12 @@ int main(int argc, char *argv[])
    */
 
   if (csprng_core != NULL && sha256_core != NULL) {
-    time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P256));
+    time_check(test_keygen_sign_verify(HAL_CURVE_P256));
   }
 
   if (csprng_core != NULL && sha512_core != NULL) {
-    time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P384));
-    time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P521));
+    time_check(test_keygen_sign_verify(HAL_CURVE_P384));
+    time_check(test_keygen_sign_verify(HAL_CURVE_P521));
   }
 
   return !ok;
diff --git a/tests/test-ecdsa.h b/tests/test-ecdsa.h
index ca51858..a607d97 100644
--- a/tests/test-ecdsa.h
+++ b/tests/test-ecdsa.h
@@ -264,7 +264,7 @@ static const uint8_t p384_w[] = { /* 48 bytes */
 };
 
 typedef struct {
-  hal_ecdsa_curve_t curve;
+  hal_curve_name_t curve;
   const uint8_t *       H; size_t        H_len;
   const uint8_t *       M; size_t        M_len;
   const uint8_t *      Qx; size_t       Qx_len;
@@ -286,7 +286,7 @@ typedef struct {
 } ecdsa_tc_t;
 
 static const ecdsa_tc_t ecdsa_tc[] = {
-  { HAL_ECDSA_CURVE_P256,
+  { HAL_CURVE_P256,
     p256_H,        sizeof(p256_H),
     p256_M,        sizeof(p256_M),
     p256_Qx,       sizeof(p256_Qx),
@@ -306,7 +306,7 @@ static const ecdsa_tc_t ecdsa_tc[] = {
     p256_v,        sizeof(p256_v),
     p256_w,        sizeof(p256_w),
   },
-  { HAL_ECDSA_CURVE_P384,
+  { HAL_CURVE_P384,
     p384_H,        sizeof(p384_H),
     p384_M,        sizeof(p384_M),
     p384_Qx,       sizeof(p384_Qx),



More information about the Commits mailing list