aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile53
-rw-r--r--core.c9
-rw-r--r--crc32.c143
-rw-r--r--daemon.c4
-rw-r--r--hal.h136
-rw-r--r--hal_internal.h617
-rw-r--r--hash.c14
-rw-r--r--ks.c411
-rw-r--r--ks_attribute.c178
-rw-r--r--ks_flash.c2042
-rw-r--r--ks_index.c457
-rw-r--r--ks_mmap.c6
-rw-r--r--ks_volatile.c520
-rw-r--r--libhal.py662
-rw-r--r--masterkey.c248
-rw-r--r--mkm.c230
-rw-r--r--rpc_api.c111
-rw-r--r--rpc_client.c489
-rw-r--r--rpc_hash.c24
-rw-r--r--rpc_misc.c20
-rw-r--r--rpc_pkcs1.c (renamed from masterkey.h)58
-rw-r--r--rpc_pkey.c537
-rw-r--r--rpc_server.c409
-rw-r--r--slip.c2
-rw-r--r--tests/test-bus.c3
-rw-r--r--tests/test-mkmif.c10
-rw-r--r--tests/test-rpc_bighash.c2
-rw-r--r--tests/test-rpc_hash.c92
-rw-r--r--tests/test-rpc_pkey.c519
-rw-r--r--tests/test-trng.c4
-rw-r--r--unit-tests.py1035
-rw-r--r--uuid.c111
33 files changed, 7195 insertions, 1962 deletions
diff --git a/.gitignore b/.gitignore
index 01c1858..764f6fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.[ao]
+*.pyc
*~
Makefile
TAGS
diff --git a/Makefile b/Makefile
index d0432f5..a2ddb10 100644
--- a/Makefile
+++ b/Makefile
@@ -33,17 +33,18 @@
STATIC_CORE_STATE_BLOCKS = 32
STATIC_HASH_STATE_BLOCKS = 10
STATIC_HMAC_STATE_BLOCKS = 4
-STATIC_PKEY_STATE_BLOCKS = 6
+STATIC_PKEY_STATE_BLOCKS = 32
+STATIC_KS_VOLATILE_SLOTS = 128
INC = hal.h hal_internal.h
LIB = libhal.a
# Error checking on known control options, some of which allow the user entirely too much rope.
-USAGE := "usage: ${MAKE} [IO_BUS=eim|i2c|fmc] [RPC_MODE=none|server|client-simple|client-mixed] [KS=volatile|mmap|flash] [RPC_TRANSPORT=none|loopback|serial|daemon] [MODEXP_CORE=no|yes]"
+USAGE := "usage: ${MAKE} [IO_BUS=eim|i2c|fmc] [RPC_MODE=none|server|client-simple|client-mixed] [KS=mmap|flash] [RPC_TRANSPORT=none|loopback|serial|daemon] [MODEXP_CORE=no|yes]"
IO_BUS ?= none
-KS ?= volatile
+KS ?= flash
RPC_MODE ?= none
RPC_TRANSPORT ?= none
MODEXP_CORE ?= no
@@ -51,7 +52,7 @@ MODEXP_CORE ?= no
ifeq (,$(and \
$(filter none eim i2c fmc ,${IO_BUS}),\
$(filter none server client-simple client-mixed ,${RPC_MODE}),\
- $(filter volatile mmap flash ,${KS}),\
+ $(filter mmap flash ,${KS}),\
$(filter none loopback serial daemon ,${RPC_TRANSPORT}),\
$(filter no yes ,${MODEXP_CORE})))
$(error ${USAGE})
@@ -73,8 +74,8 @@ endif
# makefile, so the working definition of "always want" is sometimes
# just "building this is harmless even if we don't use it."
-OBJ += errorstrings.o hash.o asn1.o ecdsa.o rsa.o ${KS_OBJ} xdr.o slip.o
-OBJ += rpc_api.o rpc_hash.o rpc_misc.o rpc_pkey.o rpc_client.o rpc_server.o
+OBJ += errorstrings.o hash.o asn1.o ecdsa.o rsa.o xdr.o slip.o
+OBJ += rpc_api.o rpc_hash.o uuid.o rpc_pkcs1.o crc32.o
# Object files to build when we're on a platform with direct access
# to our hardware (Verilog) cores.
@@ -105,22 +106,25 @@ ifneq "${IO_BUS}" "fmc"
CFLAGS += -fPIC
endif
-# The mmap and flash keystore implementations are both server code.
+# The keystore code has mutated a bit with the new API, and the Makefile,
+# probably needs more extensive changes to track that.
#
-# The volatile keystore (conventional memory) is client code, to
-# support using the same API for things like PKCS #11 "session" objects.
+# In the old world, the volatile keystore was for the client side,
+# while the flash and mmap keystores were for the server side (on the
+# Alpha and the Novena, respectively).
#
-# Default at the moment is mmap, since that should work on the Novena
-# and we haven't yet written the flash code for the bridge board.
+# In the new world, all keystores are on the server side, and the
+# volatile keystore is always present, to support things like PKCS #11
+# "session" objects.
+#
+# The mmap keystore hasn't been rewritten for the new API yet.
-KS_OBJ = ks.o
+KS_OBJ = ks_index.o ks_attribute.o ks_volatile.o
ifeq "${KS}" "mmap"
KS_OBJ += ks_mmap.o
-else ifeq "${KS}" "volatile"
- KS_OBJ += ks_volatile.o
else ifeq "${KS}" "flash"
- KS_OBJ += ks_flash.o masterkey.o
+ KS_OBJ += ks_flash.o mkm.o
endif
# RPC_MODE = none | server | client-simple | client-mixed
@@ -144,18 +148,22 @@ ifneq "${RPC_MODE}" "server"
OBJ += rpc_serial.o
endif
+RPC_CLIENT_OBJ = rpc_client.o
+
ifeq "${RPC_TRANSPORT}" "loopback"
- RPC_CLIENT_OBJ = rpc_client_loopback.o
+ RPC_CLIENT_OBJ += rpc_client_loopback.o
else ifeq "${RPC_TRANSPORT}" "serial"
- RPC_CLIENT_OBJ = rpc_client_serial.o
+ RPC_CLIENT_OBJ += rpc_client_serial.o
else ifeq "${RPC_TRANSPORT}" "daemon"
- RPC_CLIENT_OBJ = rpc_client_daemon.o
+ RPC_CLIENT_OBJ += rpc_client_daemon.o
endif
+RPC_SERVER_OBJ = ${KS_OBJ} rpc_misc.o rpc_pkey.o rpc_server.o
+
ifeq "${RPC_TRANSPORT}" "loopback"
- RPC_SERVER_OBJ = rpc_server_loopback.o
+ RPC_SERVER_OBJ += rpc_server_loopback.o
else ifeq "${RPC_TRANSPORT}" "serial"
- RPC_SERVER_OBJ = rpc_server_serial.o
+ RPC_SERVER_OBJ += rpc_server_serial.o
endif
ifeq "${RPC_MODE}" "none"
@@ -169,8 +177,7 @@ else ifeq "${RPC_MODE}" "client-simple"
CFLAGS += -DRPC_CLIENT=RPC_CLIENT_REMOTE -DHAL_RSA_USE_MODEXP=0
else ifeq "${RPC_MODE}" "client-mixed"
OBJ += ${RPC_CLIENT_OBJ}
- CFLAGS += -DRPC_CLIENT=RPC_CLIENT_MIXED -DHAL_RSA_USE_MODEXP=0 -DHAL_ONLY_USE_SOFTWARE_HASH_CORES=1
- KS = volatile
+ CFLAGS += -DRPC_CLIENT=RPC_CLIENT_MIXED -DHAL_RSA_USE_MODEXP=0
endif
ifndef CRYPTECH_ROOT
@@ -234,7 +241,7 @@ asn1.o rsa.o ecdsa.o: asn1_internal.h
ecdsa.o: ecdsa_curves.h
novena-eim.o hal_io_eim.o: novena-eim.h
slip.o rpc_client_serial.o rpc_server_serial.o: slip_internal.h
-ks.o: last_gasp_pin_internal.h
+ks_flash.o: last_gasp_pin_internal.h
last_gasp_pin_internal.h:
./utils/last_gasp_default_pin >$@
diff --git a/core.c b/core.c
index 378f085..a17422a 100644
--- a/core.c
+++ b/core.c
@@ -42,6 +42,13 @@
#include "hal_internal.h"
/*
+ * POSIX function whose declaration gets lost somewhere in the twisty
+ * corridors of glibc's "Feature Test Macro" system.
+ */
+
+extern size_t strnlen(const char *, size_t);
+
+/*
* Structure of our internal database is private, in case we want to
* change representation (array, tree, list of lists, whatever) at
* some later date without having to change the public API.
@@ -208,7 +215,7 @@ hal_error_t hal_core_alloc(const char *name, hal_core_t **pcore)
{
hal_core_t *core;
hal_error_t err = HAL_ERROR_CORE_NOT_FOUND;
-
+
if (name == NULL && (pcore == NULL || *pcore == NULL))
return HAL_ERROR_BAD_ARGUMENTS;
diff --git a/crc32.c b/crc32.c
new file mode 100644
index 0000000..417dfa8
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,143 @@
+/*
+ * crc32.c
+ * -------
+ * CRC-32 implementation. This is internal within libhal.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was generated by the nifty pycrc package. pycrc itself
+ * (well, the version used for this) is under the MIT license, but the
+ * author explictly disclaims ownership of the generated code, so
+ * we're free to do whatever we want with it. For simplicity, we've
+ * placed it under the same copyright we use for everything else.
+ *
+ * This file contains two different implementations of the same API,
+ * corresponding to different speed/size tradeoffs. These were
+ * generated with the commands:
+ *
+ * pycrc.py --model crc-32 --algorithm table-driven --std c99 --symbol-prefix hal_crc32_ --generate h
+ * pycrc.py --model crc-32 --algorithm table-driven --std c99 --symbol-prefix hal_crc32_ --generate c --table-idx-width 4
+ * pycrc.py --model crc-32 --algorithm table-driven --std c99 --symbol-prefix hal_crc32_ --generate c --table-idx-width 8
+ */
+
+/*
+ * Generated on Mon Sep 12 15:36:31 2016, by pycrc v0.9, https://pycrc.org using the configuration:
+ * Width = 32
+ * Poly = 0x04c11db7
+ * Xor_In = 0xffffffff
+ * ReflectIn = True
+ * Xor_Out = 0xffffffff
+ * ReflectOut = True
+ * Algorithm = table-driven
+ */
+
+#include "hal.h"
+#include "hal_internal.h"
+
+#ifndef HAL_CRC32_TINY
+#define HAL_CRC32_TINY 0
+#endif
+
+#if HAL_CRC32_TINY
+
+static const hal_crc32_t crc_table[16] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+};
+
+hal_crc32_t hal_crc32_update(hal_crc32_t crc, const void *data, size_t data_len)
+{
+ const unsigned char *d = (const unsigned char *)data;
+ unsigned int tbl_idx;
+
+ while (data_len--) {
+ tbl_idx = crc ^ (*d >> (0 * 4));
+ crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
+ tbl_idx = crc ^ (*d >> (1 * 4));
+ crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4);
+
+ d++;
+ }
+ return crc & 0xffffffff;
+}
+
+#else /* HAL_CRC32_TINY */
+
+static const hal_crc32_t crc_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+hal_crc32_t hal_crc32_update(hal_crc32_t crc, const void *data, size_t data_len)
+{
+ const unsigned char *d = (const unsigned char *)data;
+ unsigned int tbl_idx;
+
+ while (data_len--) {
+ tbl_idx = (crc ^ *d) & 0xff;
+ crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
+
+ d++;
+ }
+ return crc & 0xffffffff;
+}
+
+#endif /* HAL_CRC32_TINY */
diff --git a/daemon.c b/daemon.c
index b30d730..ff95353 100644
--- a/daemon.c
+++ b/daemon.c
@@ -74,7 +74,7 @@ static void poll_add(int fd)
{
/* add 4 entries at a time to avoid having to realloc too often */
#define NNEW 4
-
+
/* expand the array if necessary */
if (nfds == npollfds) {
npollfds = nfds + NNEW;
@@ -247,7 +247,7 @@ int main(int argc, char *argv[])
perror("poll");
exit(EXIT_FAILURE);
}
-
+
for (nfds_t i = 0; i < nfds; ++i) {
if (pollfds[i].revents != 0) {
/* XXX POLLERR|POLLHUP|POLLNVAL */
diff --git a/hal.h b/hal.h
index 9d5a32b..72b1d58 100644
--- a/hal.h
+++ b/hal.h
@@ -39,6 +39,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
+#include <string.h>
/*
* A handy macro from cryptlib.
@@ -143,6 +144,20 @@
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_NOT_SET, "Master key (Key Encryption Key) not set") \
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_FAIL, "Master key generic failure") \
DEFINE_HAL_ERROR(HAL_ERROR_MASTERKEY_BAD_LENGTH, "Master key of unacceptable length") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KS_DRIVER_NOT_FOUND, "Keystore driver not found") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_BAD_CRC, "Bad CRC in keystore") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE, "Unsupported keystore block type") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_LOST_DATA, "Keystore appears to have lost data") \
+ DEFINE_HAL_ERROR(HAL_ERROR_BAD_ATTRIBUTE_LENGTH, "Bad attribute length") \
+ DEFINE_HAL_ERROR(HAL_ERROR_ATTRIBUTE_NOT_FOUND, "Attribute not found") \
+ DEFINE_HAL_ERROR(HAL_ERROR_NO_KEY_INDEX_SLOTS, "No key index slots available") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_UUID_MISORDERED, "Key index UUID misordered") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_CHUNK_ORPHANED, "Key index chunk orphaned") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_CHUNK_MISSING, "Key index chunk missing") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KSI_INDEX_CHUNK_OVERLAPS, "Key index chunk overlaps") \
+ DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE, "Wrong block type in keystore") \
+ DEFINE_HAL_ERROR(HAL_ERROR_RPC_PROTOCOL_ERROR, "RPC protocol error") \
+ DEFINE_HAL_ERROR(HAL_ERROR_NOT_IMPLEMENTED, "Not implemented") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -246,14 +261,14 @@ typedef struct hal_hash_driver hal_hash_driver_t;
*/
typedef enum {
- hal_digest_algorithm_none,
- hal_digest_algorithm_sha1,
- hal_digest_algorithm_sha224,
- hal_digest_algorithm_sha256,
- hal_digest_algorithm_sha512_224,
- hal_digest_algorithm_sha512_256,
- hal_digest_algorithm_sha384,
- hal_digest_algorithm_sha512
+ HAL_DIGEST_ALGORITHM_NONE,
+ HAL_DIGEST_ALGORITHM_SHA1,
+ HAL_DIGEST_ALGORITHM_SHA224,
+ HAL_DIGEST_ALGORITHM_SHA256,
+ HAL_DIGEST_ALGORITHM_SHA512_224,
+ HAL_DIGEST_ALGORITHM_SHA512_256,
+ HAL_DIGEST_ALGORITHM_SHA384,
+ HAL_DIGEST_ALGORITHM_SHA512
} hal_digest_algorithm_t;
typedef struct {
@@ -553,6 +568,26 @@ extern hal_error_t hal_ecdsa_verify(const hal_core_t *core,
const uint8_t * const signature, const size_t signature_len);
/*
+ * UUID stuff. All UUIDs we use (or are likely to use) are type 4 "random" UUIDs
+ */
+
+typedef struct { uint8_t uuid[16]; } hal_uuid_t;
+
+#define HAL_UUID_TEXT_SIZE (sizeof("00112233-4455-6677-8899-aabbccddeeff"))
+
+static inline int hal_uuid_cmp(const hal_uuid_t * const a, const hal_uuid_t * const b)
+{
+ return memcmp(a, b, sizeof(hal_uuid_t));
+}
+
+extern hal_error_t hal_uuid_gen(hal_uuid_t *uuid);
+
+extern hal_error_t hal_uuid_parse(hal_uuid_t *uuid, const char * const string);
+
+extern hal_error_t hal_uuid_format(const hal_uuid_t * const uuid,
+ char *buffer, const size_t buffer_len);
+
+/*
* Higher level RPC-based mechanism for working with HSM at arm's
* length, using handles instead of direct access to the cores.
*
@@ -675,8 +710,6 @@ extern hal_error_t hal_rpc_hash_finalize(const hal_hash_handle_t hash,
* a session handle and which ones don't...).
*/
-#define HAL_RPC_PKEY_NAME_MAX 128
-
typedef struct { uint32_t handle; } hal_pkey_handle_t;
typedef uint32_t hal_key_flags_t;
@@ -684,28 +717,43 @@ typedef uint32_t hal_key_flags_t;
#define HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE (1 << 0)
#define HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT (1 << 1)
#define HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT (1 << 2)
-#define HAL_KEY_FLAG_PROXIMATE (1 << 3)
+#define HAL_KEY_FLAG_TOKEN (1 << 3)
+#define HAL_KEY_FLAG_PUBLIC (1 << 4)
+
+/*
+ * hal_pkey_attribute_t.length would be size_t, except that we also
+ * need it to transport HAL_PKEY_ATTRIBUTE_NIL safely, which we can
+ * only do with a known-width type. The RPC code conveys size_t as a
+ * uint32_t in any case, so we just use that here and have done.
+ */
+
+typedef struct {
+ uint32_t type;
+ uint32_t length;
+ const void *value;
+} hal_pkey_attribute_t;
+
+#define HAL_PKEY_ATTRIBUTE_NIL (0xFFFFFFFF)
extern hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags);
-extern hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client,
+extern hal_error_t hal_rpc_pkey_open(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags);
extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags);
@@ -713,7 +761,7 @@ extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
extern hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags);
@@ -721,12 +769,12 @@ extern hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey);
extern hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey);
-extern hal_error_t hal_rpc_pkey_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len);
-
extern hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *type);
+extern hal_error_t hal_rpc_pkey_get_key_curve(const hal_pkey_handle_t pkey,
+ hal_curve_name_t *curve);
+
extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_pkey_handle_t pkey,
hal_key_flags_t *flags);
@@ -735,37 +783,49 @@ extern size_t hal_rpc_pkey_get_public_key_len(const hal_pkey_handle_t pkey);
extern hal_error_t hal_rpc_pkey_get_public_key(const hal_pkey_handle_t pkey,
uint8_t *der, size_t *der_len, const size_t der_max);
-extern hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+extern hal_error_t hal_rpc_pkey_sign(const hal_pkey_handle_t pkey,
const hal_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_session_handle_t session,
- const hal_pkey_handle_t pkey,
+extern hal_error_t hal_rpc_pkey_verify(const hal_pkey_handle_t pkey,
const hal_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_pkey_info_t;
-
-extern hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max,
- hal_key_flags_t flags);
+extern hal_error_t hal_rpc_pkey_match(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid);
+
+extern hal_error_t hal_rpc_pkey_set_attributes(const hal_pkey_handle_t pkey,
+ const hal_pkey_attribute_t *const attributes,
+ const unsigned attributes_len);
+
+extern hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len);
extern hal_error_t hal_rpc_client_init(void);
+
extern hal_error_t hal_rpc_client_close(void);
+
extern hal_error_t hal_rpc_server_init(void);
+
extern hal_error_t hal_rpc_server_close(void);
-extern hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen);
+
+extern hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen,
+ uint8_t * const obuf, size_t * const olen);
+
extern void hal_rpc_server_main(void);
#endif /* _HAL_H_ */
diff --git a/hal_internal.h b/hal_internal.h
index 5e08c4e..9aa360b 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -36,6 +36,8 @@
#ifndef _HAL_INTERNAL_H_
#define _HAL_INTERNAL_H_
+#include <string.h>
+
#include "hal.h"
#include "verilog_constants.h"
@@ -67,6 +69,20 @@ inline uint32_t htonl(uint32_t w)
#endif
/*
+ * Static memory allocation on start-up. Don't use this except where
+ * really necessary. By design, there's no way to free this, we don't
+ * want to have to manage a heap. Intent is just to allow allocation
+ * things like the large-ish ks_index arrays used by ks_flash.c from a
+ * memory source external to the executable image file (eg, from the
+ * secondary SDRAM chip on the Cryptech Alpha board).
+ *
+ * We shouldn't need this except on the HSM, so for now we don't bother
+ * with implementing a version of this based on malloc() or sbrk().
+ */
+
+extern void *hal_allocate_static_memory(const size_t size);
+
+/*
* Longest hash block and digest we support at the moment.
*/
@@ -169,21 +185,20 @@ typedef struct {
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags);
- hal_error_t (*find)(const hal_client_handle_t client,
+ hal_error_t (*open)(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags);
hal_error_t (*generate_rsa)(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags);
@@ -191,7 +206,7 @@ typedef struct {
hal_error_t (*generate_ec)(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags);
@@ -199,11 +214,11 @@ typedef struct {
hal_error_t (*delete)(const hal_pkey_handle_t pkey);
- hal_error_t (*rename)(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len);
-
hal_error_t (*get_key_type)(const hal_pkey_handle_t pkey,
- hal_key_type_t *key_type);
+ hal_key_type_t *type);
+
+ hal_error_t (*get_key_curve)(const hal_pkey_handle_t pkey,
+ hal_curve_name_t *curve);
hal_error_t (*get_key_flags)(const hal_pkey_handle_t pkey,
hal_key_flags_t *flags);
@@ -213,22 +228,37 @@ typedef struct {
hal_error_t (*get_public_key)(const hal_pkey_handle_t pkey,
uint8_t *der, size_t *der_len, const size_t der_max);
- hal_error_t (*sign)(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+ hal_error_t (*sign)(const hal_pkey_handle_t pkey,
const hal_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);
- hal_error_t (*verify)(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+ hal_error_t (*verify)(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
const uint8_t * const input, const size_t input_len,
const uint8_t * const signature, const size_t signature_len);
- hal_error_t (*list)(hal_pkey_info_t *result,
+ hal_error_t (*match)(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
unsigned *result_len,
const unsigned result_max,
- hal_key_flags_t flags);
+ const hal_uuid_t * const previous_uuid);
+
+ hal_error_t (*set_attributes)(const hal_pkey_handle_t pkey,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len);
+
+ hal_error_t (*get_attributes)(const hal_pkey_handle_t pkey,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len);
} hal_rpc_pkey_dispatch_t;
@@ -241,7 +271,7 @@ extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote
* See code in rpc_pkey.c for how this flag fits into the pkey handle.
*/
-#define HAL_PKEY_HANDLE_PROXIMATE_FLAG (1 << 31)
+#define HAL_PKEY_HANDLE_TOKEN_FLAG (1 << 31)
/*
* Mostly used by the local_pkey code, but the mixed_pkey code needs
@@ -251,19 +281,33 @@ extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote
* and just pass the plain hash for everything else.
*/
-extern hal_error_t hal_rpc_pkey_pkcs1_construct_digestinfo(const hal_hash_handle_t handle,
- uint8_t *digest_info, size_t *digest_info_len,
- const size_t digest_info_max);
+extern hal_error_t hal_rpc_pkcs1_construct_digestinfo(const hal_hash_handle_t handle,
+ uint8_t *digest_info, size_t *digest_info_len,
+ const size_t digest_info_max);
/*
- * Keystore API.
- *
- * The original design for this subsystem used two separate tables,
- * one for RSA keys, one for EC keys, because the RSA keys are so much
- * larger than the EC keys. This led to unnecessarily complex and
- * duplicated code, so for now we treat all keys the same, and waste
- * the unneeded space in the case of EC keys.
+ * CRC-32 stuff (for flash keystore, etc). Dunno if we want a Verilog
+ * implementation of this, or if it would even be faster than doing it
+ * the main CPU taking I/O overhead and so forth into account.
*
+ * These prototypes were generated by pycrc.py, see notes in crc32.c.
+ */
+
+typedef uint32_t hal_crc32_t;
+
+static inline hal_crc32_t hal_crc32_init(void)
+{
+ return 0xffffffff;
+}
+
+extern hal_crc32_t hal_crc32_update(hal_crc32_t crc, const void *data, size_t data_len);
+
+static inline hal_crc32_t hal_crc32_finalize(hal_crc32_t crc)
+{
+ return crc ^ 0xffffffff;
+}
+
+/*
* 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:
*
@@ -277,32 +321,21 @@ extern hal_error_t hal_rpc_pkey_pkcs1_construct_digestinfo(const hal_hash_handle
* Plus we need a bit of AES-keywrap overhead, since we're storing the
* wrapped form (see hal_aes_keywrap_cyphertext_length()).
*
- * We also need to store PINs somewhere, so they go into the keystore
- * data structure even though they're not keys. Like keys, they're
- * stored in a relatively safe form (PBKDF2), so while we would prefer
- * to keep them private, they don't require tamper-protected RAM.
+ * A buffer big enough for a 8192-bit RSA key would overflow one
+ * sub-sector on the flash chip we're using on the Alpha. We could
+ * invent some more complex scheme where key blocks are allowed to
+ * span multiple sub-sectors, but since an 8192-bit RSA key would also
+ * be unusably slow with the current RSA implementation, for the
+ * moment we take the easy way out and cap this at 4096-bit RSA.
*/
-#define HAL_KS_WRAPPED_KEYSIZE ((4655 + 15) & ~7)
+#define HAL_KS_WRAPPED_KEYSIZE ((2351 + 15) & ~7)
-#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
-#define HAL_STATIC_PKEY_STATE_BLOCKS 0
-#endif
-
-/* This struct is ordered such that all metadata appears before the
- * big buffers, in order for all metadata to be loaded with a single
- * page read from e.g. the ks_flash module.
+/*
+ * PINs.
+ *
+ * The functions here might want renaming, eg, to hal_pin_*().
*/
-typedef struct {
- hal_key_type_t type;
- hal_curve_name_t curve;
- hal_key_flags_t flags;
- uint8_t in_use;
- size_t name_len;
- size_t der_len;
- uint8_t name[HAL_RPC_PKEY_NAME_MAX];
- uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
-} hal_ks_key_t;
#ifndef HAL_PIN_SALT_LENGTH
#define HAL_PIN_SALT_LENGTH 16
@@ -314,40 +347,47 @@ typedef struct {
uint8_t salt[HAL_PIN_SALT_LENGTH];
} hal_ks_pin_t;
-typedef struct {
-
-#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
- hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
-#else
- #warning No keys in keydb
-#endif
-
- hal_ks_pin_t wheel_pin;
- hal_ks_pin_t so_pin;
- hal_ks_pin_t user_pin;
-
-} hal_ks_keydb_t;
-
extern hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client,
const uint32_t iterations);
+extern hal_error_t hal_get_pin(const hal_user_t user,
+ const hal_ks_pin_t **pin);
+
+extern hal_error_t hal_set_pin(const hal_user_t user,
+ const hal_ks_pin_t * const pin);
+
/*
- * Internal functions within the keystore implementation. Think of
- * these as concrete methods for the keystore API subclassed onto
- * various storage technologies.
+ * Master key memory (MKM) and key-encryption-key (KEK).
+ *
+ * Providing a mechanism for storing the KEK in flash is a horrible
+ * kludge which defeats the entire purpose of having the MKM. We
+ * support it for now because the Alpha hardware does not yet have
+ * a working battery backup for the MKM, but it should go away RSN.
*/
-extern const hal_ks_keydb_t *hal_ks_get_keydb(void);
+#ifndef HAL_MKM_FLASH_BACKUP_KLUDGE
+#define HAL_MKM_FLASH_BACKUP_KLUDGE 1
+#endif
+
+#ifndef KEK_LENGTH
+#define KEK_LENGTH (bitsToBytes(256))
+#endif
+
+extern hal_error_t hal_mkm_get_kek(uint8_t *kek, size_t *kek_len, const size_t kek_max);
+
+extern hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len);
+extern hal_error_t hal_mkm_volatile_write(const uint8_t * const buf, const size_t len);
+extern hal_error_t hal_mkm_volatile_erase(const size_t len);
-extern hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating);
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
-extern hal_error_t hal_ks_del_keydb(const int loc);
+/* #warning MKM flash backup kludge enabled. Do NOT use this in production! */
-extern hal_error_t hal_ks_get_kek(uint8_t *kek,
- size_t *kek_len,
- const size_t kek_max);
+extern hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len);
+extern hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len);
+extern hal_error_t hal_mkm_flash_erase(const size_t len);
+
+#endif
/*
* Keystore API for use by the pkey implementation.
@@ -359,44 +399,405 @@ extern hal_error_t hal_ks_get_kek(uint8_t *kek,
* Unclear whether these should also call the ASN.1 encode/decode
* functions. For the moment, the answer is no, but we may need to
* revisit this as the underlying Verilog API evolves.
+ *
+ * hal_pkey_slot_t is defined here too, so that keystore drivers can
+ * piggyback on the pkey database for storage related to keys on which
+ * the user currently has an active pkey handle. Nothing outside the
+ * pkey and keystore code should touch this.
*/
-extern hal_error_t hal_ks_store(const hal_key_type_t type,
- const hal_curve_name_t curve,
- const hal_key_flags_t flags,
- const uint8_t * const name, const size_t name_len,
- const uint8_t * const der, const size_t der_len,
- int *hint);
+typedef struct {
+ hal_client_handle_t client_handle;
+ hal_session_handle_t session_handle;
+ hal_pkey_handle_t pkey_handle;
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ hal_uuid_t name;
+ int 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.
+ */
+} hal_pkey_slot_t;
+
+typedef struct hal_ks_driver hal_ks_driver_t;
+
+typedef struct hal_ks hal_ks_t;
+
+struct hal_ks_driver {
+
+ hal_error_t (*init)(const hal_ks_driver_t * const driver,
+ const int alloc);
-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);
+ hal_error_t (*shutdown)(const hal_ks_driver_t * const driver);
-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);
+ hal_error_t (*open)(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks);
-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);
+ hal_error_t (*close)(hal_ks_t *ks);
-extern hal_error_t hal_ks_rename(const hal_key_type_t type,
- const uint8_t * const old_name, const size_t old_name_len,
- const uint8_t * const new_name, const size_t new_name_len,
- int *hint);
+ hal_error_t (*store)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len);
-extern hal_error_t hal_ks_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max);
+ hal_error_t (*fetch)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max);
-extern hal_error_t hal_ks_get_pin(const hal_user_t user,
- const hal_ks_pin_t **pin);
+ hal_error_t (*delete)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot);
+
+ hal_error_t (*match)(hal_ks_t *ks,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid);
+
+ hal_error_t (*set_attributes)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len);
+
+ hal_error_t (*get_attributes)(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len);
+
+};
+
+
+struct hal_ks {
+ const hal_ks_driver_t *driver;
+ /*
+ * Any other common portions of hal_ks_t go here.
+ */
+
+ /*
+ * Driver-specific stuff is handled by a form of subclassing:
+ * driver module embeds this structure at the head of whatever
+ * else it needs, and performs casts as needed.
+ */
+};
+
+extern const hal_ks_driver_t
+ hal_ks_volatile_driver[1],
+ hal_ks_token_driver[1];
+
+static inline hal_error_t hal_ks_init(const hal_ks_driver_t * const driver,
+ const int alloc)
+{
+ if (driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (driver->init == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return driver->init(driver, alloc);
+}
+
+static inline hal_error_t hal_ks_shutdown(const hal_ks_driver_t * const driver)
+{
+ if (driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (driver->shutdown == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return driver->shutdown(driver);
+}
+
+static inline hal_error_t hal_ks_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ if (driver == NULL || ks == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (driver->open == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return driver->open(driver, ks);
+}
+
+static inline hal_error_t hal_ks_close(hal_ks_t *ks)
+{
+ if (ks == NULL || ks->driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->close == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->close(ks);
+}
+
+static inline hal_error_t hal_ks_store(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (ks == NULL || ks->driver == NULL || slot == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->store == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->store(ks, slot, der, der_len);
+}
+
+static inline hal_error_t hal_ks_fetch(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->fetch == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->fetch(ks, slot, der, der_len, der_max);
+}
+
+static inline hal_error_t hal_ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot)
+{
+ if (ks == NULL || ks->driver == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->delete == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->delete(ks, slot);
+}
+
+static inline hal_error_t hal_ks_match(hal_ks_t *ks,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
+{
+ if (ks == NULL || ks->driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->match == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->match(ks, client, session, type, curve, flags, attributes, attributes_len,
+ result, result_len, result_max, previous_uuid);
+}
+
+static inline hal_error_t hal_ks_set_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
+{
+ if (ks == NULL || ks->driver == NULL || slot == NULL ||
+ attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->set_attributes == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->set_attributes(ks, slot, attributes, attributes_len);
+}
+
+static inline hal_error_t hal_ks_get_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
+{
+ if (ks == NULL || ks->driver == NULL || slot == NULL ||
+ attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->get_attributes == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ return ks->driver->get_attributes(ks, slot, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len);
+}
+
+/*
+ * Keystore index. This is intended to be usable by both memory-based
+ * (in-memory, mmap(), ...) keystores and keystores based on raw flash.
+ * Some of the features aren't really necessary for memory-based keystores,
+ * but should be harmless.
+ *
+ * General approach is multiple arrays, all but one of which are
+ * indexed by "block" numbers, where a block number might be a slot in
+ * yet another static array, the number of a flash sub-sector, or
+ * whatever is the appropriate unit for holding one keystore record.
+ *
+ * The index array contains nothing but flags and block numbers, and
+ * is deliberately a small data structure so that moving data around
+ * within it is relatively cheap.
+ *
+ * The index array is divided into two portions: the index proper, and
+ * the free queue. The index proper is ordered according to the names
+ * (UUIDs) of the corresponding blocks; the free queue is a FIFO, to
+ * support a simplistic form of wear leveling in flash-based keystores.
+ *
+ * Key names are kept in a separate array, indexed by block number.
+ * Key names here are a composite of the key's UUID and a "chunk"
+ * number; the latter allows storage of keys whose total size exceeds
+ * one block (whatever a block is). For the moment we keep the UUID
+ * and the chunk number in a single array, which may provide (very)
+ * slightly better performance due to reference locality in SDRAM, but
+ * this may change if we need to reclaim the space wasted by structure
+ * size rounding.
+ *
+ * The all-zeros UUID, which (by definition) cannot be a valid key
+ * UUID, is reserved for the (non-key) block used to stash PINs and
+ * other small data which aren't really part of the keystore proper
+ * but are kept with it because the keystore is the flash we have.
+ *
+ * Note that this API deliberately says nothing about how the keys
+ * themselves are stored, that's up to the keystore driver. This
+ * portion of the API is only concerned with allocation and naming.
+ */
+
+typedef struct {
+ hal_uuid_t name; /* Key name */
+ uint8_t chunk; /* Key chunk number */
+} hal_ks_name_t;
+
+typedef struct {
+ unsigned size; /* Array length */
+ unsigned used; /* How many blocks are in use */
+ uint16_t *index; /* Index/freelist array */
+ hal_ks_name_t *names; /* Keyname array */
+} hal_ks_index_t;
+
+/*
+ * Finish setting up key index. Caller must populate index, free
+ * list, and name array.
+ *
+ * This function checks a few things then sorts the index proper.
+ *
+ * If driver cares about wear leveling, driver must supply the free
+ * list in the desired order (FIFO); figuring out what that order is a
+ * problem for the keystore driver.
+ */
+extern hal_error_t hal_ks_index_setup(hal_ks_index_t *ksi);
+
+/*
+ * Find a key block, return its block number.
+ */
+extern hal_error_t hal_ks_index_find(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint);
+
+/*
+ * Find all the blocks in a key, return the block numbers.
+ */
+extern hal_error_t hal_ks_index_find_range(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned max_blocks,
+ unsigned *n_blocks,
+ unsigned *blocknos,
+ int *hint,
+ const int strict);
+
+/*
+ * Add a key block, return its block number.
+ */
+extern hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint);
+
+/*
+ * Delete a key block, returns its block number (driver may need it).
+ */
+extern hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint);
+
+/*
+ * Delete all of blocks in a key, returning the block numbers.
+ */
+
+extern hal_error_t hal_ks_index_delete_range(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned max_blocks,
+ unsigned *n_blocks,
+ unsigned *blocknos,
+ int *hint);
+
+/*
+ * Replace a key block with a new one, return new block number.
+ * Name of block does not change. This is an optimization of
+ * a delete immediately followed by an add for the same name.
+ */
+
+extern hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint);
+
+/*
+ * Check the index for errors. At least for the moment, this just
+ * reports errors, it doesn't attempt to fix them.
+ */
+
+extern hal_error_t hal_ks_index_fsck(hal_ks_index_t *ksi);
+
+/*
+ * Keystore attribute utilities, for use by keystore drivers.
+ */
-extern hal_error_t hal_ks_set_pin(const hal_user_t user,
- const hal_ks_pin_t * const pin);
+extern const size_t hal_ks_attribute_header_size;
+
+extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ size_t *total_len);
+
+extern hal_error_t hal_ks_attribute_delete(uint8_t *bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type);
+
+extern hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type,
+ const uint8_t * const value,
+ const size_t value_len);
/*
* RPC lowest-level send and receive routines. These are blocking, and
@@ -421,7 +822,7 @@ extern hal_error_t hal_rpc_server_transport_close(void);
*/
typedef enum {
- RPC_FUNC_GET_VERSION = 0,
+ RPC_FUNC_GET_VERSION,
RPC_FUNC_GET_RANDOM,
RPC_FUNC_SET_PIN,
RPC_FUNC_LOGIN,
@@ -435,7 +836,7 @@ typedef enum {
RPC_FUNC_HASH_UPDATE,
RPC_FUNC_HASH_FINALIZE,
RPC_FUNC_PKEY_LOAD,
- RPC_FUNC_PKEY_FIND,
+ RPC_FUNC_PKEY_OPEN,
RPC_FUNC_PKEY_GENERATE_RSA,
RPC_FUNC_PKEY_GENERATE_EC,
RPC_FUNC_PKEY_CLOSE,
@@ -446,8 +847,10 @@ typedef enum {
RPC_FUNC_PKEY_GET_PUBLIC_KEY,
RPC_FUNC_PKEY_SIGN,
RPC_FUNC_PKEY_VERIFY,
- RPC_FUNC_PKEY_LIST,
- RPC_FUNC_PKEY_RENAME,
+ RPC_FUNC_PKEY_MATCH,
+ RPC_FUNC_PKEY_GET_KEY_CURVE,
+ RPC_FUNC_PKEY_SET_ATTRIBUTES,
+ RPC_FUNC_PKEY_GET_ATTRIBUTES,
} rpc_func_num_t;
#define RPC_VERSION 0x01010000 /* 1.1.0.0 */
diff --git a/hash.c b/hash.c
index 302ccd2..2c745a8 100644
--- a/hash.c
+++ b/hash.c
@@ -200,7 +200,7 @@ static const uint8_t
*/
const hal_hash_descriptor_t hal_hash_sha1[1] = {{
- hal_digest_algorithm_sha1,
+ HAL_DIGEST_ALGORITHM_SHA1,
SHA1_BLOCK_LEN, SHA1_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha1, sizeof(dalgid_sha1),
@@ -208,7 +208,7 @@ const hal_hash_descriptor_t hal_hash_sha1[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha224[1] = {{
- hal_digest_algorithm_sha256,
+ HAL_DIGEST_ALGORITHM_SHA256,
SHA256_BLOCK_LEN, SHA224_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha224, sizeof(dalgid_sha224),
@@ -216,7 +216,7 @@ const hal_hash_descriptor_t hal_hash_sha224[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha256[1] = {{
- hal_digest_algorithm_sha256,
+ HAL_DIGEST_ALGORITHM_SHA256,
SHA256_BLOCK_LEN, SHA256_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha256, sizeof(dalgid_sha256),
@@ -224,7 +224,7 @@ const hal_hash_descriptor_t hal_hash_sha256[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{
- hal_digest_algorithm_sha512_224,
+ HAL_DIGEST_ALGORITHM_SHA512_224,
SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_224, sizeof(dalgid_sha512_224),
@@ -232,7 +232,7 @@ const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{
- hal_digest_algorithm_sha512_256,
+ HAL_DIGEST_ALGORITHM_SHA512_256,
SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512_256, sizeof(dalgid_sha512_256),
@@ -240,7 +240,7 @@ const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha384[1] = {{
- hal_digest_algorithm_sha384,
+ HAL_DIGEST_ALGORITHM_SHA384,
SHA512_BLOCK_LEN, SHA384_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha384, sizeof(dalgid_sha384),
@@ -248,7 +248,7 @@ const hal_hash_descriptor_t hal_hash_sha384[1] = {{
}};
const hal_hash_descriptor_t hal_hash_sha512[1] = {{
- hal_digest_algorithm_sha512,
+ HAL_DIGEST_ALGORITHM_SHA512,
SHA512_BLOCK_LEN, SHA512_DIGEST_LEN,
sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t),
dalgid_sha512, sizeof(dalgid_sha512),
diff --git a/ks.c b/ks.c
deleted file mode 100644
index 48d4751..0000000
--- a/ks.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * 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"
-#include "last_gasp_pin_internal.h"
-
-#define KEK_LENGTH (bitsToBytes(256))
-
-/*
- * In "remote" and "mixed" RPC modes we're a software only RPC client
- * without (direct) access to secure hardware, thus there is no real
- * point in encrypting keys. As precautions, we (a) warn about this
- * when configured in one of these modes, and (b) refuse to store any
- * sort of private keys.
- */
-
-#define USE_KEK (RPC_CLIENT != RPC_CLIENT_REMOTE && RPC_CLIENT != RPC_CLIENT_MIXED)
-
-#if !USE_KEK
-#warning ks.c compiled without KEK support and will only accept public keys -- this is normal for the host-side build of libhsm
-#endif
-
-static inline int acceptable_key_type(const hal_key_type_t type)
-{
- switch (type) {
-#if USE_KEK
- case HAL_KEY_TYPE_RSA_PRIVATE:
- case HAL_KEY_TYPE_EC_PRIVATE:
-#endif
- case HAL_KEY_TYPE_RSA_PUBLIC:
- 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 || 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_KEY_NAME_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));
- k.der_len = sizeof(k.der);
-
-#if USE_KEK
-
- 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;
-
-#else /* USE_KEK */
-
- if (der_len > k.der_len)
- return HAL_ERROR_RESULT_TOO_LONG;
-
- k.der_len = der_len;
- memcpy(k.der, der, der_len);
-
-#endif /* USE_KEK */
-
- 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, 0)) != 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 && 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 || !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 || !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) {
-
-#if USE_KEK
-
- 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;
-
-#else /* USE_KEK */
-
- if (k->der_len > der_max)
- return HAL_ERROR_RESULT_TOO_LONG;
-
- if (der_len != NULL)
- *der_len = k->der_len;
-
- memcpy(der, k->der, k->der_len);
-
-#endif /* USE_KEK */
- }
-
- 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 || !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_rename(const hal_key_type_t type,
- const uint8_t * const old_name, const size_t old_name_len,
- const uint8_t * const new_name, const size_t new_name_len,
- int *hint)
-{
- if (old_name == NULL || new_name == NULL || !acceptable_key_type(type))
- return HAL_ERROR_BAD_ARGUMENTS;
-
- if (new_name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
-
- const hal_ks_keydb_t * const db = hal_ks_get_keydb();
- int hint_ = -1;
-
- if (db == NULL)
- return HAL_ERROR_KEYSTORE_ACCESS;
-
- if (find(db, type, new_name, new_name_len, NULL))
- return HAL_ERROR_KEY_NAME_IN_USE;
-
- if (hint == NULL)
- hint = &hint_;
-
- if (!find(db, type, old_name, old_name_len, hint))
- return HAL_ERROR_KEY_NOT_FOUND;
-
- hal_ks_key_t k = db->keys[*hint];
-
- assert(new_name_len <= sizeof(k.name));
- memcpy(k.name, new_name, new_name_len);
- k.name_len = new_name_len;
-
- return hal_ks_set_keydb(&k, *hint, 1);
-}
-
-hal_error_t hal_ks_list(hal_pkey_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;
-}
-
-hal_error_t hal_ks_get_pin(const hal_user_t user,
- const hal_ks_pin_t **pin)
-{
- if (pin == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- const hal_ks_keydb_t * const db = hal_ks_get_keydb();
-
- if (db == NULL)
- return HAL_ERROR_KEYSTORE_ACCESS;
-
- switch (user) {
- case HAL_USER_WHEEL: *pin = &db->wheel_pin; break;
- case HAL_USER_SO: *pin = &db->so_pin; break;
- case HAL_USER_NORMAL: *pin = &db->user_pin; break;
- default: return HAL_ERROR_BAD_ARGUMENTS;
- }
-
-#warning Need better "Have we been initialized yet?" test
- /*
- * If we were looking for the WHEEL PIN and it appears to be
- * completely unset, return the compiled-in last-gasp PIN. This is
- * a terrible answer, but we need some kind of bootstrapping
- * mechanism. Feel free to suggest something better.
- *
- * We probably need some more general "have we been initialized?"
- * state somewhere, and might want to refuse to do things like
- * storing keys until we've been initialized and the appropriate
- * PINs have been set.
- *
- * Just to make things more fun, some drivers return all zeros for
- * "this has never been set", some return all ones to indicate the
- * same thing. REALLY need a flag somewhere.
- */
-
- uint8_t u00 = 0x00, uFF = 0xFF;
- for (int i = 0; i < sizeof((*pin)->pin); i++) {
- u00 |= (*pin)->pin[i];
- uFF &= (*pin)->pin[i];
- }
- for (int i = 0; i < sizeof((*pin)->salt); i++) {
- u00 |= (*pin)->salt[i];
- uFF &= (*pin)->salt[i];
- }
- if (user == HAL_USER_WHEEL && ((u00 == 0x00 && (*pin)->iterations == 0x00000000) ||
- (uFF == 0xFF && (*pin)->iterations == 0xFFFFFFFF)))
- *pin = &hal_last_gasp_pin;
-
- return HAL_OK;
-}
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/ks_attribute.c b/ks_attribute.c
new file mode 100644
index 0000000..92e450d
--- /dev/null
+++ b/ks_attribute.c
@@ -0,0 +1,178 @@
+/*
+ * ks_attribute.c
+ * --------------
+ * Keystore attribute API. This is internal within libhal.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+/*
+ * Read and write attribute headers (type and length). We could do
+ * this with a structure type and casts, but that has portability
+ * issues, and doing it this way just isn't expensive enough to worry about.
+ */
+
+const size_t hal_ks_attribute_header_size = 6;
+
+static inline hal_error_t read_header(const uint8_t * const bytes, const size_t bytes_len,
+ uint32_t *attribute_type, size_t *attribute_len)
+{
+ if (bytes == NULL || bytes_len < hal_ks_attribute_header_size ||
+ attribute_type == NULL || attribute_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *attribute_type = ((bytes[0] << 24) |
+ (bytes[1] << 16) |
+ (bytes[2] << 8) |
+ (bytes[3] << 0));
+ *attribute_len = ((bytes[4] << 8) |
+ (bytes[5] << 0));
+
+ return HAL_OK;
+}
+
+static inline hal_error_t write_header(uint8_t *bytes, const size_t bytes_len,
+ const uint32_t attribute_type, const size_t attribute_len)
+{
+ if (bytes == NULL || bytes_len < hal_ks_attribute_header_size)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ bytes[0] = (attribute_type >> 24) & 0xFF;
+ bytes[1] = (attribute_type >> 16) & 0xFF;
+ bytes[2] = (attribute_type >> 8) & 0xFF;
+ bytes[3] = (attribute_type >> 0) & 0xFF;
+ bytes[4] = (attribute_len >> 8) & 0xFF;
+ bytes[5] = (attribute_len >> 0) & 0xFF;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes, const unsigned attributes_len,
+ size_t *total_len)
+{
+ if (bytes == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t *b = bytes;
+ const uint8_t * const end = bytes + bytes_len;
+
+ for (int i = 0; i < attributes_len; i++) {
+ uint32_t type;
+ size_t length;
+ hal_error_t err = read_header(b, end - b, &type, &length);
+ if (err != HAL_OK)
+ return err;
+ if (b + hal_ks_attribute_header_size + length > end)
+ return HAL_ERROR_BAD_ATTRIBUTE_LENGTH;
+ b += hal_ks_attribute_header_size;
+ if (attributes != NULL) {
+ attributes[i].type = type;
+ attributes[i].length = length;
+ attributes[i].value = b;
+ }
+ b += length;
+ }
+
+ if (total_len != NULL)
+ *total_len = b - bytes;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_attribute_delete(uint8_t *bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes, unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type)
+{
+ if (bytes == NULL || attributes == NULL || attributes_len == NULL || total_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ int i = 0;
+
+ while (i < *attributes_len && attributes[i].type != type)
+ i++;
+
+ if (i == *attributes_len)
+ return HAL_OK;
+
+ const size_t delete_length = hal_ks_attribute_header_size + attributes[i].length;
+ const size_t delete_offset = (uint8_t*) attributes[i].value - hal_ks_attribute_header_size - bytes;
+
+ if (delete_offset + delete_length > *total_len)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ memmove(bytes + delete_offset,
+ bytes + delete_offset + delete_length,
+ *total_len - delete_length - delete_offset);
+
+ return hal_ks_attribute_scan(bytes, bytes_len, attributes, --*attributes_len, total_len);
+}
+
+hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes, unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type,
+ const uint8_t * const value, const size_t value_len)
+
+{
+ if (bytes == NULL || attributes == NULL || attributes_len == NULL ||
+ total_len == NULL || value == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err
+ = hal_ks_attribute_delete(bytes, bytes_len, attributes, attributes_len, total_len, type);
+
+ if (err != HAL_OK)
+ return err;
+
+ if (*total_len + hal_ks_attribute_header_size + value_len > bytes_len)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ uint8_t *b = bytes + *total_len;
+
+ if ((err = write_header(b, bytes_len - *total_len, type, value_len)) != HAL_OK)
+ return err;
+
+ memcpy(b + hal_ks_attribute_header_size, value, value_len);
+
+ return hal_ks_attribute_scan(bytes, bytes_len, attributes, ++*attributes_len, total_len);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_flash.c b/ks_flash.c
index 9ba342a..f784539 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -33,315 +33,1945 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define HAL_OK LIBHAL_OK
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
#include "hal.h"
#include "hal_internal.h"
-#undef HAL_OK
+
+#include "last_gasp_pin_internal.h"
#define HAL_OK CMIS_HAL_OK
#include "stm-keystore.h"
-#include "masterkey.h"
#undef HAL_OK
-#include <string.h>
+/*
+ * Known block states.
+ *
+ * C does not guarantee any particular representation for enums, so
+ * including enums directly in the block header isn't safe. Instead,
+ * we use an access method which casts when reading from the header.
+ * Writing to the header isn't a problem, because C does guarantee
+ * that enum is compatible with *some* integer type, it just doesn't
+ * specify which one.
+ */
+
+typedef enum {
+ BLOCK_TYPE_ERASED = 0xFF, /* Pristine erased block (candidate for reuse) */
+ BLOCK_TYPE_ZEROED = 0x00, /* Zeroed block (recently used) */
+ BLOCK_TYPE_KEY = 0x55, /* Block contains key material */
+ BLOCK_TYPE_ATTR = 0x66, /* Block contains key attributes (overflow from key block) */
+ BLOCK_TYPE_PIN = 0xAA, /* Block contains PINs */
+ BLOCK_TYPE_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} flash_block_type_t;
+
+/*
+ * Block status.
+ */
+
+typedef enum {
+ BLOCK_STATUS_LIVE = 0x66, /* This is a live flash block */
+ BLOCK_STATUS_TOMBSTONE = 0x44, /* This is a tombstone left behind during an update */
+ BLOCK_STATUS_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} flash_block_status_t;
+
+/*
+ * Common header for all flash block types.
+ * A few of these fields are deliberately omitted from the CRC.
+ */
+
+typedef struct {
+ uint8_t block_type;
+ uint8_t block_status;
+ uint8_t total_chunks;
+ uint8_t this_chunk;
+ hal_crc32_t crc;
+} flash_block_header_t;
+
+/*
+ * Key block. Tail end of "der" field (after der_len) used for attributes.
+ */
+
+typedef struct {
+ flash_block_header_t header;
+ hal_uuid_t name;
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ size_t der_len;
+ unsigned attributes_len;
+ uint8_t der[]; /* Must be last field -- C99 "flexible array member" */
+} flash_key_block_t;
+
+#define SIZEOF_FLASH_KEY_BLOCK_DER \
+ (KEYSTORE_SUBSECTOR_SIZE - offsetof(flash_key_block_t, der))
+
+/*
+ * Key attribute overflow block (attributes which don't fit in der field of key block).
+ */
+
+typedef struct {
+ flash_block_header_t header;
+ hal_uuid_t name;
+ unsigned attributes_len;
+ uint8_t attributes[]; /* Must be last field -- C99 "flexible array member" */
+} flash_attributes_block_t;
+
+#define SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES \
+ (KEYSTORE_SUBSECTOR_SIZE - offsetof(flash_attributes_block_t, attributes))
+
+/*
+ * PIN block. Also includes space for backing up the KEK when
+ * HAL_MKM_FLASH_BACKUP_KLUDGE is enabled.
+ */
+
+typedef struct {
+ flash_block_header_t header;
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
+ uint32_t kek_set;
+ uint8_t kek[KEK_LENGTH];
+#endif
+} flash_pin_block_t;
+
+#define FLASH_KEK_SET 0x33333333
+
+/*
+ * One flash block.
+ */
+typedef union {
+ uint8_t bytes[KEYSTORE_SUBSECTOR_SIZE];
+ flash_block_header_t header;
+ flash_key_block_t key;
+ flash_attributes_block_t attr;
+ flash_pin_block_t pin;
+} flash_block_t;
-#define PAGE_SIZE_MASK (KEYSTORE_PAGE_SIZE - 1)
+/*
+ * In-memory cache.
+ */
+
+typedef struct {
+ unsigned blockno;
+ uint32_t lru;
+ flash_block_t block;
+} cache_block_t;
+
+/*
+ * In-memory database.
+ *
+ * The top-level structure is a static variable; the arrays are allocated at runtime
+ * using hal_allocate_static_memory() because they can get kind of large.
+ */
+
+#ifndef KS_FLASH_CACHE_SIZE
+#define KS_FLASH_CACHE_SIZE 4
+#endif
+
+#define NUM_FLASH_BLOCKS KEYSTORE_NUM_SUBSECTORS
+
+typedef struct {
+ hal_ks_t ks; /* Must be first (C "subclassing") */
+ hal_ks_index_t ksi;
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+ uint32_t cache_lru;
+ cache_block_t *cache;
+} db_t;
/*
- * Use a one-element array here so that references can be pointer-based
- * as in the other implementations, to ease re-merge at some later date.
+ * PIN block gets the all-zeros UUID, which will never be returned by
+ * the UUID generation code (by definition -- it's not a version 4 UUID).
*/
-static hal_ks_keydb_t db[1];
+const static hal_uuid_t pin_uuid = {{0}};
-#define FLASH_SECTOR_1_OFFSET (0 * KEYSTORE_SECTOR_SIZE)
-#define FLASH_SECTOR_2_OFFSET (1 * KEYSTORE_SECTOR_SIZE)
+/*
+ * The in-memory database structure itself is small, but the arrays it
+ * points to are large enough that they come from SDRAM allocated at
+ * startup.
+ */
-uint32_t _active_sector_offset()
+static db_t db;
+
+/*
+ * Type safe casts.
+ */
+
+static inline flash_block_type_t block_get_type(const flash_block_t * const block)
{
- /* XXX Load status bytes from both sectors and decide which is current. */
- #warning Have not implemented two flash sectors yet
- return FLASH_SECTOR_1_OFFSET;
+ assert(block != NULL);
+ return (flash_block_type_t) block->header.block_type;
}
-uint32_t _get_key_offset(uint32_t num)
+static inline flash_block_status_t block_get_status(const flash_block_t * const block)
{
- /* Reserve first two pages for flash sector state, PINs and future additions.
- * The three PINs alone currently occupy 3 * (64 + 16 + 4) bytes (252).
- */
- uint32_t offset = KEYSTORE_PAGE_SIZE * 2;
- uint32_t key_size = sizeof(*db->keys);
- uint32_t bytes_per_key = KEYSTORE_PAGE_SIZE * ((key_size / KEYSTORE_PAGE_SIZE) + 1);
- offset += num * bytes_per_key;
- return offset;
+ assert(block != NULL);
+ return (flash_block_status_t) block->header.block_status;
}
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
+/*
+ * Pick unused or least-recently-used slot in our in-memory cache.
+ *
+ * Updating lru values is caller's problem: if caller is using a cache
+ * slot as a temporary buffer and there's no point in caching the
+ * result, leave the lru values alone and the right thing will happen.
+ */
+
+static inline flash_block_t *cache_pick_lru(void)
{
- uint32_t offset, i, idx = 0, active_sector_offset;
- hal_ks_key_t *key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ uint32_t best_delta = 0;
+ int best_index = 0;
- memset(db, 0, sizeof(*db));
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
- if (keystore_check_id() != 1) return NULL;
+ if (db.cache[i].blockno == ~0)
+ return &db.cache[i].block;
- active_sector_offset = _active_sector_offset();
+ const uint32_t delta = db.cache_lru - db.cache[i].lru;
+ if (delta > best_delta) {
+ best_delta = delta;
+ best_index = i;
+ }
- /* The PINs are in the second page of the sector. */
- offset = active_sector_offset + KEYSTORE_PAGE_SIZE;
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
- offset = 0;
- memcpy(&db->wheel_pin, page_buf + offset, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(&db->so_pin, page_buf + offset, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(&db->user_pin, page_buf + offset, sizeof(db->user_pin));
+ }
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- idx++;
- continue;
- }
+ db.cache[best_index].blockno = ~0;
+ return &db.cache[best_index].block;
+}
- offset += active_sector_offset;
+/*
+ * Find a block in our in-memory cache; return block or NULL if not present.
+ */
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) return NULL;
+static inline flash_block_t *cache_find_block(const unsigned blockno)
+{
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
+ if (db.cache[i].blockno == blockno)
+ return &db.cache[i].block;
+ return NULL;
+}
- key = (hal_ks_key_t *) page_buf;
- if (key->in_use == 0xff) {
- /* unprogrammed data */
- idx++;
- continue;
- }
+/*
+ * Mark a block in our in-memory cache as being in current use.
+ */
- if (key->in_use == 1) {
- uint8_t *dst = (uint8_t *) &db->keys[idx];
- uint32_t to_read = sizeof(*db->keys);
-
- /* We already have the first page in page_buf. Put it into place. */
- memcpy(dst, page_buf, sizeof(page_buf));
- to_read -= sizeof(page_buf);
- dst += sizeof(page_buf);
-
- /* Read as many more full pages as possible */
- if (keystore_read_data (offset + KEYSTORE_PAGE_SIZE, dst, to_read & ~PAGE_SIZE_MASK) != 1) return NULL;
- dst += to_read & ~PAGE_SIZE_MASK;
- to_read &= PAGE_SIZE_MASK;
-
- if (to_read) {
- /* Partial last page. We can only read full pages so load it into page_buf. */
- if (keystore_read_data(offset + sizeof(*db->keys) - to_read, page_buf, sizeof(page_buf)) != 1) return NULL;
- memcpy(dst, page_buf, to_read);
- }
- }
- idx++;
+static inline void cache_mark_used(const flash_block_t * const block, const unsigned blockno)
+{
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
+ if (&db.cache[i].block == block) {
+ db.cache[i].blockno = blockno;
+ db.cache[i].lru = ++db.cache_lru;
+ return;
}
+ }
+}
- return db;
+/*
+ * Release a block from the in-memory cache.
+ */
+
+static inline void cache_release(const flash_block_t * const block)
+{
+ if (block != NULL)
+ cache_mark_used(block, ~0);
}
-hal_error_t _write_data_to_flash(const uint32_t offset, const uint8_t *data, const size_t len)
+/*
+ * Generate CRC-32 for a block.
+ *
+ * This function needs to understand the structure of
+ * flash_block_header_t, so that it can skip over fields that
+ * shouldn't be included in the CRC.
+ */
+
+static hal_crc32_t calculate_block_crc(const flash_block_t * const block)
{
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t to_write = len;
+ assert(block != NULL);
- if (keystore_write_data(offset, data, to_write & ~PAGE_SIZE_MASK) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- to_write &= PAGE_SIZE_MASK;
- if (to_write) {
- /* Use page_buf to write the remaining bytes, since we must write a full page each time. */
- memset(page_buf, 0xff, sizeof(page_buf));
- memcpy(page_buf, data + len - to_write, to_write);
- if (keystore_write_data((offset + len) & ~PAGE_SIZE_MASK, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- }
+ hal_crc32_t crc = hal_crc32_init();
+
+ crc = hal_crc32_update(crc, &block->header.block_type,
+ sizeof(block->header.block_type));
+
+ crc = hal_crc32_update(crc, &block->header.total_chunks,
+ sizeof(block->header.total_chunks));
+
+ crc = hal_crc32_update(crc, &block->header.this_chunk,
+ sizeof(block->header.this_chunk));
+
+ crc = hal_crc32_update(crc, block->bytes + sizeof(flash_block_header_t),
+ sizeof(*block) - sizeof(flash_block_header_t));
+
+ return hal_crc32_finalize(crc);
+}
+
+/*
+ * Calculate block offset.
+ */
+
+static inline uint32_t block_offset(const unsigned blockno)
+{
+ return blockno * KEYSTORE_SUBSECTOR_SIZE;
+}
+
+/*
+ * Read a flash block.
+ *
+ * Flash read on the Alpha is slow enough that it pays to check the
+ * first page before reading the rest of the block.
+ */
+
+static hal_error_t block_read(const unsigned blockno, flash_block_t *block)
+{
+ if (block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_read_data(block_offset(blockno),
+ block->bytes,
+ KEYSTORE_PAGE_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ switch (block_get_type(block)) {
+ case BLOCK_TYPE_ERASED:
+ case BLOCK_TYPE_ZEROED:
+ return HAL_OK;
+ case BLOCK_TYPE_KEY:
+ case BLOCK_TYPE_PIN:
+ case BLOCK_TYPE_ATTR:
+ break;
+ default:
+ return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
+ }
+
+ switch (block_get_status(block)) {
+ case BLOCK_STATUS_LIVE:
+ case BLOCK_STATUS_TOMBSTONE:
+ break;
+ default:
+ return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
+ }
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_read_data(block_offset(blockno) + KEYSTORE_PAGE_SIZE,
+ block->bytes + KEYSTORE_PAGE_SIZE,
+ sizeof(*block) - KEYSTORE_PAGE_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if (calculate_block_crc(block) != block->header.crc)
+ return HAL_ERROR_KEYSTORE_BAD_CRC;
+
+ return HAL_OK;
+}
+
+/*
+ * Read a block using the cache. Marking the block as used is left
+ * for the caller, so we can avoid blowing out the cache when we
+ * perform a ks_match() operation.
+ */
+
+static hal_error_t block_read_cached(const unsigned blockno, flash_block_t **block)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((*block = cache_find_block(blockno)) != NULL)
+ return HAL_OK;
+
+ if ((*block = cache_pick_lru()) == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ return block_read(blockno, *block);
+}
+
+/*
+ * Convert a live block into a tombstone. Caller is responsible for
+ * making sure that the block being converted is valid; since we don't
+ * need to update the CRC for this, we just modify the first page.
+ */
+
+static hal_error_t block_deprecate(const unsigned blockno)
+{
+ if (blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page[KEYSTORE_PAGE_SIZE];
+ flash_block_header_t *header = (void *) page;
+ uint32_t offset = block_offset(blockno);
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_read_data(offset, page, sizeof(page)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ header->block_status = BLOCK_STATUS_TOMBSTONE;
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_write_data(offset, page, sizeof(page)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * Zero (not erase) a flash block. Just need to zero the first page.
+ */
+
+static hal_error_t block_zero(const unsigned blockno)
+{
+ if (blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page[KEYSTORE_PAGE_SIZE] = {0};
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_write_data(block_offset(blockno), page, sizeof(page)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * Erase a flash block. Also see block_erase_maybe(), below.
+ */
+
+static hal_error_t block_erase(const unsigned blockno)
+{
+ if (blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_erase_subsectors(blockno, blockno) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * Erase a flash block if it hasn't already been erased.
+ * May not be necessary, trying to avoid unnecessary wear.
+ *
+ * Unclear whether there's any sane reason why this needs to be
+ * constant time, given how slow erasure is. But side channel attacks
+ * can be tricky things, and it's theoretically possible that we could
+ * leak information about, eg, key length, so we do constant time.
+ */
+
+static hal_error_t block_erase_maybe(const unsigned blockno)
+{
+ if (blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t mask = 0xFF;
+
+ for (uint32_t a = block_offset(blockno); a < block_offset(blockno + 1); a += KEYSTORE_PAGE_SIZE) {
+ uint8_t page[KEYSTORE_PAGE_SIZE];
+ if (keystore_read_data(a, page, sizeof(page)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ for (int i = 0; i < KEYSTORE_PAGE_SIZE; i++)
+ mask &= page[i];
+ }
+
+ return mask == 0xFF ? HAL_OK : block_erase(blockno);
+}
+
+/*
+ * Write a flash block, calculating CRC when appropriate.
+ */
+
+static hal_error_t block_write(const unsigned blockno, flash_block_t *block)
+{
+ if (block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_error_t err = block_erase_maybe(blockno);
+
+ if (err != HAL_OK)
+ return err;
+
+ switch (block_get_type(block)) {
+ case BLOCK_TYPE_KEY:
+ case BLOCK_TYPE_PIN:
+ case BLOCK_TYPE_ATTR:
+ block->header.crc = calculate_block_crc(block);
+ break;
+ default:
+ break;
+ }
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_write_data(block_offset(blockno), block->bytes, sizeof(*block)) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * Update one flash block, including zombie jamboree.
+ */
+
+static hal_error_t block_update(const unsigned b1, flash_block_t *block,
+ const hal_uuid_t * const uuid, const unsigned chunk, int *hint)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (db.ksi.used == db.ksi.size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ cache_release(block);
- return LIBHAL_OK;
+ hal_error_t err;
+ unsigned b2;
+
+ if ((err = block_deprecate(b1)) != HAL_OK ||
+ (err = hal_ks_index_replace(&db.ksi, uuid, chunk, &b2, hint)) != HAL_OK ||
+ (err = block_write(b2, block)) != HAL_OK ||
+ (err = block_zero(b1)) != HAL_OK)
+ return err;
+
+ cache_mark_used(block, b2);
+
+ return block_erase_maybe(db.ksi.index[db.ksi.used]);
}
/*
- * Write the full DB to flash, PINs and all.
+ * Forward reference.
*/
-hal_error_t _write_db_to_flash(const uint32_t sector_offset)
+
+static hal_error_t fetch_pin_block(unsigned *b, flash_block_t **block);
+
+/*
+ * Initialize keystore. This includes various tricky bits, some of
+ * which attempt to preserve the free list ordering across reboots, to
+ * improve our simplistic attempt at wear leveling, others attempt to
+ * recover from unclean shutdown.
+ */
+
+static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
+{
+ if (mem == NULL || *mem == NULL || len == NULL || size > *len)
+ return NULL;
+ void *ret = *mem;
+ *mem += size;
+ *len -= size;
+ return ret;
+}
+
+static hal_error_t ks_init(const hal_ks_driver_t * const driver, const int alloc)
{
- hal_error_t status;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
- uint32_t i, offset;
+ /*
+ * Initialize the in-memory database.
+ */
+
+ if (alloc) {
+
+ size_t len = (sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS +
+ sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS +
+ sizeof(*db.cache) * KS_FLASH_CACHE_SIZE);
+
+ uint8_t *mem = hal_allocate_static_memory(len);
+
+ if (mem == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+
+ memset(&db, 0, sizeof(db));
+ memset(mem, 0, len);
+
+ db.ksi.index = gnaw(&mem, &len, sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS);
+ db.ksi.names = gnaw(&mem, &len, sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS);
+ db.cache = gnaw(&mem, &len, sizeof(*db.cache) * KS_FLASH_CACHE_SIZE);
+ db.ksi.size = NUM_FLASH_BLOCKS;
+ }
+
+ else {
+ memset(&db.wheel_pin, 0, sizeof(db.wheel_pin));
+ memset(&db.so_pin, 0, sizeof(db.so_pin));
+ memset(&db.user_pin, 0, sizeof(db.user_pin));
+ }
+
+ db.ksi.used = 0;
+
+ if (db.ksi.index == NULL || db.ksi.names == NULL || db.cache == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
+ db.cache[i].blockno = ~0;
+
+ /*
+ * Scan existing content of flash to figure out what we've got.
+ * This gets a bit involved due to the need to recover from things
+ * like power failures at inconvenient times.
+ */
+
+ flash_block_type_t block_types[NUM_FLASH_BLOCKS];
+ flash_block_status_t block_status[NUM_FLASH_BLOCKS];
+ flash_block_t *block = cache_pick_lru();
+ int first_erased = -1;
+ hal_error_t err;
+ uint16_t n = 0;
+
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ for (int i = 0; i < NUM_FLASH_BLOCKS; i++) {
+
+ /*
+ * Read one block. If the CRC is bad or the block type is
+ * unknown, it's old data we don't understand, something we were
+ * writing when we crashed, or bad flash; in any of these cases,
+ * we want the block to ends up near the end of the free list.
+ */
+
+ err = block_read(i, block);
+
+ if (err == HAL_ERROR_KEYSTORE_BAD_CRC || err == HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE)
+ block_types[i] = BLOCK_TYPE_UNKNOWN;
+
+ else if (err == HAL_OK)
+ block_types[i] = block_get_type(block);
+
+ else
+ return err;
- if (sizeof(db->wheel_pin) + sizeof(db->so_pin) + sizeof(db->user_pin) > sizeof(page_buf)) {
- return HAL_ERROR_BAD_ARGUMENTS;
+ switch (block_types[i]) {
+ case BLOCK_TYPE_KEY:
+ case BLOCK_TYPE_PIN:
+ case BLOCK_TYPE_ATTR:
+ block_status[i] = block_get_status(block);
+ break;
+ default:
+ block_status[i] = BLOCK_STATUS_UNKNOWN;
}
- /* Put the three PINs into page_buf */
- offset = 0;
- memcpy(page_buf + offset, &db->wheel_pin, sizeof(db->wheel_pin));
- offset += sizeof(db->wheel_pin);
- memcpy(page_buf + offset, &db->so_pin, sizeof(db->so_pin));
- offset += sizeof(db->so_pin);
- memcpy(page_buf + offset, &db->user_pin, sizeof(db->user_pin));
-
- /* Write PINs into the second of the two reserved pages at the start of the sector. */
- offset = sector_offset + KEYSTORE_PAGE_SIZE;
- if ((status = _write_data_to_flash(offset, page_buf, sizeof(page_buf))) != LIBHAL_OK) {
- return status;
+ /*
+ * First erased block we see is head of the free list.
+ */
+
+ if (block_types[i] == BLOCK_TYPE_ERASED && first_erased < 0)
+ first_erased = i;
+
+ /*
+ * If it's a valid data block, include it in the index. We remove
+ * tombstones (if any) below, for now it's easiest to include them
+ * in the index, so we can look them up by name if we must.
+ */
+
+ const hal_uuid_t *uuid = NULL;
+
+ switch (block_types[i]) {
+ case BLOCK_TYPE_KEY: uuid = &block->key.name; break;
+ case BLOCK_TYPE_ATTR: uuid = &block->attr.name; break;
+ case BLOCK_TYPE_PIN: uuid = &pin_uuid; break;
+ default: /* Keep GCC happy */ break;
}
- for (i = 0; i < sizeof(db->keys) / sizeof(*db->keys); i++) {
- offset = _get_key_offset(i);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
- }
+ if (uuid != NULL) {
+ db.ksi.names[i].name = *uuid;
+ db.ksi.names[i].chunk = block->header.this_chunk;
+ db.ksi.index[n++] = i;
+ }
+ }
+
+ db.ksi.used = n;
+
+ assert(db.ksi.used <= db.ksi.size);
+
+ /*
+ * At this point we've built the (unsorted) index from all the valid
+ * blocks. Now we need to insert free and unrecognized blocks into
+ * the free list in our preferred order. It's possible that there's
+ * a better way to do this than linear scan, but this is just
+ * integer comparisons in a fairly small data set, so it's probably
+ * not worth trying to optimize.
+ */
+
+ if (n < db.ksi.size)
+ for (int i = 0; i < NUM_FLASH_BLOCKS; i++)
+ if (block_types[i] == BLOCK_TYPE_ERASED)
+ db.ksi.index[n++] = i;
+
+ if (n < db.ksi.size)
+ for (int i = first_erased; i < NUM_FLASH_BLOCKS; i++)
+ if (block_types[i] == BLOCK_TYPE_ZEROED)
+ db.ksi.index[n++] = i;
+
+ if (n < db.ksi.size)
+ for (int i = 0; i < first_erased; i++)
+ if (block_types[i] == BLOCK_TYPE_ZEROED)
+ db.ksi.index[n++] = i;
+
+ if (n < db.ksi.size)
+ for (int i = 0; i < NUM_FLASH_BLOCKS; i++)
+ if (block_types[i] == BLOCK_TYPE_UNKNOWN)
+ db.ksi.index[n++] = i;
+
+ assert(n == db.ksi.size);
+
+ /*
+ * Initialize the index.
+ */
+
+ if ((err = hal_ks_index_setup(&db.ksi)) != HAL_OK)
+ return err;
+
+ /*
+ * We might want to call hal_ks_index_fsck() here, if we can figure
+ * out some safe set of recovery actions we can take.
+ */
+
+ /*
+ * Deal with tombstones. These are blocks left behind when
+ * something bad (like a power failure) happened while we updating.
+ * The sequence of operations while updating is designed so that,
+ * barring a bug or a hardware failure, we should never lose data.
+ *
+ * For any tombstone we find, we start by looking for all the blocks
+ * with a matching UUID, then see what valid sequences we can
+ * construct from what we found.
+ *
+ * If we can construct a valid sequence of live blocks, the complete
+ * update was written out, and we just need to zero the tombstones.
+ *
+ * Otherwise, if we can construct a complete sequence of tombstone
+ * blocks, the update failed before it was completely written, so we
+ * have to zero the incomplete sequence of live blocks then restore
+ * from the tombstones.
+ *
+ * Otherwise, if the live and tombstone blocks taken together form a
+ * valid sequence, the update failed while deprecating the old live
+ * blocks, and the update itself was not written, so we need to
+ * restore the tombstones and leave the live blocks alone.
+ *
+ * If none of the above applies, we don't understand what happened,
+ * which is a symptom of either a bug or a hardware failure more
+ * serious than simple loss of power or reboot at an inconvenient
+ * time, so we error out to avoid accidental loss of data.
+ */
+
+ for (int i = 0; i < NUM_FLASH_BLOCKS; i++) {
+
+ if (block_status[i] != BLOCK_STATUS_TOMBSTONE)
+ continue;
+
+ hal_uuid_t name = db.ksi.names[i].name;
+ unsigned n_blocks;
+ int where = -1;
+
+ if ((err = hal_ks_index_find_range(&db.ksi, &name, 0, &n_blocks, NULL, &where, 0)) != HAL_OK)
+ return err;
+
+ while (where > 0 && !hal_uuid_cmp(&name, &db.ksi.names[db.ksi.index[where - 1]].name)) {
+ where--;
+ n_blocks++;
+ }
+
+ int live_ok = 1, tomb_ok = 1, join_ok = 1;
+ unsigned n_live = 0, n_tomb = 0;
+ unsigned i_live = 0, i_tomb = 0;
+
+ for (int j = 0; j < n_blocks; j++) {
+ unsigned b = db.ksi.index[where + j];
+ switch (block_status[b]) {
+ case BLOCK_STATUS_LIVE: n_live++; break;
+ case BLOCK_STATUS_TOMBSTONE: n_tomb++; break;
+ default: return HAL_ERROR_IMPOSSIBLE;
+ }
+ }
+
+ uint16_t live_blocks[n_live], tomb_blocks[n_tomb];
+
+ for (int j = 0; j < n_blocks; j++) {
+ unsigned b = db.ksi.index[where + j];
- offset += sector_offset;
+ if ((err = block_read(b, block)) != HAL_OK)
+ return err;
- if ((status =_write_data_to_flash(offset, (uint8_t *) &db->keys[i], sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
+ join_ok &= block->header.this_chunk == j && block->header.total_chunks == n_blocks;
+
+ switch (block_status[b]) {
+ case BLOCK_STATUS_LIVE:
+ live_blocks[i_live] = b;
+ live_ok &= block->header.this_chunk == i_live++ && block->header.total_chunks == n_live;
+ break;
+ case BLOCK_STATUS_TOMBSTONE:
+ tomb_blocks[i_tomb] = b;
+ tomb_ok &= block->header.this_chunk == i_tomb++ && block->header.total_chunks == n_tomb;
+ break;
+ default:
+ return HAL_ERROR_IMPOSSIBLE;
+ }
+ }
+
+ if (!live_ok && !tomb_ok && !join_ok)
+ return HAL_ERROR_KEYSTORE_LOST_DATA;
+
+ if (live_ok) {
+ for (int j = 0; j < n_tomb; j++) {
+ const unsigned b = tomb_blocks[j];
+ if ((err = block_zero(b)) != HAL_OK)
+ return err;
+ block_types[b] = BLOCK_TYPE_ZEROED;
+ block_status[b] = BLOCK_STATUS_UNKNOWN;
+ }
+ }
+
+ else if (tomb_ok) {
+ for (int j = 0; j < n_live; j++) {
+ const unsigned b = live_blocks[j];
+ if ((err = block_zero(b)) != HAL_OK)
+ return err;
+ block_types[b] = BLOCK_TYPE_ZEROED;
+ block_status[b] = BLOCK_STATUS_UNKNOWN;
+ }
+ }
+
+ if (live_ok) {
+ memcpy(&db.ksi.index[where], live_blocks, n_live * sizeof(*db.ksi.index));
+ memmove(&db.ksi.index[where + n_live], &db.ksi.index[where + n_blocks],
+ (db.ksi.size - where - n_blocks) * sizeof(*db.ksi.index));
+ memcpy(&db.ksi.index[db.ksi.size - n_tomb], tomb_blocks, n_tomb * sizeof(*db.ksi.index));
+ db.ksi.used -= n_tomb;
+ n_blocks = n_live;
+ }
+
+ else if (tomb_ok) {
+ memcpy(&db.ksi.index[where], tomb_blocks, n_tomb * sizeof(*db.ksi.index));
+ memmove(&db.ksi.index[where + n_tomb], &db.ksi.index[where + n_blocks],
+ (db.ksi.size - where - n_blocks) * sizeof(*db.ksi.index));
+ memcpy(&db.ksi.index[db.ksi.size - n_live], live_blocks, n_live * sizeof(*db.ksi.index));
+ db.ksi.used -= n_live;
+ n_blocks = n_tomb;
+ }
+
+ for (int j = 0; j < n_blocks; j++) {
+ int hint = where + j;
+ unsigned b1 = db.ksi.index[hint], b2;
+ if (block_status[b1] != BLOCK_STATUS_TOMBSTONE)
+ continue;
+ if ((err = block_read(b1, block)) != HAL_OK)
+ return err;
+ block->header.block_status = BLOCK_STATUS_LIVE;
+ if ((err = hal_ks_index_replace(&db.ksi, &name, j, &b2, &hint)) != HAL_OK ||
+ (err = block_write(b2, block)) != HAL_OK)
+ return err;
+ block_types[b1] = BLOCK_TYPE_ZEROED;
+ block_status[b1] = BLOCK_STATUS_UNKNOWN;
+ block_status[b2] = BLOCK_STATUS_LIVE;
+ }
+ }
+
+ err = fetch_pin_block(NULL, &block);
+
+ if (err == HAL_OK) {
+ db.wheel_pin = block->pin.wheel_pin;
+ db.so_pin = block->pin.so_pin;
+ db.user_pin = block->pin.user_pin;
+ }
+
+ else if (err != HAL_ERROR_KEY_NOT_FOUND)
+ return err;
+
+ else {
+ /*
+ * We found no PIN block, so create one, with the user and so PINs
+ * cleared and the wheel PIN set to the last-gasp value. The
+ * last-gasp WHEEL PIN is a terrible answer, but we need some kind
+ * of bootstrapping mechanism when all else fails. If you have a
+ * better suggestion, we'd love to hear it.
+ */
+
+ unsigned b;
+
+ memset(block, 0xFF, sizeof(*block));
+
+ block->header.block_type = BLOCK_TYPE_PIN;
+ block->header.block_status = BLOCK_STATUS_LIVE;
+ block->header.total_chunks = 1;
+ block->header.this_chunk = 0;
+
+ block->pin.wheel_pin = db.wheel_pin = hal_last_gasp_pin;
+ block->pin.so_pin = db.so_pin;
+ block->pin.user_pin = db.user_pin;
+
+ if ((err = hal_ks_index_add(&db.ksi, &pin_uuid, 0, &b, NULL)) != HAL_OK)
+ return err;
+
+ cache_mark_used(block, b);
+
+ err = block_write(b, block);
+
+ cache_release(block);
+
+ if (err != HAL_OK)
+ return err;
+ }
+
+ /*
+ * Erase first block on free list if it's not already erased.
+ */
+
+ if (db.ksi.used < db.ksi.size &&
+ (err = block_erase_maybe(db.ksi.index[db.ksi.used])) != HAL_OK)
+ return err;
+
+ /*
+ * And we're finally done.
+ */
+
+ db.ks.driver = driver;
+
+ return HAL_OK;
+}
+
+static hal_error_t ks_shutdown(const hal_ks_driver_t * const driver)
+{
+ if (db.ks.driver != driver)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ return HAL_OK;
+}
+
+static hal_error_t ks_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ if (driver != hal_ks_token_driver || ks == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ *ks = &db.ks;
+ return HAL_OK;
+}
+
+static hal_error_t ks_close(hal_ks_t *ks)
+{
+ if (ks != NULL && ks != &db.ks)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return HAL_OK;
+}
+
+static inline int acceptable_key_type(const hal_key_type_t type)
+{
+ switch (type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ case HAL_KEY_TYPE_EC_PRIVATE:
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ case HAL_KEY_TYPE_EC_PUBLIC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static hal_error_t ks_store(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (ks != &db.ks || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ flash_block_t *block = cache_pick_lru();
+ flash_key_block_t *k = &block->key;
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+ hal_error_t err;
+ unsigned b;
+
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((err = hal_ks_index_add(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ cache_mark_used(block, b);
+
+ memset(block, 0xFF, sizeof(*block));
+
+ block->header.block_type = BLOCK_TYPE_KEY;
+ block->header.block_status = BLOCK_STATUS_LIVE;
+ block->header.total_chunks = 1;
+ block->header.this_chunk = 0;
+
+ k->name = slot->name;
+ k->type = slot->type;
+ k->curve = slot->curve;
+ k->flags = slot->flags;
+ k->der_len = SIZEOF_FLASH_KEY_BLOCK_DER;
+ k->attributes_len = 0;
+
+ if ((err = hal_mkm_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 &&
+ (err = block_write(b, block)) == HAL_OK)
+ return HAL_OK;
+
+ memset(block, 0, sizeof(*block));
+ cache_release(block);
+ (void) hal_ks_index_delete(&db.ksi, &slot->name, 0, NULL, &slot->hint);
+ return err;
+}
+
+static hal_error_t ks_fetch(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (ks != &db.ks || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ flash_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block_get_type(block) != BLOCK_TYPE_KEY)
+ return HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE; /* HAL_ERROR_KEY_NOT_FOUND */
+
+ cache_mark_used(block, b);
+
+ flash_key_block_t *k = &block->key;
+
+ slot->type = k->type;
+ slot->curve = k->curve;
+ slot->flags = k->flags;
+
+ if (der == NULL && der_len != NULL)
+ *der_len = k->der_len;
+
+ if (der != NULL) {
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len, der_len_;
+ hal_error_t err;
+
+ if (der_len == NULL)
+ der_len = &der_len_;
+
+ *der_len = der_max;
+
+ if ((err = hal_mkm_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;
+}
+
+static hal_error_t ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot)
+{
+ if (ks != &db.ks || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+ unsigned n;
+
+ if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, 0, &n, NULL, &slot->hint)) != HAL_OK)
+ return err;
+
+ unsigned b[n];
+
+ if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, n, NULL, b, &slot->hint)) != HAL_OK)
+ return err;
+
+ for (int i = 0; i < n; i++)
+ cache_release(cache_find_block(b[i]));
+
+ for (int i = 0; i < n; i++)
+ if ((err = block_zero(b[i])) != HAL_OK)
+ return err;
+
+ return block_erase_maybe(db.ksi.index[db.ksi.used]);
+}
+
+static inline hal_error_t locate_attributes(flash_block_t *block, const unsigned chunk,
+ uint8_t **bytes, size_t *bytes_len,
+ unsigned **attrs_len)
+{
+ if (block == NULL || bytes == NULL || bytes_len == NULL || attrs_len == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (chunk == 0) {
+ if (block_get_type(block) != BLOCK_TYPE_KEY)
+ return HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE; /* HAL_ERROR_KEY_NOT_FOUND */
+ *attrs_len = &block->key.attributes_len;
+ *bytes = block->key.der + block->key.der_len;
+ *bytes_len = SIZEOF_FLASH_KEY_BLOCK_DER - block->key.der_len;
+ }
+
+ else {
+ if (block_get_type(block) != BLOCK_TYPE_ATTR)
+ return HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE; /* HAL_ERROR_KEY_NOT_FOUND */
+ *attrs_len = &block->attr.attributes_len;
+ *bytes = block->attr.attributes;
+ *bytes_len = SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES;
+ }
+
+ return HAL_OK;
+}
+
+static hal_error_t ks_match(hal_ks_t *ks,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
+{
+ if (ks == NULL || (attributes == NULL && attributes_len > 0) ||
+ result == NULL || result_len == NULL || previous_uuid == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ uint8_t need_attr[attributes_len > 0 ? attributes_len : 1];
+ flash_block_t *block;
+ int possible = 0;
+ hal_error_t err;
+ int i = -1;
+
+ *result_len = 0;
+
+ err = hal_ks_index_find(&db.ksi, previous_uuid, 0, NULL, &i);
+
+ if (err == HAL_ERROR_KEY_NOT_FOUND)
+ i--;
+ else if (err != HAL_OK)
+ return err;
+
+ while (*result_len < result_max && ++i < db.ksi.used) {
+
+ unsigned b = db.ksi.index[i];
+
+ if (db.ksi.names[b].chunk == 0)
+ possible = 1;
+
+ if (!possible)
+ continue;
+
+ if ((err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (db.ksi.names[b].chunk == 0) {
+ memset(need_attr, 1, sizeof(need_attr));
+ possible = ((type == HAL_KEY_TYPE_NONE || type == block->key.type) &&
+ (curve == HAL_CURVE_NONE || curve == block->key.curve));
+ }
+
+ if (!possible)
+ continue;
+
+ if (attributes_len > 0) {
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, db.ksi.names[b].chunk,
+ &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ if (*attrs_len > 0) {
+ hal_pkey_attribute_t attrs[*attrs_len];
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
+ return err;
+
+ for (int j = 0; possible && j < attributes_len; j++) {
+
+ if (!need_attr[j])
+ continue;
+
+ for (hal_pkey_attribute_t *a = attrs; a < attrs + *attrs_len; a++) {
+ if (a->type != attributes[j].type)
+ continue;
+ need_attr[j] = 0;
+ possible = (a->length == attributes[j].length &&
+ !memcmp(a->value, attributes[j].value, a->length));
+ break;
+ }
}
+ }
}
- return LIBHAL_OK;
+ if (!possible)
+ continue;
+
+ if (attributes_len > 0 && memchr(need_attr, 1, sizeof(need_attr)) != NULL)
+ continue;
+
+ result[*result_len] = db.ksi.names[b].name;
+ ++*result_len;
+ possible = 0;
+ }
+
+ return HAL_OK;
}
-hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating)
+/*
+ * This controls whether we include a separate code path for the
+ * common case where we can handle attribute setting via a single
+ * block update. It's a lot simpler when it works, but it's yet
+ * another code path, and enabling it leaves the slower full-blown
+ * algorithm less tested.
+ */
+
+#ifndef KS_SET_ATTRIBUTES_SINGLE_BLOCK_UPDATE_FAST_PATH
+#define KS_SET_ATTRIBUTES_SINGLE_BLOCK_UPDATE_FAST_PATH 0
+#endif
+
+/*
+ * ks_set_attributes() is much too long. Probably needs to be broken
+ * up into a collection of inline functions, even if most of them end
+ * up being called exactly once.
+ */
+
+static hal_error_t ks_set_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
{
- hal_error_t status;
- uint32_t offset, active_sector_offset;
- hal_ks_key_t *tmp_key;
- uint8_t page_buf[KEYSTORE_PAGE_SIZE];
+ if (ks != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
- return HAL_ERROR_BAD_ARGUMENTS;
+ /*
+ * Perform initial scan of the object to figure out the total
+ * attribute count and a few other parameters.
+ *
+ * If enabled, try to do everything as as a single-block update. If
+ * single block update fails, we MUST clear the modified block from
+ * the cache before doing anything else.
+ */
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) return HAL_ERROR_BAD_ARGUMENTS;
+ unsigned updated_attributes_len = attributes_len;
+ flash_block_t *block;
+ unsigned chunk = 0;
+ hal_error_t err;
+ unsigned b;
+
+ do {
+ int hint = slot->hint + chunk;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ cache_mark_used(block, b);
+
+ if (chunk == 0)
+ slot->hint = hint;
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ updated_attributes_len += *attrs_len;
+
+#if KS_SET_ATTRIBUTES_SINGLE_BLOCK_UPDATE_FAST_PATH
+
+ hal_pkey_attribute_t attrs[*attrs_len + attributes_len];
+ size_t total;
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK)
+ return err;
+
+ for (int i = 0; err == HAL_OK && i < attributes_len; i++)
+ if (attributes[i].length == HAL_PKEY_ATTRIBUTE_NIL)
+ err = hal_ks_attribute_delete(bytes, bytes_len, attrs, attrs_len, &total,
+ attributes[i].type);
+ else
+ err = hal_ks_attribute_insert(bytes, bytes_len, attrs, attrs_len, &total,
+ attributes[i].type,
+ attributes[i].value,
+ attributes[i].length);
+
+ if (err != HAL_OK)
+ cache_release(block);
+
+ if (err == HAL_ERROR_RESULT_TOO_LONG)
+ continue;
+
+ if (err != HAL_OK)
+ return err;
+
+ return block_update(b, block, &slot->name, chunk, &hint);
+
+#endif /* KS_SET_ATTRIBUTES_SINGLE_BLOCK_UPDATE_FAST_PATH */
+
+ } while (++chunk < block->header.total_chunks);
+
+ /*
+ * If we get here, we're on the slow path, which requires rewriting
+ * all the chunks in this object but which can also add or remove
+ * chunks from this object. We need to keep track of all the old
+ * chunks so we can zero them at the end, and because we can't zero
+ * them until we've written out the new chunks, we need enough free
+ * blocks to hold all the new chunks.
+ *
+ * Calculating all of this is extremely tedious, but flash writes
+ * are so much more expensive than anything else we do here that
+ * it's almost certainly worth it.
+ *
+ * We don't need the attribute values to compute the sizes, just the
+ * attribute sizes, so we scan all the existing blocks, build up a
+ * structure with the current attribute types and sizes, modify that
+ * according to our arguments, and compute the needed size. Once we
+ * have that, we can start rewriting existing blocks. We put all
+ * the new stuff at the end, which simplifies this slightly.
+ *
+ * In theory, this process never requires us to have more than two
+ * blocks in memory at the same time (source and destination when
+ * copying across chunk boundaries), but having enough cache buffers
+ * to keep the whole set in memory will almost certainly make this
+ * run faster.
+ */
+
+ hal_pkey_attribute_t updated_attributes[updated_attributes_len];
+ const unsigned total_chunks_old = block->header.total_chunks;
+ size_t bytes_available = 0;
- active_sector_offset = _active_sector_offset();
+ updated_attributes_len = 0;
- offset += active_sector_offset;
+ /*
+ * Phase 0.1: Walk the old chunks to populate updated_attributes[].
+ * This also initializes bytes_available, since we can only get that
+ * by reading old chunk zero.
+ */
- if (keystore_check_id() != 1) return HAL_ERROR_KEYSTORE_ACCESS;
+ for (chunk = 0; chunk < total_chunks_old; chunk++) {
+ int hint = slot->hint + chunk;
- /* Check if there is a key occupying this slot in the flash already.
- * Don't trust the in-memory representation since it would mean data
- * corruption in flash if it had been altered.
- */
- if (keystore_read_data(offset, page_buf, sizeof(page_buf)) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ cache_mark_used(block, b);
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ hal_pkey_attribute_t attrs[*attrs_len];
+ size_t total;
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK)
+ return err;
+
+ if (chunk == 0)
+ bytes_available = bytes_len;
+
+ for (int i = 0; i < *attrs_len; i++) {
+
+ if (updated_attributes_len >= sizeof(updated_attributes)/sizeof(*updated_attributes))
+ return HAL_ERROR_IMPOSSIBLE;
+
+ updated_attributes[updated_attributes_len].type = attrs[i].type;
+ updated_attributes[updated_attributes_len].length = attrs[i].length;
+ updated_attributes[updated_attributes_len].value = NULL;
+ updated_attributes_len++;
}
- tmp_key = (hal_ks_key_t *) page_buf;
+ }
+
+ /*
+ * Phase 0.2: Merge new attributes into updated_attributes[].
+ */
+
+ for (int i = 0; i < attributes_len; i++) {
+
+ for (int j = 0; j < updated_attributes_len; j++)
+ if (updated_attributes[j].type == attributes[i].type)
+ updated_attributes[j].length = HAL_PKEY_ATTRIBUTE_NIL;
+
+ if (updated_attributes_len >= sizeof(updated_attributes)/sizeof(*updated_attributes))
+ return HAL_ERROR_IMPOSSIBLE;
+
+ updated_attributes[updated_attributes_len].type = attributes[i].type;
+ updated_attributes[updated_attributes_len].length = attributes[i].length;
+ updated_attributes[updated_attributes_len].value = attributes[i].value;
+ updated_attributes_len++;
+ }
+
+ /*
+ * Phase 0.3: Prune trailing deletion actions: we don't need them to
+ * maintain synchronization with existing attributes, and doing so
+ * simplifies logic for updating the final new chunk.
+ */
+
+ while (updated_attributes_len > 0 &&
+ updated_attributes[updated_attributes_len - 1].length == HAL_PKEY_ATTRIBUTE_NIL)
+ --updated_attributes_len;
+
+ /*
+ * Phase 0.4: Figure out how many chunks all this will occupy.
+ */
+
+ chunk = 0;
+
+ for (int i = 0; i < updated_attributes_len; i++) {
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
+ if (updated_attributes[i].length == HAL_PKEY_ATTRIBUTE_NIL)
+ continue;
- if (tmp_key->in_use == 0xff) {
- /* Key slot was unused in flash. Write the new key there. */
- if ((status = _write_data_to_flash(offset, (uint8_t *) key, sizeof(*db->keys))) != LIBHAL_OK) {
- return status;
+ const size_t needed = hal_ks_attribute_header_size + updated_attributes[i].length;
+
+ if (needed > bytes_available) {
+ bytes_available = SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES;
+ chunk++;
+ }
+
+ if (needed > bytes_available)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ bytes_available -= needed;
+ }
+
+ const unsigned total_chunks_new = chunk + 1;
+
+ /*
+ * If there aren't enough free blocks, give up now, before changing anything.
+ */
+
+ if (db.ksi.used + total_chunks_new > db.ksi.size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ /*
+ * Phase 1: Deprecate all the old chunks, remember where they were.
+ */
+
+ unsigned old_blocks[total_chunks_old];
+
+ for (chunk = 0; chunk < total_chunks_old; chunk++) {
+ int hint = slot->hint + chunk;
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_deprecate(b)) != HAL_OK)
+ return err;
+ old_blocks[chunk] = b;
+ }
+
+ /*
+ * Phase 2: Write new chunks, copying attributes from old chunks or
+ * from attributes[], as needed.
+ */
+
+ {
+ hal_pkey_attribute_t old_attrs[updated_attributes_len], new_attrs[updated_attributes_len];
+ unsigned *old_attrs_len = NULL, *new_attrs_len = NULL;
+ flash_block_t *old_block = NULL, *new_block = NULL;
+ uint8_t *old_bytes = NULL, *new_bytes = NULL;
+ size_t old_bytes_len = 0, new_bytes_len = 0;
+ unsigned old_chunk = 0, new_chunk = 0;
+ size_t old_total = 0, new_total = 0;
+
+ int updated_attributes_i = 0, old_attrs_i = 0;
+
+ uint32_t new_attr_type;
+ size_t new_attr_length;
+ const uint8_t *new_attr_value;
+
+ while (updated_attributes_i < updated_attributes_len) {
+
+ if (old_chunk >= total_chunks_old || new_chunk >= total_chunks_new)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /*
+ * If we've gotten as far as new data that comes from
+ * attributes[], we have it in hand and can just copy it.
+ */
+
+ if (updated_attributes_len - updated_attributes_i <= attributes_len) {
+ new_attr_type = updated_attributes[updated_attributes_i].type;
+ new_attr_length = updated_attributes[updated_attributes_i].length;
+ new_attr_value = updated_attributes[updated_attributes_i].value;
+ }
+
+ /*
+ * Otherwise, we have to read it from an old block, which may in
+ * turn require reading in the next old block.
+ */
+
+ else {
+
+ if (old_block == NULL) {
+
+ if ((err = block_read_cached(old_blocks[old_chunk], &old_block)) != HAL_OK)
+ return err;
+
+ if (old_block->header.this_chunk != old_chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((err = locate_attributes(old_block, old_chunk,
+ &old_bytes, &old_bytes_len, &old_attrs_len)) != HAL_OK ||
+ (err = hal_ks_attribute_scan(old_bytes, old_bytes_len,
+ old_attrs, *old_attrs_len, &old_total)) != HAL_OK)
+ return err;
+
+ old_attrs_i = 0;
+ }
+
+ if (old_attrs_i >= *old_attrs_len) {
+ old_chunk++;
+ old_block = NULL;
+ continue;
}
- } else {
- /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
- if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
+
+ new_attr_type = old_attrs[old_attrs_i].type;
+ new_attr_length = old_attrs[old_attrs_i].length;
+ new_attr_value = old_attrs[old_attrs_i].value;
+
+ if (new_attr_type != updated_attributes[updated_attributes_i].type)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ old_attrs_i++;
+ }
+
+ /*
+ * Unless this is a deletion, we should have something to write.
+ */
+
+ if (new_attr_length != HAL_PKEY_ATTRIBUTE_NIL && new_attr_value == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /*
+ * Initialize the new block if necessary. If it's the new chunk
+ * zero, we need to copy all the non-attribute data from the old
+ * chunk zero; otherwise, it's a new empty attribute block.
+ */
+
+ if (new_block == NULL) {
+
+ new_block = cache_pick_lru();
+ memset(new_block, 0xFF, sizeof(*new_block));
+
+ if (new_chunk == 0) {
+ flash_block_t *tmp_block;
+ if ((err = block_read_cached(old_blocks[0], &tmp_block)) != HAL_OK)
+ return err;
+ if (tmp_block->header.this_chunk != 0)
+ return HAL_ERROR_IMPOSSIBLE;
+ new_block->header.block_type = BLOCK_TYPE_KEY;
+ new_block->key.name = slot->name;
+ new_block->key.type = tmp_block->key.type;
+ new_block->key.curve = tmp_block->key.curve;
+ new_block->key.flags = tmp_block->key.flags;
+ new_block->key.der_len = tmp_block->key.der_len;
+ new_block->key.attributes_len = 0;
+ memcpy(new_block->key.der, tmp_block->key.der, tmp_block->key.der_len);
}
- if ((status =_write_db_to_flash(active_sector_offset)) != LIBHAL_OK) {
- return status;
+ else {
+ new_block->header.block_type = BLOCK_TYPE_ATTR;
+ new_block->attr.name = slot->name;
+ new_block->attr.attributes_len = 0;
}
+
+ new_block->header.block_status = BLOCK_STATUS_LIVE;
+ new_block->header.total_chunks = total_chunks_new;
+ new_block->header.this_chunk = new_chunk;
+
+ if ((err = locate_attributes(new_block, new_chunk,
+ &new_bytes, &new_bytes_len, &new_attrs_len)) != HAL_OK)
+ return err;
+
+ new_total = 0;
+ }
+
+ /*
+ * After all that setup, we finally get to write the frelling attribute.
+ */
+
+ if (new_attr_length != HAL_PKEY_ATTRIBUTE_NIL)
+ err = hal_ks_attribute_insert(new_bytes, new_bytes_len, new_attrs, new_attrs_len, &new_total,
+ new_attr_type, new_attr_value, new_attr_length);
+
+ /*
+ * Figure out what to do next: immediately loop for next
+ * attribute, write current block, or bail out.
+ */
+
+ switch (err) {
+ case HAL_OK:
+ if (++updated_attributes_i < updated_attributes_len)
+ continue;
+ break;
+ case HAL_ERROR_RESULT_TOO_LONG:
+ if (new_chunk > 0 && new_attrs_len == 0)
+ return err;
+ break;
+ default:
+ return err;
+ }
+
+ /*
+ * If we get here, either the current new block is full or we
+ * finished the last block, so we need to write it out.
+ */
+
+ int hint = slot->hint + new_chunk;
+
+ if (new_chunk < total_chunks_old)
+ err = hal_ks_index_replace(&db.ksi, &slot->name, new_chunk, &b, &hint);
+ else
+ err = hal_ks_index_add( &db.ksi, &slot->name, new_chunk, &b, &hint);
+
+ if (err != HAL_OK || (err = block_write(b, new_block)) != HAL_OK)
+ return err;
+
+ cache_mark_used(new_block, b);
+
+ new_block = NULL;
+ new_chunk++;
}
- return LIBHAL_OK;
+ /*
+ * If number of blocks shrank, we need to clear trailing entries from the index.
+ */
+
+ for (old_chunk = total_chunks_new; old_chunk < total_chunks_old; old_chunk++) {
+ int hint = slot->hint + old_chunk;
+
+ err = hal_ks_index_delete(&db.ksi, &slot->name, old_chunk, NULL, &hint);
+
+ if (err != HAL_OK)
+ return err;
+ }
+
+ }
+
+ /*
+ * Phase 3: Zero the old chunks we deprecated in phase 1.
+ */
+
+ for (chunk = 0; chunk < total_chunks_old; chunk++)
+ if ((err = block_zero(old_blocks[chunk])) != HAL_OK)
+ return err;
+
+ return HAL_OK;
+
+#warning What happens if something goes wrong partway through this awful mess?
+ // We're left in a state with all the old blocks deprecated and
+ // (maybe) some of the new blocks current, need to clean that up.
+ // Would be nice if we could just reuse the keystore initialization
+ // code, but don't quite see how (yet?).
}
-hal_error_t hal_ks_del_keydb(const int loc)
+static hal_error_t ks_get_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
{
- uint32_t offset;
-
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+ if (ks != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0 ||
+ attributes_buffer == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- offset = _get_key_offset(loc);
- if (offset > KEYSTORE_SECTOR_SIZE) {
- return HAL_ERROR_BAD_ARGUMENTS;
+ for (int i = 0; i < attributes_len; i++) {
+ attributes[i].length = 0;
+ attributes[i].value = NULL;
}
- offset += _active_sector_offset();
+ uint8_t *abuf = attributes_buffer;
+ flash_block_t *block = NULL;
+ unsigned chunk = 0;
+ unsigned found = 0;
+ hal_error_t err;
+ unsigned b;
+
+ do {
+ int hint = slot->hint + chunk;
+
+ if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
+ (err = block_read_cached(b, &block)) != HAL_OK)
+ return err;
+
+ if (block->header.this_chunk != chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (chunk == 0)
+ slot->hint = hint;
+
+ cache_mark_used(block, b);
- memset(&db->keys[loc], 0, sizeof(*db->keys));
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
- /* Setting bits to 0 never requires erasing flash. Just write it. */
- return _write_data_to_flash(offset, (uint8_t *) &db->keys[loc], sizeof(*db->keys));
+ if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ return err;
+
+ if (*attrs_len == 0)
+ continue;
+
+ hal_pkey_attribute_t attrs[*attrs_len];
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
+ return err;
+
+ for (int i = 0; i < attributes_len; i++) {
+
+ if (attributes[i].length > 0)
+ continue;
+
+ int j = 0;
+ while (j < *attrs_len && attrs[j].type != attributes[i].type)
+ j++;
+ if (j >= *attrs_len)
+ continue;
+ found++;
+
+ attributes[i].length = attrs[j].length;
+
+ if (attributes_buffer_len == 0)
+ continue;
+
+ if (attrs[j].length > attributes_buffer + attributes_buffer_len - abuf)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ memcpy(abuf, attrs[j].value, attrs[j].length);
+ attributes[i].value = abuf;
+ abuf += attrs[j].length;
+ }
+
+ } while (found < attributes_len && ++chunk < block->header.total_chunks);
+
+ if (found < attributes_len && attributes_buffer_len > 0)
+ return HAL_ERROR_ATTRIBUTE_NOT_FOUND;
+
+ return HAL_OK;
}
-hal_error_t hal_ks_set_pin(const hal_user_t user,
- const hal_ks_pin_t * const pin)
-{
- uint32_t active_sector_offset;
+const hal_ks_driver_t hal_ks_token_driver[1] = {{
+ .init = ks_init,
+ .shutdown = ks_shutdown,
+ .open = ks_open,
+ .close = ks_close,
+ .store = ks_store,
+ .fetch = ks_fetch,
+ .delete = ks_delete,
+ .match = ks_match,
+ .set_attributes = ks_set_attributes,
+ .get_attributes = ks_get_attributes
+}};
+
+/*
+ * The remaining functions aren't really part of the keystore API per se,
+ * but they all involve non-key data which we keep in the keystore
+ * because it's the flash we've got.
+ */
+/*
+ * Fetch PIN. This is always cached, so just returned cached value.
+ */
+
+hal_error_t hal_get_pin(const hal_user_t user,
+ const hal_ks_pin_t **pin)
+{
if (pin == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- hal_ks_pin_t *p = NULL;
-
switch (user) {
- case HAL_USER_WHEEL: p = &db->wheel_pin; break;
- case HAL_USER_SO: p = &db->so_pin; break;
- case HAL_USER_NORMAL: p = &db->user_pin; break;
- default: return HAL_ERROR_BAD_ARGUMENTS;
+ case HAL_USER_WHEEL: *pin = &db.wheel_pin; break;
+ case HAL_USER_SO: *pin = &db.so_pin; break;
+ case HAL_USER_NORMAL: *pin = &db.user_pin; break;
+ default: return HAL_ERROR_BAD_ARGUMENTS;
}
- memcpy(p, pin, sizeof(*p));
+ return HAL_OK;
+}
+
+/*
+ * Fetch PIN block. hint = 0 because we know that the all-zeros UUID
+ * should always sort to first slot in the index.
+ */
+
+static hal_error_t fetch_pin_block(unsigned *b, flash_block_t **block)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
- active_sector_offset = _active_sector_offset();
+ hal_error_t err;
+ int hint = 0;
+ unsigned b_;
- /* TODO: Could check if the PIN is currently all 0xff, in which case we wouldn't have to
- * erase and re-write the whole DB.
- */
+ if (b == NULL)
+ b = &b_;
- /* TODO: Erase and write the database to the inactive sector, and then toggle active sector. */
- if (keystore_erase_sectors(active_sector_offset / KEYSTORE_SECTOR_SIZE,
- active_sector_offset / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_KEYSTORE_ACCESS;
- }
- return _write_db_to_flash(active_sector_offset);
+ if ((err = hal_ks_index_find(&db.ksi, &pin_uuid, 0, b, &hint)) != HAL_OK ||
+ (err = block_read_cached(*b, block)) != HAL_OK)
+ return err;
+
+ cache_mark_used(*block, *b);
+
+ if (block_get_type(*block) != BLOCK_TYPE_PIN)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ return HAL_OK;
}
+/*
+ * Update the PIN block. This block should always be present, but we
+ * have to do the zombie jamboree to make sure we write the new PIN
+ * block before destroying the old one. hint = 0 because we know that
+ * the all-zeros UUID should always sort to first slot in the index.
+ */
-hal_error_t hal_ks_get_kek(uint8_t *kek,
- size_t *kek_len,
- const size_t kek_max)
+static hal_error_t update_pin_block(const unsigned b,
+ flash_block_t *block,
+ const flash_pin_block_t * const new_data)
{
- if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128))
+ if (block == NULL || new_data == NULL || block_get_type(block) != BLOCK_TYPE_PIN)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ int hint = 0;
+
+ block->pin = *new_data;
+
+ return block_update(b, block, &pin_uuid, 0, &hint);
+}
+
+/*
+ * Change a PIN.
+ */
+
+hal_error_t hal_set_pin(const hal_user_t user,
+ const hal_ks_pin_t * const pin)
+{
+ if (pin == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) :
- (kek_max < bitsToBytes(256)) ? bitsToBytes(192) :
- bitsToBytes(256));
+ flash_block_t *block;
+ hal_error_t err;
+ unsigned b;
- hal_error_t err = masterkey_volatile_read(kek, len);
- if (err == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
- }
- if (masterkey_flash_read(kek, len) == LIBHAL_OK) {
- *kek_len = len;
- return LIBHAL_OK;
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ return err;
+
+ flash_pin_block_t new_data = block->pin;
+ hal_ks_pin_t *dp, *bp;
+
+ switch (user) {
+ case HAL_USER_WHEEL: bp = &new_data.wheel_pin; dp = &db.wheel_pin; break;
+ case HAL_USER_SO: bp = &new_data.so_pin; dp = &db.so_pin; break;
+ case HAL_USER_NORMAL: bp = &new_data.user_pin; dp = &db.user_pin; break;
+ default: return HAL_ERROR_BAD_ARGUMENTS;
}
- /* Both keystores returned an error, probably HAL_ERROR_MASTERKEY_NOT_SET.
- * I could try to be clever and compare the errors, but really the volatile
- * keystore is the important one (you shouldn't store the master key in
- * flash), so return that error.
- */
+ const hal_ks_pin_t old_pin = *dp;
+ *dp = *bp = *pin;
+
+ if ((err = update_pin_block(b, block, &new_data)) != HAL_OK)
+ *dp = old_pin;
+
return err;
}
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
+
+/*
+ * Horrible insecure kludge in lieu of a battery for the MKM.
+ *
+ * API here is a little strange: all calls pass a length parameter,
+ * but any length other than the compiled in constant just returns an
+ * immediate error, there's no notion of buffer max length vs buffer
+ * used length, querying for the size of buffer really needed, or
+ * anything like that.
+ *
+ * We might want to rewrite this some day, if we don't replace it with
+ * a battery first. For now we just preserve the API as we found it
+ * while re-implementing it on top of the new keystore.
+ */
+
+hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len)
+{
+ if (buf != NULL && len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ flash_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ return err;
+
+ if (block->pin.kek_set != FLASH_KEK_SET)
+ return HAL_ERROR_MASTERKEY_NOT_SET;
+
+ if (buf != NULL)
+ memcpy(buf, block->pin.kek, len);
+
+ return HAL_OK;
+}
+
+hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len)
+{
+ if (buf == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ flash_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ return err;
+
+ flash_pin_block_t new_data = block->pin;
+
+ new_data.kek_set = FLASH_KEK_SET;
+ memcpy(new_data.kek, buf, len);
+
+ return update_pin_block(b, block, &new_data);
+}
+
+hal_error_t hal_mkm_flash_erase(const size_t len)
+{
+ if (len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ flash_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ return err;
+
+ flash_pin_block_t new_data = block->pin;
+
+ new_data.kek_set = FLASH_KEK_SET;
+ memset(new_data.kek, 0, len);
+
+ return update_pin_block(b, block, &new_data);
+}
+
+#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */
/*
diff --git a/ks_index.c b/ks_index.c
new file mode 100644
index 0000000..0c12fcc
--- /dev/null
+++ b/ks_index.c
@@ -0,0 +1,457 @@
+/*
+ * ks_index.c
+ * ----------
+ * Keystore index API. This is internal within libhal.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+/*
+ * Compare two hal_ks_name_t objects.
+ */
+
+static inline int ks_name_cmp(const hal_ks_name_t * const name1, const hal_ks_name_t * const name2)
+{
+ assert(name1 != NULL && name2 != NULL);
+
+ int cmp = hal_uuid_cmp(&name1->name, &name2->name);
+
+ if (cmp == 0)
+ cmp = ((int) name1->chunk) - ((int) name2->chunk);
+
+ return cmp;
+}
+
+/*
+ * Return value indicates whether the name is present in the index.
+ * "where" indicates the name's position whether present or not.
+ *
+ * NB: This does NOT return a block number, it returns an index into
+ * ksi->index[].
+ */
+
+static int ks_find(const hal_ks_index_t * const ksi,
+ const hal_uuid_t * const uuid,
+ const uint8_t chunk,
+ const int * const hint,
+ int *where)
+{
+ assert(ksi != NULL && ksi->index != NULL && ksi->names != NULL && uuid != NULL && where != NULL);
+
+ const hal_ks_name_t name = { *uuid, chunk };
+
+ if (hint != NULL && *hint >= 0 && *hint < ksi->used &&
+ ks_name_cmp(&name, &ksi->names[ksi->index[*hint]]) == 0) {
+ *where = *hint;
+ return 1;
+ }
+
+ int lo = -1;
+ int hi = ksi->used;
+
+ for (;;) {
+ int m = (lo + hi) / 2;
+ if (hi == 0 || m == lo) {
+ *where = hi;
+ return 0;
+ }
+ const int cmp = ks_name_cmp(&name, &ksi->names[ksi->index[m]]);
+ if (cmp < 0)
+ hi = m;
+ else if (cmp > 0)
+ lo = m;
+ else {
+ *where = m;
+ return 1;
+ }
+ }
+}
+
+/*
+ * Heapsort the index. We only need to do this on setup, for other
+ * operations we're just inserting or deleting a single entry in an
+ * already-ordered array, which is just a search problem. If we were
+ * really crunched for space, we could use an insertion sort here, but
+ * heapsort is easy and works well with data already in place.
+ */
+
+static inline void ks_heapsift(hal_ks_index_t *ksi, int parent, const int end)
+{
+ assert(ksi != NULL && ksi->index != NULL && ksi->names != NULL &&
+ parent >= 0 && end >= parent);
+ for (;;) {
+ const int left_child = parent * 2 + 1;
+ const int right_child = parent * 2 + 2;
+ int biggest = parent;
+ if (left_child <= end && ks_name_cmp(&ksi->names[ksi->index[biggest]],
+ &ksi->names[ksi->index[left_child]]) < 0)
+ biggest = left_child;
+ if (right_child <= end && ks_name_cmp(&ksi->names[ksi->index[biggest]],
+ &ksi->names[ksi->index[right_child]]) < 0)
+ biggest = right_child;
+ if (biggest == parent)
+ return;
+ const uint16_t tmp = ksi->index[biggest];
+ ksi->index[biggest] = ksi->index[parent];
+ ksi->index[parent] = tmp;
+ parent = biggest;
+ }
+}
+
+static inline void ks_heapsort(hal_ks_index_t *ksi)
+{
+ assert(ksi != NULL && ksi->index != NULL && ksi->names != NULL);
+ if (ksi->used < 2)
+ return;
+ for (int i = (ksi->used - 2) / 2; i >= 0; i--)
+ ks_heapsift(ksi, i, ksi->used - 1);
+ for (int i = ksi->used - 1; i > 0; i--) {
+ const uint16_t tmp = ksi->index[i];
+ ksi->index[i] = ksi->index[0];
+ ksi->index[0] = tmp;
+ ks_heapsift(ksi, 0, i - 1);
+ }
+}
+
+#define fsck(_ksi) \
+ do { hal_error_t _err = hal_ks_index_fsck(_ksi); if (_err != HAL_OK) return _err; } while (0)
+
+
+hal_error_t hal_ks_index_fsck(hal_ks_index_t *ksi)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ for (int i = 0; i < ksi->used; i++) {
+
+ const int cmp = i == 0 ? -1 : hal_uuid_cmp(&ksi->names[ksi->index[i - 1]].name,
+ &ksi->names[ksi->index[i ]].name);
+
+ const uint8_t prev_chunk = i == 0 ? 0 : ksi->names[ksi->index[i - 1]].chunk;
+ const uint8_t cur_chunk = ksi->names[ksi->index[i ]].chunk;
+
+ if (cmp > 0)
+ return HAL_ERROR_KSI_INDEX_UUID_MISORDERED;
+
+ if (cur_chunk > 0 && cmp != 0)
+ return HAL_ERROR_KSI_INDEX_CHUNK_ORPHANED;
+
+ if (cur_chunk > 0 && prev_chunk + 1 < cur_chunk)
+ return HAL_ERROR_KSI_INDEX_CHUNK_MISSING;
+
+ if (cur_chunk > 0 && prev_chunk + 1 > cur_chunk)
+ return HAL_ERROR_KSI_INDEX_CHUNK_OVERLAPS;
+ }
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_setup(hal_ks_index_t *ksi)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Only setup task we have at the moment is sorting the index.
+ */
+
+ ks_heapsort(ksi);
+
+ /*
+ * One might think we should fsck here, but errors in the index
+ * at this point probably relate to errors in the supplied data,
+ * which only the driver knows how to clean up.
+ */
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_find(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ int where;
+
+ fsck(ksi);
+
+ int ok = ks_find(ksi, name, chunk, hint, &where);
+
+ if (blockno != NULL)
+ *blockno = ksi->index[where];
+
+ if (hint != NULL)
+ *hint = where;
+
+ return ok ? HAL_OK : HAL_ERROR_KEY_NOT_FOUND;
+}
+
+hal_error_t hal_ks_index_find_range(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned max_blocks,
+ unsigned *n_blocks,
+ unsigned *blocknos,
+ int *hint,
+ const int strict)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ int where;
+
+ fsck(ksi);
+
+ if (!ks_find(ksi, name, 0, hint, &where))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ int n = 0;
+
+ for (int i = where; i < ksi->used && !hal_uuid_cmp(name, &ksi->names[ksi->index[i]].name); i++) {
+ if (strict && n != ksi->names[ksi->index[i]].chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+ if (blocknos != NULL && n < max_blocks)
+ blocknos[n] = ksi->index[i];
+ n++;
+ }
+
+ if (n_blocks != NULL)
+ *n_blocks = n;
+
+ if (hint != NULL)
+ *hint = where;
+
+ if (blocknos != NULL && n > max_blocks)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ksi->used == ksi->size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ int where;
+
+ fsck(ksi);
+
+ if (ks_find(ksi, name, chunk, hint, &where))
+ return HAL_ERROR_KEY_NAME_IN_USE;
+
+ /*
+ * Grab first block on free list, which makes room to slide the
+ * index up by one slot so we can insert the new block number.
+ */
+
+ const size_t len = (ksi->used - where) * sizeof(*ksi->index);
+ const uint16_t b = ksi->index[ksi->used++];
+ memmove(&ksi->index[where + 1], &ksi->index[where], len);
+ ksi->index[where] = b;
+ ksi->names[b].name = *name;
+ ksi->names[b].chunk = chunk;
+
+ if (blockno != NULL)
+ *blockno = b;
+
+ if (hint != NULL)
+ *hint = where;
+
+ fsck(ksi);
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ int where;
+
+ fsck(ksi);
+
+ if (ksi->used == 0 || !ks_find(ksi, name, chunk, hint, &where))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ /*
+ * Free the block and stuff it at the end of the free list.
+ */
+
+ const size_t len = (ksi->size - where - 1) * sizeof(*ksi->index);
+ const uint16_t b = ksi->index[where];
+ memmove(&ksi->index[where], &ksi->index[where + 1], len);
+ ksi->index[ksi->size - 1] = b;
+ ksi->used--;
+ memset(&ksi->names[b], 0, sizeof(ksi->names[b]));
+
+ if (blockno != NULL)
+ *blockno = b;
+
+ if (hint != NULL)
+ *hint = where;
+
+ fsck(ksi);
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_delete_range(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned max_blocks,
+ unsigned *n_blocks,
+ unsigned *blocknos,
+ int *hint)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ int where;
+
+ fsck(ksi);
+
+ if (ksi->used == 0 || !ks_find(ksi, name, 0, hint, &where))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ int n = 0;
+
+ for (int i = where; i < ksi->used && !hal_uuid_cmp(name, &ksi->names[ksi->index[i]].name); i++) {
+ if (n != ksi->names[ksi->index[i]].chunk)
+ return HAL_ERROR_IMPOSSIBLE;
+ if (blocknos != NULL && n < max_blocks)
+ blocknos[n] = ksi->index[i];
+ n++;
+ }
+
+ if (n_blocks != NULL)
+ *n_blocks = n;
+
+ /*
+ * Free the blocks and stuff them at the end of the free list.
+ */
+
+ if (blocknos != NULL) {
+ if (n > max_blocks)
+ return HAL_ERROR_RESULT_TOO_LONG;
+ const size_t len = (ksi->size - where - n) * sizeof(*ksi->index);
+ memmove(&ksi->index[where], &ksi->index[where + n], len);
+ ksi->used -= n;
+ for (int i = 0; i < n; i++) {
+ ksi->index[ksi->size - n + i] = blocknos[i];
+ memset(&ksi->names[blocknos[i]], 0, sizeof(ksi->names[blocknos[i]]));
+ }
+ where = -1;
+ }
+
+ if (hint != NULL)
+ *hint = where;
+
+ fsck(ksi);
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
+ const hal_uuid_t * const name,
+ const unsigned chunk,
+ unsigned *blockno,
+ int *hint)
+{
+ if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
+ ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ksi->used == ksi->size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ int where;
+
+ fsck(ksi);
+
+ if (ksi->used == 0 || !ks_find(ksi, name, chunk, hint, &where))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ /*
+ * Grab first block from free list, slide free list down, put old
+ * block at end of free list and replace old block with new block.
+ */
+
+ const size_t len = (ksi->size - ksi->used - 1) * sizeof(*ksi->index);
+ const uint16_t b1 = ksi->index[where];
+ const uint16_t b2 = ksi->index[ksi->used];
+ memmove(&ksi->index[ksi->used], &ksi->index[ksi->used + 1], len);
+ ksi->index[ksi->size - 1] = b1;
+ ksi->index[where] = b2;
+ ksi->names[b2].name = *name;
+ ksi->names[b2].chunk = chunk;
+ memset(&ksi->names[b1], 0, sizeof(ksi->names[b1]));
+
+ if (blockno != NULL)
+ *blockno = b2;
+
+ if (hint != NULL)
+ *hint = where;
+
+ fsck(ksi);
+
+ return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_mmap.c b/ks_mmap.c
index cca9d3f..066e93e 100644
--- a/ks_mmap.c
+++ b/ks_mmap.c
@@ -125,8 +125,8 @@ hal_error_t hal_ks_del_keydb(const int loc)
return HAL_OK;
}
-hal_error_t hal_ks_set_pin(const hal_user_t user,
- const hal_ks_pin_t * const pin)
+hal_error_t hal_set_pin(const hal_user_t user,
+ const hal_ks_pin_t * const pin)
{
if (pin == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -144,7 +144,7 @@ hal_error_t hal_ks_set_pin(const hal_user_t user,
return HAL_OK;
}
-hal_error_t hal_ks_get_kek(uint8_t *kek,
+hal_error_t hal_mkm_get_kek(uint8_t *kek,
size_t *kek_len,
const size_t kek_max)
{
diff --git a/ks_volatile.c b/ks_volatile.c
index 00f656a..99ad68c 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -7,7 +7,7 @@
* to survive library exit, eg, for storing PKCS #11 session keys.
*
* Authors: Rob Austein
- * Copyright (c) 2015, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -37,106 +37,530 @@
*/
#include <string.h>
+#include <assert.h>
#include "hal.h"
#include "hal_internal.h"
+#define KEK_LENGTH (bitsToBytes(256))
+
+#ifndef STATIC_KS_VOLATILE_SLOTS
+#define STATIC_KS_VOLATILE_SLOTS HAL_STATIC_PKEY_STATE_BLOCKS
+#endif
+
+#ifndef STATIC_KS_VOLATILE_ATTRIBUTE_SPACE
+#define STATIC_KS_VOLATILE_ATTRIBUTE_SPACE 4096
+#endif
+
/*
- * Splitting the different keystore backends out into separate files
- * seemed like a good idea at the time, but the code is getting
- * somewhat repetitive. Might want to re-merge and conditionalize in
- * some other way. Deferred until we sort out ks_flash.c.
+ * In-memory keystore database. This should also be usable for
+ * mmap(), if and when we get around to rewriting that driver (and in
+ * which case this driver probably ought to be renamed ks_memory).
*/
+typedef struct {
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ hal_client_handle_t client;
+ hal_session_handle_t session;
+ size_t der_len;
+ unsigned attributes_len;
+ uint8_t der[HAL_KS_WRAPPED_KEYSIZE + STATIC_KS_VOLATILE_ATTRIBUTE_SPACE];
+} ks_key_t;
+
+typedef struct {
+ hal_ks_index_t ksi;
+ ks_key_t *keys;
+} db_t;
+
+/*
+ * "Subclass" (well, what one can do in C) of hal_ks_t. This is
+ * separate from db_t primarily to simplify things like rewriting the
+ * old ks_mmap driver to piggy-back on the ks_volatile driver: we
+ * wouldn't want the hal_ks_t into the mmap()ed file.
+ */
+
+typedef struct {
+ hal_ks_t ks; /* Must be first */
+ db_t *db; /* Which memory-based keystore database */
+ int per_session; /* Whether objects are per-session */
+} ks_t;
+
/*
- * Use a one-element array here so that references can be pointer-based
- * as in the other implementations, to ease re-merge at some later date.
+ * If we also supported mmap, there would be a separate definition for
+ * HAL_KS_MMAP_SLOTS above, and the bulk of the code would be under a
+ * conditional testing whether either HAL_KS_*_SLOTS were nonzero.
*/
-static hal_ks_keydb_t db[1];
+#if STATIC_KS_VOLATILE_SLOTS > 0
+
+static ks_t volatile_ks;
+
+static inline ks_t *ks_to_ksv(hal_ks_t *ks)
+{
+ return (ks_t *) ks;
+}
/*
- * There's no good place to store the master key (KEK) in this volatile memory implementation.
- * We might be able to add a bit of protection doing things like using locked physical memory,
- * as gpg does, or obfuscating the KEK a bit to make it harder to pull out of a crash dump,
- * but, really, there's not a lot we can do against a determined opponant in this case.
+ * Check whether the current session can see a particular key. One
+ * might expect this to be based on whether the session matches, and
+ * indeed it would be in a sane world, but in the world of PKCS #11,
+ * keys belong to sessions, are visible to other sessions, and may
+ * even be modifiable by other sessions, but softly and silently
+ * vanish away when the original creating session is destroyed.
*
- * For now, we just go through the motions.
+ * In our terms, this means that visibility of session objects is
+ * determined only by the client handle, so taking the session handle
+ * as an argument here isn't really necessary, but we've flipflopped
+ * on that enough times that at least for now I'd prefer to leave the
+ * session handle here and not have to revise all the RPC calls again.
+ * Remove it at some later date and redo the RPC calls if we manage to
+ * avoid revising this yet again.
*/
-static uint8_t kekbuf[bitsToBytes(256)];
+static inline int key_visible_to_session(const ks_t * const ksv,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const ks_key_t * const k)
+{
+ return !ksv->per_session || client.handle == HAL_HANDLE_NONE || k->client.handle == client.handle;
+}
+
+static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
+{
+ if (mem == NULL || *mem == NULL || len == NULL || size > *len)
+ return NULL;
+ void *ret = *mem;
+ *mem += size;
+ *len -= size;
+ return ret;
+}
+
+static hal_error_t ks_init(const hal_ks_driver_t * const driver,
+ const int per_session,
+ ks_t *ksv,
+ uint8_t *mem,
+ size_t len)
+{
+ if (ksv == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (mem != NULL) {
+ memset(ksv, 0, sizeof(*ksv));
+ memset(mem, 0, len);
+
+ ksv->db = gnaw(&mem, &len, sizeof(*ksv->db));
+ ksv->db->ksi.index = gnaw(&mem, &len, sizeof(*ksv->db->ksi.index) * STATIC_KS_VOLATILE_SLOTS);
+ ksv->db->ksi.names = gnaw(&mem, &len, sizeof(*ksv->db->ksi.names) * STATIC_KS_VOLATILE_SLOTS);
+ ksv->db->keys = gnaw(&mem, &len, sizeof(*ksv->db->keys) * STATIC_KS_VOLATILE_SLOTS);
+ ksv->db->ksi.size = STATIC_KS_VOLATILE_SLOTS;
+ }
+
+ if (ksv->db == NULL ||
+ ksv->db->ksi.index == NULL ||
+ ksv->db->ksi.names == NULL ||
+ ksv->db->keys == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (mem == NULL) {
+ memset(ksv->db->ksi.index, 0, sizeof(*ksv->db->ksi.index) * STATIC_KS_VOLATILE_SLOTS);
+ memset(ksv->db->ksi.names, 0, sizeof(*ksv->db->ksi.names) * STATIC_KS_VOLATILE_SLOTS);
+ memset(ksv->db->keys, 0, sizeof(*ksv->db->keys) * STATIC_KS_VOLATILE_SLOTS);
+ }
+
+ ksv->ks.driver = driver;
+ ksv->per_session = per_session;
+ ksv->db->ksi.used = 0;
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
+ /*
+ * Set up keystore with empty index and full free list.
+ * Since this driver doesn't care about wear leveling,
+ * just populate the free list in block numerical order.
+ */
+
+ for (int i = 0; i < STATIC_KS_VOLATILE_SLOTS; i++)
+ ksv->db->ksi.index[i] = i;
+
+ return hal_ks_index_setup(&ksv->db->ksi);
+}
+
+static hal_error_t ks_volatile_init(const hal_ks_driver_t * const driver, const int alloc)
{
- return db;
+ const size_t len = (sizeof(*volatile_ks.db) +
+ sizeof(*volatile_ks.db->ksi.index) * STATIC_KS_VOLATILE_SLOTS +
+ sizeof(*volatile_ks.db->ksi.names) * STATIC_KS_VOLATILE_SLOTS +
+ sizeof(*volatile_ks.db->keys) * STATIC_KS_VOLATILE_SLOTS);
+
+ uint8_t *mem = NULL;
+
+ if (alloc && (mem = hal_allocate_static_memory(len)) == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+
+ return ks_init(driver, 1, &volatile_ks, mem, len);
+}
+
+static hal_error_t ks_volatile_shutdown(const hal_ks_driver_t * const driver)
+{
+ if (volatile_ks.ks.driver != driver)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ return HAL_OK;
+}
+
+static hal_error_t ks_volatile_open(const hal_ks_driver_t * const driver,
+ hal_ks_t **ks)
+{
+ assert(driver != NULL && ks != NULL);
+ *ks = &volatile_ks.ks;
+ return HAL_OK;
+}
+
+static hal_error_t ks_volatile_close(hal_ks_t *ks)
+{
+ return HAL_OK;
+}
+
+static inline int acceptable_key_type(const hal_key_type_t type)
+{
+ switch (type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ case HAL_KEY_TYPE_EC_PRIVATE:
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ case HAL_KEY_TYPE_EC_PUBLIC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static hal_error_t ks_store(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (ks == NULL || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ ks_t *ksv = ks_to_ksv(ks);
+ hal_error_t err;
+ unsigned b;
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err = hal_ks_index_add(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+ ks_key_t k;
+
+ memset(&k, 0, sizeof(k));
+ k.der_len = sizeof(k.der);
+ k.type = slot->type;
+ k.curve = slot->curve;
+ k.flags = slot->flags;
+ k.client = slot->client_handle;
+ k.session = slot->session_handle;
+
+ if ((err = hal_mkm_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)
+ ksv->db->keys[b] = k;
+ else
+ (void) hal_ks_index_delete(&ksv->db->ksi, &slot->name, 0, NULL, &slot->hint);
+
+ return err;
+}
+
+static hal_error_t ks_fetch(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (ks == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ ks_t *ksv = ks_to_ksv(ks);
+ hal_error_t err;
+ unsigned b;
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ const ks_key_t * const k = &ksv->db->keys[b];
+
+ if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ slot->type = k->type;
+ slot->curve = k->curve;
+ slot->flags = k->flags;
+
+ if (der == NULL && der_len != NULL)
+ *der_len = k->der_len;
+
+ if (der != NULL) {
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len, der_len_;
+ hal_error_t err;
+
+ if (der_len == NULL)
+ der_len = &der_len_;
+
+ *der_len = der_max;
+
+ if ((err = hal_mkm_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_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating)
+static hal_error_t ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot)
{
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
+ if (ks == NULL || slot == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
+ ks_t *ksv = ks_to_ksv(ks);
+ hal_error_t err;
+ unsigned b;
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, &ksv->db->keys[b]))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if ((err = hal_ks_index_delete(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ memset(&ksv->db->keys[b], 0, sizeof(ksv->db->keys[b]));
+
return HAL_OK;
}
-hal_error_t hal_ks_del_keydb(const int loc)
+static hal_error_t ks_match(hal_ks_t *ks,
+ hal_client_handle_t client,
+ hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
{
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
+ if (ks == NULL || (attributes == NULL && attributes_len > 0) ||
+ result == NULL || result_len == NULL || previous_uuid == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- memset(&db->keys[loc], 0, sizeof(db->keys[loc]));
+ ks_t *ksv = ks_to_ksv(ks);
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ hal_error_t err;
+ int i = -1;
+
+ *result_len = 0;
+
+ err = hal_ks_index_find(&ksv->db->ksi, previous_uuid, 0, NULL, &i);
+
+ if (err == HAL_ERROR_KEY_NOT_FOUND)
+ i--;
+ else if (err != HAL_OK)
+ return err;
+
+ while (*result_len < result_max && ++i < ksv->db->ksi.used) {
+
+ unsigned b = ksv->db->ksi.index[i];
+
+ if (ksv->db->ksi.names[b].chunk > 0)
+ continue;
+
+ if (type != HAL_KEY_TYPE_NONE && type != ksv->db->keys[b].type)
+ continue;
+
+ if (curve != HAL_CURVE_NONE && curve != ksv->db->keys[b].curve)
+ continue;
+
+ if (!key_visible_to_session(ksv, client, session, &ksv->db->keys[b]))
+ continue;
+
+ if (attributes_len > 0) {
+ const ks_key_t * const k = &ksv->db->keys[b];
+ int ok = 1;
+
+ if (k->attributes_len == 0)
+ continue;
+
+ hal_pkey_attribute_t key_attrs[k->attributes_len];
+
+ if ((err = hal_ks_attribute_scan(k->der + k->der_len, sizeof(k->der) - k->der_len,
+ key_attrs, k->attributes_len, NULL)) != HAL_OK)
+ return err;
+
+ for (const hal_pkey_attribute_t *required = attributes;
+ ok && required < attributes + attributes_len; required++) {
+
+ hal_pkey_attribute_t *present = key_attrs;
+ while (ok && present->type != required->type)
+ ok = ++present < key_attrs + k->attributes_len;
+
+ if (ok)
+ ok = (present->length == required->length &&
+ !memcmp(present->value, required->value, present->length));
+ }
+
+ if (!ok)
+ continue;
+ }
+
+ result[*result_len] = ksv->db->ksi.names[b].name;
+ ++*result_len;
+ }
+
return HAL_OK;
}
-hal_error_t hal_ks_set_pin(const hal_user_t user,
- const hal_ks_pin_t * const pin)
+static hal_error_t ks_set_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
{
- if (pin == NULL)
+ if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0)
return HAL_ERROR_BAD_ARGUMENTS;
- hal_ks_pin_t *p = NULL;
+ ks_t *ksv = ks_to_ksv(ks);
+ hal_error_t err;
+ unsigned b;
+
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
- switch (user) {
- case HAL_USER_WHEEL: p = &db->wheel_pin; break;
- case HAL_USER_SO: p = &db->so_pin; break;
- case HAL_USER_NORMAL: p = &db->user_pin; break;
- default: return HAL_ERROR_BAD_ARGUMENTS;
+ ks_key_t * const k = &ksv->db->keys[b];
+
+ if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k))
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ hal_pkey_attribute_t attrs[k->attributes_len + attributes_len];
+ uint8_t *bytes = k->der + k->der_len;
+ size_t bytes_len = sizeof(k->der) - k->der_len;
+ size_t total_len;
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, k->attributes_len, &total_len)) != HAL_OK)
+ return err;
+
+ for (const hal_pkey_attribute_t *a = attributes; a < attributes + attributes_len; a++) {
+ if (a->length == HAL_PKEY_ATTRIBUTE_NIL)
+ err = hal_ks_attribute_delete(bytes, bytes_len, attrs, &k->attributes_len, &total_len,
+ a->type);
+ else
+ err = hal_ks_attribute_insert(bytes, bytes_len, attrs, &k->attributes_len, &total_len,
+ a->type, a->value, a->length);
+ if (err != HAL_OK)
+ return err;
}
- *p = *pin;
return HAL_OK;
}
-hal_error_t hal_ks_get_kek(uint8_t *kek,
- size_t *kek_len,
- const size_t kek_max)
+static hal_error_t ks_get_attributes(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
{
- if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128))
+ if (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0 ||
+ attributes_buffer == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
+ ks_t *ksv = ks_to_ksv(ks);
hal_error_t err;
+ unsigned b;
- const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) :
- (kek_max < bitsToBytes(256)) ? bitsToBytes(192) :
- bitsToBytes(256));
+ if (ksv->db == NULL)
+ return HAL_ERROR_KEYSTORE_ACCESS;
- uint8_t t = 0;
+ if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
+ return err;
+
+ const ks_key_t * const k = &ksv->db->keys[b];
- for (int i = 0; i < sizeof(kekbuf); i++)
- t |= kekbuf[i];
+ if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k))
+ return HAL_ERROR_KEY_NOT_FOUND;
- if (t == 0 && (err = hal_rpc_get_random(kekbuf, sizeof(kekbuf))) != HAL_OK)
+ hal_pkey_attribute_t attrs[k->attributes_len > 0 ? k->attributes_len : 1];
+
+ if ((err = hal_ks_attribute_scan(k->der + k->der_len, sizeof(k->der) - k->der_len,
+ attrs, k->attributes_len, NULL)) != HAL_OK)
return err;
- memcpy(kek, kekbuf, len);
- *kek_len = len;
+ uint8_t *abuf = attributes_buffer;
+
+ for (int i = 0; i < attributes_len; i++) {
+ int j = 0;
+ while (j < k->attributes_len && attrs[j].type != attributes[i].type)
+ j++;
+ const int found = j < k->attributes_len;
+
+ if (attributes_buffer_len == 0) {
+ attributes[i].value = NULL;
+ attributes[i].length = found ? attrs[j].length : 0;
+ continue;
+ }
+
+ if (!found)
+ return HAL_ERROR_ATTRIBUTE_NOT_FOUND;
+
+ if (attrs[j].length > attributes_buffer + attributes_buffer_len - abuf)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ memcpy(abuf, attrs[j].value, attrs[j].length);
+ attributes[i].value = abuf;
+ attributes[i].length = attrs[j].length;
+ abuf += attrs[j].length;
+ }
+
return HAL_OK;
}
+const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
+ .init = ks_volatile_init,
+ .shutdown = ks_volatile_shutdown,
+ .open = ks_volatile_open,
+ .close = ks_volatile_close,
+ .store = ks_store,
+ .fetch = ks_fetch,
+ .delete = ks_delete,
+ .match = ks_match,
+ .set_attributes = ks_set_attributes,
+ .get_attributes = ks_get_attributes
+}};
+
+#endif /* STATIC_KS_VOLATILE_SLOTS > 0 */
+
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/libhal.py b/libhal.py
new file mode 100644
index 0000000..369e5e1
--- /dev/null
+++ b/libhal.py
@@ -0,0 +1,662 @@
+# Copyright (c) 2016, NORDUnet A/S
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of the NORDUnet nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+A Python interface to the Cryptech libhal RPC API.
+"""
+
+# A lot of this is hand-generated XDR data structure encoding. If and
+# when we ever convert the C library to use data structures processed
+# by rpcgen, we may want to rewrite this code to use the output of
+# something like https://github.com/floodlight/xdr.git -- in either
+# case the generated code would just be for the data structures, we're
+# not likely to want to use the full ONC RPC mechanism.
+
+import os
+import sys
+import time
+import uuid
+import xdrlib
+import serial
+import contextlib
+
+SLIP_END = chr(0300) # indicates end of packet
+SLIP_ESC = chr(0333) # indicates byte stuffing
+SLIP_ESC_END = chr(0334) # ESC ESC_END means END data byte
+SLIP_ESC_ESC = chr(0335) # ESC ESC_ESC means ESC data byte
+
+HAL_OK = 0
+
+class HALError(Exception):
+ "LibHAL error"
+
+ table = [None]
+
+ @classmethod
+ def define(cls, **kw):
+ assert len(kw) == 1
+ name, text = kw.items()[0]
+ e = type(name, (cls,), dict(__doc__ = text))
+ cls.table.append(e)
+ globals()[name] = e
+
+HALError.define(HAL_ERROR_BAD_ARGUMENTS = "Bad arguments given")
+HALError.define(HAL_ERROR_UNSUPPORTED_KEY = "Unsupported key type or key length")
+HALError.define(HAL_ERROR_IO_SETUP_FAILED = "Could not set up I/O with FPGA")
+HALError.define(HAL_ERROR_IO_TIMEOUT = "I/O with FPGA timed out")
+HALError.define(HAL_ERROR_IO_UNEXPECTED = "Unexpected response from FPGA")
+HALError.define(HAL_ERROR_IO_OS_ERROR = "Operating system error talking to FPGA")
+HALError.define(HAL_ERROR_IO_BAD_COUNT = "Bad byte count")
+HALError.define(HAL_ERROR_CSPRNG_BROKEN = "CSPRNG is returning nonsense")
+HALError.define(HAL_ERROR_KEYWRAP_BAD_MAGIC = "Bad magic number while unwrapping key")
+HALError.define(HAL_ERROR_KEYWRAP_BAD_LENGTH = "Length out of range while unwrapping key")
+HALError.define(HAL_ERROR_KEYWRAP_BAD_PADDING = "Non-zero padding detected unwrapping key")
+HALError.define(HAL_ERROR_IMPOSSIBLE = "\"Impossible\" error")
+HALError.define(HAL_ERROR_ALLOCATION_FAILURE = "Memory allocation failed")
+HALError.define(HAL_ERROR_RESULT_TOO_LONG = "Result too long for buffer")
+HALError.define(HAL_ERROR_ASN1_PARSE_FAILED = "ASN.1 parse failed")
+HALError.define(HAL_ERROR_KEY_NOT_ON_CURVE = "EC key is not on its purported curve")
+HALError.define(HAL_ERROR_INVALID_SIGNATURE = "Invalid signature")
+HALError.define(HAL_ERROR_CORE_NOT_FOUND = "Requested core not found")
+HALError.define(HAL_ERROR_CORE_BUSY = "Requested core busy")
+HALError.define(HAL_ERROR_KEYSTORE_ACCESS = "Could not access keystore")
+HALError.define(HAL_ERROR_KEY_NOT_FOUND = "Key not found")
+HALError.define(HAL_ERROR_KEY_NAME_IN_USE = "Key name in use")
+HALError.define(HAL_ERROR_NO_KEY_SLOTS_AVAILABLE = "No key slots available")
+HALError.define(HAL_ERROR_PIN_INCORRECT = "PIN incorrect")
+HALError.define(HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE = "No client slots available")
+HALError.define(HAL_ERROR_FORBIDDEN = "Forbidden")
+HALError.define(HAL_ERROR_XDR_BUFFER_OVERFLOW = "XDR buffer overflow")
+HALError.define(HAL_ERROR_RPC_TRANSPORT = "RPC transport error")
+HALError.define(HAL_ERROR_RPC_PACKET_OVERFLOW = "RPC packet overflow")
+HALError.define(HAL_ERROR_RPC_BAD_FUNCTION = "Bad RPC function number")
+HALError.define(HAL_ERROR_KEY_NAME_TOO_LONG = "Key name too long")
+HALError.define(HAL_ERROR_MASTERKEY_NOT_SET = "Master key (Key Encryption Key) not set")
+HALError.define(HAL_ERROR_MASTERKEY_FAIL = "Master key generic failure")
+HALError.define(HAL_ERROR_MASTERKEY_BAD_LENGTH = "Master key of unacceptable length")
+HALError.define(HAL_ERROR_KS_DRIVER_NOT_FOUND = "Keystore driver not found")
+HALError.define(HAL_ERROR_KEYSTORE_BAD_CRC = "Bad CRC in keystore")
+HALError.define(HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE = "Unsupported keystore block type")
+HALError.define(HAL_ERROR_KEYSTORE_LOST_DATA = "Keystore appears to have lost data")
+HALError.define(HAL_ERROR_BAD_ATTRIBUTE_LENGTH = "Bad attribute length")
+HALError.define(HAL_ERROR_ATTRIBUTE_NOT_FOUND = "Attribute not found")
+HALError.define(HAL_ERROR_NO_KEY_INDEX_SLOTS = "No key index slots available")
+HALError.define(HAL_ERROR_KSI_INDEX_UUID_MISORDERED = "Key index UUID misordered")
+HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_ORPHANED = "Key index chunk orphaned")
+HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_MISSING = "Key index chunk missing")
+HALError.define(HAL_ERROR_KSI_INDEX_CHUNK_OVERLAPS = "Key index chunk overlaps")
+HALError.define(HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE = "Wrong block type in keystore")
+HALError.define(HAL_ERROR_RPC_PROTOCOL_ERROR = "RPC protocol error")
+HALError.define(HAL_ERROR_NOT_IMPLEMENTED = "Not implemented")
+
+
+class Enum(int):
+
+ def __new__(cls, name, value):
+ self = int.__new__(cls, value)
+ self._name = name
+ setattr(self.__class__, name, self)
+ return self
+
+ def __str__(self):
+ return self._name
+
+ def __repr__(self):
+ return "<Enum:{0.__class__.__name__} {0._name}:{0:d}>".format(self)
+
+ _counter = 0
+
+ @classmethod
+ def define(cls, names):
+ symbols = []
+ for name in names.translate(None, "{}").split(","):
+ if "=" in name:
+ name, sep, expr = name.partition("=")
+ cls._counter = eval(expr.strip())
+ if not isinstance(cls._counter, int):
+ raise TypeError
+ symbols.append(cls(name.strip(), cls._counter))
+ cls._counter += 1
+ cls.index = dict((int(symbol), symbol) for symbol in symbols)
+ globals().update((symbol._name, symbol) for symbol in symbols)
+
+ def xdr_packer(self, packer):
+ packer.pack_uint(self)
+
+
+class RPCFunc(Enum): pass
+
+RPCFunc.define('''
+ RPC_FUNC_GET_VERSION,
+ RPC_FUNC_GET_RANDOM,
+ RPC_FUNC_SET_PIN,
+ RPC_FUNC_LOGIN,
+ RPC_FUNC_LOGOUT,
+ RPC_FUNC_LOGOUT_ALL,
+ RPC_FUNC_IS_LOGGED_IN,
+ RPC_FUNC_HASH_GET_DIGEST_LEN,
+ RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID,
+ RPC_FUNC_HASH_GET_ALGORITHM,
+ RPC_FUNC_HASH_INITIALIZE,
+ RPC_FUNC_HASH_UPDATE,
+ RPC_FUNC_HASH_FINALIZE,
+ RPC_FUNC_PKEY_LOAD,
+ RPC_FUNC_PKEY_OPEN,
+ RPC_FUNC_PKEY_GENERATE_RSA,
+ RPC_FUNC_PKEY_GENERATE_EC,
+ RPC_FUNC_PKEY_CLOSE,
+ RPC_FUNC_PKEY_DELETE,
+ RPC_FUNC_PKEY_GET_KEY_TYPE,
+ RPC_FUNC_PKEY_GET_KEY_FLAGS,
+ RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN,
+ RPC_FUNC_PKEY_GET_PUBLIC_KEY,
+ RPC_FUNC_PKEY_SIGN,
+ RPC_FUNC_PKEY_VERIFY,
+ RPC_FUNC_PKEY_MATCH,
+ RPC_FUNC_PKEY_GET_KEY_CURVE,
+ RPC_FUNC_PKEY_SET_ATTRIBUTES,
+ RPC_FUNC_PKEY_GET_ATTRIBUTES,
+''')
+
+class HALDigestAlgorithm(Enum): pass
+
+HALDigestAlgorithm.define('''
+ HAL_DIGEST_ALGORITHM_NONE,
+ HAL_DIGEST_ALGORITHM_SHA1,
+ HAL_DIGEST_ALGORITHM_SHA224,
+ HAL_DIGEST_ALGORITHM_SHA256,
+ HAL_DIGEST_ALGORITHM_SHA512_224,
+ HAL_DIGEST_ALGORITHM_SHA512_256,
+ HAL_DIGEST_ALGORITHM_SHA384,
+ HAL_DIGEST_ALGORITHM_SHA512
+''')
+
+class HALKeyType(Enum): pass
+
+HALKeyType.define('''
+ HAL_KEY_TYPE_NONE,
+ HAL_KEY_TYPE_RSA_PRIVATE,
+ HAL_KEY_TYPE_RSA_PUBLIC,
+ HAL_KEY_TYPE_EC_PRIVATE,
+ HAL_KEY_TYPE_EC_PUBLIC
+''')
+
+class HALCurve(Enum): pass
+
+HALCurve.define('''
+ HAL_CURVE_NONE,
+ HAL_CURVE_P256,
+ HAL_CURVE_P384,
+ HAL_CURVE_P521
+''')
+
+class HALUser(Enum): pass
+
+HALUser.define('''
+ HAL_USER_NONE,
+ HAL_USER_NORMAL,
+ HAL_USER_SO,
+ HAL_USER_WHEEL
+''')
+
+HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE = (1 << 0)
+HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT = (1 << 1)
+HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT = (1 << 2)
+HAL_KEY_FLAG_TOKEN = (1 << 3)
+HAL_KEY_FLAG_PUBLIC = (1 << 4)
+
+HAL_PKEY_ATTRIBUTE_NIL = (0xFFFFFFFF)
+
+
+class UUID(uuid.UUID):
+
+ def xdr_packer(self, packer):
+ packer.pack_bytes(self.bytes)
+
+
+def cached_property(func):
+
+ attr_name = "_" + func.__name__
+
+ def wrapped(self):
+ try:
+ value = getattr(self, attr_name)
+ except AttributeError:
+ value = func(self)
+ setattr(self, attr_name, value)
+ return value
+
+ wrapped.__name__ = func.__name__
+
+ return property(wrapped)
+
+
+class Handle(object):
+
+ def __int__(self):
+ return self.handle
+
+ def __cmp__(self, other):
+ return cmp(self.handle, int(other))
+
+ def xdr_packer(self, packer):
+ packer.pack_uint(self.handle)
+
+
+class Digest(Handle):
+
+ def __init__(self, hsm, handle, algorithm):
+ self.hsm = hsm
+ self.handle = handle
+ self.algorithm = algorithm
+
+ def update(self, data):
+ self.hsm.hash_update(self, data)
+
+ def finalize(self, length = None):
+ return self.hsm.hash_finalize(self, length or self.digest_length)
+
+ @cached_property
+ def algorithm_id(self):
+ return self.hsm.hash_get_digest_algorithm_id(self.algorithm)
+
+ @cached_property
+ def digest_length(self):
+ return self.hsm.hash_get_digest_length(self.algorithm)
+
+
+class LocalDigest(object):
+ """
+ Implements same interface as Digest class, but using PyCrypto, to
+ support mixed-mode PKey operations. This only supports algorithms
+ that PyCrypto supports, so no SHA512/224 or SHA512/256, sorry.
+ """
+
+ def __init__(self, hsm, handle, algorithm, key):
+ from Crypto.Hash import HMAC, SHA, SHA224, SHA256, SHA384, SHA512
+ self.hsm = hsm
+ self.handle = handle
+ self.algorithm = algorithm
+ try:
+ h = self._algorithms[algorithm]
+ except AttributeError:
+ self._algorithms = {
+ HAL_DIGEST_ALGORITHM_SHA1 : SHA.SHA1Hash,
+ HAL_DIGEST_ALGORITHM_SHA224 : SHA224.SHA224Hash,
+ HAL_DIGEST_ALGORITHM_SHA256 : SHA256.SHA256Hash,
+ HAL_DIGEST_ALGORITHM_SHA384 : SHA384.SHA384Hash,
+ HAL_DIGEST_ALGORITHM_SHA512 : SHA512.SHA512Hash
+ }
+ h = self._algorithms[algorithm]
+ self.digest_length = h.digest_size
+ self.algorithm_id = chr(0x30) + chr(2 + len(h.oid)) + h.oid
+ self._context = HMAC.HMAC(key = key, digestmod = h) if key else h()
+
+ def update(self, data):
+ self._context.update(data)
+
+ def finalize(self, length = None):
+ return self._context.digest()
+
+ def finalize_padded(self, pkey):
+ if pkey.key_type not in (HAL_KEY_TYPE_RSA_PRIVATE, HAL_KEY_TYPE_RSA_PUBLIC):
+ return self.finalize()
+ # PKCS #1.5 requires the digest to be wrapped up in an ASN.1 DigestInfo object.
+ from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
+ return DerSequence([DerSequence([self._context.oid, DerNull().encode()]).encode(),
+ DerOctetString(self.finalize()).encode()]).encode()
+
+
+class PKey(Handle):
+
+ def __init__(self, hsm, handle, uuid):
+ self.hsm = hsm
+ self.handle = handle
+ self.uuid = uuid
+ self.deleted = False
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if not self.deleted:
+ self.close()
+
+ def close(self):
+ self.hsm.pkey_close(self)
+
+ def delete(self):
+ self.hsm.pkey_delete(self)
+ self.deleted = True
+
+ @cached_property
+ def key_type(self):
+ return self.hsm.pkey_get_key_type(self)
+
+ @cached_property
+ def key_curve(self):
+ return self.hsm.pkey_get_key_curve(self)
+
+ @cached_property
+ def key_flags(self):
+ return self.hsm.pkey_get_key_flags(self)
+
+ @cached_property
+ def public_key_len(self):
+ return self.hsm.pkey_get_public_key_len(self)
+
+ @cached_property
+ def public_key(self):
+ return self.hsm.pkey_get_public_key(self, self.public_key_len)
+
+ def sign(self, hash = 0, data = "", length = 1024):
+ return self.hsm.pkey_sign(self, hash = hash, data = data, length = length)
+
+ def verify(self, hash = 0, data = "", signature = None):
+ self.hsm.pkey_verify(self, hash = hash, data = data, signature = signature)
+
+ def set_attributes(self, attributes):
+ self.hsm.pkey_set_attributes(self, attributes)
+
+ def get_attributes(self, attributes):
+ attrs = self.hsm.pkey_get_attributes(self, attributes, 0)
+ attrs = dict((k, v) for k, v in attrs.iteritems() if v != HAL_PKEY_ATTRIBUTE_NIL)
+ result = dict((a, None) for a in attributes)
+ result.update(self.hsm.pkey_get_attributes(self, attrs.iterkeys(), sum(attrs.itervalues())))
+ return result
+
+
+class HSM(object):
+
+ debug = False
+ mixed_mode = False
+
+ _send_delay = 0 # 0.1
+
+ def _raise_if_error(self, status):
+ if status != 0:
+ raise HALError.table[status]()
+
+ def __init__(self, device = os.getenv("CRYPTECH_RPC_CLIENT_SERIAL_DEVICE", "/dev/ttyUSB0")):
+ while True:
+ try:
+ self.tty = serial.Serial(device, 921600, timeout = 0.1)
+ break
+ except serial.SerialException:
+ time.sleep(0.2)
+
+ def _write(self, c):
+ if self.debug:
+ sys.stdout.write("{:02x}".format(ord(c)))
+ self.tty.write(c)
+ if self._send_delay > 0:
+ time.sleep(self._send_delay)
+
+ def _send(self, msg): # Expects an xdrlib.Packer
+ if self.debug:
+ sys.stdout.write("+send: ")
+ self._write(SLIP_END)
+ for c in msg.get_buffer():
+ if c == SLIP_END:
+ self._write(SLIP_ESC)
+ self._write(SLIP_ESC_END)
+ elif c == SLIP_ESC:
+ self._write(SLIP_ESC)
+ self._write(SLIP_ESC_ESC)
+ else:
+ self._write(c)
+ self._write(SLIP_END)
+ if self.debug:
+ sys.stdout.write("\n")
+
+ def _recv(self, code): # Returns an xdrlib.Unpacker
+ if self.debug:
+ sys.stdout.write("+recv: ")
+ msg = []
+ esc = False
+ while True:
+ c = self.tty.read(1)
+ if self.debug and c:
+ sys.stdout.write("{:02x}".format(ord(c)))
+ if not c:
+ time.sleep(0.1)
+ elif c == SLIP_END and not msg:
+ continue
+ elif c == SLIP_END:
+ if self.debug:
+ sys.stdout.write("\n")
+ msg = xdrlib.Unpacker("".join(msg))
+ if msg.unpack_uint() == code:
+ return msg
+ msg = []
+ if self.debug:
+ sys.stdout.write("+recv: ")
+ elif c == SLIP_ESC:
+ esc = True
+ elif esc and c == SLIP_ESC_END:
+ esc = False
+ msg.append(SLIP_END)
+ elif esc and c == SLIP_ESC_ESC:
+ esc = False
+ msg.append(SLIP_ESC)
+ else:
+ msg.append(c)
+
+ _pack_builtin = (((int, long), "_pack_uint"),
+ (str, "_pack_bytes"),
+ ((list, tuple, set), "_pack_array"),
+ (dict, "_pack_items"))
+
+ def _pack_arg(self, packer, arg):
+ if hasattr(arg, "xdr_packer"):
+ return arg.xdr_packer(packer)
+ for cls, method in self._pack_builtin:
+ if isinstance(arg, cls):
+ return getattr(self, method)(packer, arg)
+ raise RuntimeError("Don't know how to pack {!r} ({!r})".format(arg, type(arg)))
+
+ def _pack_args(self, packer, args):
+ for arg in args:
+ self._pack_arg(packer, arg)
+
+ def _pack_uint(self, packer, arg):
+ packer.pack_uint(arg)
+
+ def _pack_bytes(self, packer, arg):
+ packer.pack_bytes(arg)
+
+ def _pack_array(self, packer, arg):
+ packer.pack_uint(len(arg))
+ self._pack_args(packer, arg)
+
+ def _pack_items(self, packer, arg):
+ packer.pack_uint(len(arg))
+ for name, value in arg.iteritems():
+ self._pack_arg(packer, name)
+ self._pack_arg(packer, HAL_PKEY_ATTRIBUTE_NIL if value is None else value)
+
+ @contextlib.contextmanager
+ def rpc(self, code, *args, **kwargs):
+ client = kwargs.get("client", 0)
+ packer = xdrlib.Packer()
+ packer.pack_uint(code)
+ packer.pack_uint(client)
+ self._pack_args(packer, args)
+ self._send(packer)
+ unpacker = self._recv(code)
+ client = unpacker.unpack_uint()
+ self._raise_if_error(unpacker.unpack_uint())
+ yield unpacker
+ unpacker.done()
+
+ def get_version(self):
+ with self.rpc(RPC_FUNC_GET_VERSION) as r:
+ return r.unpack_uint()
+
+ def get_random(self, n):
+ with self.rpc(RPC_FUNC_GET_RANDOM, n) as r:
+ return r.unpack_bytes()
+
+ def set_pin(self, user, pin, client = 0):
+ with self.rpc(RPC_FUNC_SET_PIN, user, pin, client = client):
+ return
+
+ def login(self, user, pin, client = 0):
+ with self.rpc(RPC_FUNC_LOGIN, user, pin, client = client):
+ return
+
+ def logout(self, client = 0):
+ with self.rpc(RPC_FUNC_LOGOUT, client = client):
+ return
+
+ def logout_all(self):
+ with self.rpc(RPC_FUNC_LOGOUT_ALL):
+ return
+
+ def is_logged_in(self, user, client = 0):
+ with self.rpc(RPC_FUNC_IS_LOGGED_IN, user, client = client):
+ return
+
+ def hash_get_digest_length(self, alg):
+ with self.rpc(RPC_FUNC_HASH_GET_DIGEST_LEN, alg) as r:
+ return r.unpack_uint()
+
+ def hash_get_digest_algorithm_id(self, alg, max_len = 256):
+ with self.rpc(RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID, alg, max_len) as r:
+ return r.unpack_bytes()
+
+ def hash_get_algorithm(self, handle):
+ with self.rpc(RPC_FUNC_HASH_GET_ALGORITHM, handle) as r:
+ return HALDigestAlgorithm.index[r.unpack_uint()]
+
+ def hash_initialize(self, alg, key = "", client = 0, session = 0, mixed_mode = None):
+ if mixed_mode is None:
+ mixed_mode = self.mixed_mode
+ if mixed_mode:
+ return LocalDigest(self, 0, alg, key)
+ else:
+ with self.rpc(RPC_FUNC_HASH_INITIALIZE, session, alg, key, client = client) as r:
+ return Digest(self, r.unpack_uint(), alg)
+
+ def hash_update(self, handle, data):
+ with self.rpc(RPC_FUNC_HASH_UPDATE, handle, data):
+ return
+
+ def hash_finalize(self, handle, length = None):
+ if length is None:
+ length = self.hash_get_digest_length(self.hash_get_algorithm(handle))
+ with self.rpc(RPC_FUNC_HASH_FINALIZE, handle, length) as r:
+ return r.unpack_bytes()
+
+ def pkey_load(self, type, curve, der, flags = 0, client = 0, session = 0):
+ with self.rpc(RPC_FUNC_PKEY_LOAD, session, type, curve, der, flags, client = client) as r:
+ return PKey(self, r.unpack_uint(), UUID(bytes = r.unpack_bytes()))
+
+ def pkey_open(self, uuid, flags = 0, client = 0, session = 0):
+ with self.rpc(RPC_FUNC_PKEY_OPEN, session, uuid, flags, client = client) as r:
+ return PKey(self, r.unpack_uint(), uuid)
+
+ def pkey_generate_rsa(self, keylen, exponent = "\x01\x00\x01", flags = 0, client = 0, session = 0):
+ with self.rpc(RPC_FUNC_PKEY_GENERATE_RSA, session, keylen, exponent, flags, client = client) as r:
+ return PKey(self, r.unpack_uint(), UUID(bytes = r.unpack_bytes()))
+
+ def pkey_generate_ec(self, curve, flags = 0, client = 0, session = 0):
+ with self.rpc(RPC_FUNC_PKEY_GENERATE_EC, session, curve, flags, client = client) as r:
+ return PKey(self, r.unpack_uint(), UUID(bytes = r.unpack_bytes()))
+
+ def pkey_close(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_CLOSE, pkey):
+ return
+
+ def pkey_delete(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_DELETE, pkey):
+ return
+
+ def pkey_get_key_type(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_GET_KEY_TYPE, pkey) as r:
+ return HALKeyType.index[r.unpack_uint()]
+
+ def pkey_get_key_curve(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_GET_KEY_CURVE, pkey) as r:
+ return HALCurve.index[r.unpack_uint()]
+
+ def pkey_get_key_flags(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_GET_KEY_FLAGS, pkey) as r:
+ return r.unpack_uint()
+
+ def pkey_get_public_key_len(self, pkey):
+ with self.rpc(RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN, pkey) as r:
+ return r.unpack_uint()
+
+ def pkey_get_public_key(self, pkey, length = None):
+ if length is None:
+ length = self.pkey_get_public_key_len(pkey)
+ with self.rpc(RPC_FUNC_PKEY_GET_PUBLIC_KEY, pkey, length) as r:
+ return r.unpack_bytes()
+
+ def pkey_sign(self, pkey, hash = 0, data = "", length = 1024):
+ assert not hash or not data
+ if isinstance(hash, LocalDigest):
+ hash, data = 0, hash.finalize_padded(pkey)
+ with self.rpc(RPC_FUNC_PKEY_SIGN, pkey, hash, data, length) as r:
+ return r.unpack_bytes()
+
+ def pkey_verify(self, pkey, hash = 0, data = "", signature = None):
+ assert not hash or not data
+ if isinstance(hash, LocalDigest):
+ hash, data = 0, hash.finalize_padded(pkey)
+ with self.rpc(RPC_FUNC_PKEY_VERIFY, pkey, hash, data, signature):
+ return
+
+ def pkey_match(self, type = 0, curve = 0, flags = 0, attributes = {},
+ length = 64, client = 0, session = 0):
+ u = UUID(int = 0)
+ n = length
+ while n == length:
+ with self.rpc(RPC_FUNC_PKEY_MATCH, session, type, curve, flags,
+ attributes, length, u, client = client) as r:
+ n = r.unpack_uint()
+ for i in xrange(n):
+ u = UUID(bytes = r.unpack_bytes())
+ yield u
+
+ def pkey_set_attributes(self, pkey, attributes):
+ with self.rpc(RPC_FUNC_PKEY_SET_ATTRIBUTES, pkey, attributes):
+ return
+
+ def pkey_get_attributes(self, pkey, attributes, attributes_buffer_len = 2048):
+ attributes = tuple(attributes)
+ with self.rpc(RPC_FUNC_PKEY_GET_ATTRIBUTES, pkey, attributes, attributes_buffer_len) as r:
+ n = r.unpack_uint()
+ if n != len(attributes):
+ raise HAL_ERROR_RPC_PROTOCOL_ERROR
+ if attributes_buffer_len > 0:
+ return dict((r.unpack_uint(), r.unpack_bytes()) for i in xrange(n))
+ else:
+ return dict((r.unpack_uint(), r.unpack_uint()) for i in xrange(n))
diff --git a/masterkey.c b/masterkey.c
deleted file mode 100644
index 3c4f0d3..0000000
--- a/masterkey.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * masterkey.c
- * -----------
- * Masterkey set/get functions.
- *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Code to load the Master key (Key Encryption Key) from either the volatile MKM
- * (by asking the FPGA to provide it, using the mkmif) or from the last sector in
- * the keystore flash.
- *
- * Storing the master key in flash is a pretty Bad Idea, but since the Alpha board
- * doesn't have a battery mounted (only pin headers for attaching one), it might
- * help in non-production use where one doesn't have tamper protection anyways.
- *
- * For production use on the Alpha, one option is to have the Master Key on paper
- * and enter it into volatile RAM after each power on.
- *
- * In both volatile memory and flash, the data is stored as a 32 bit status to
- * know if the memory is initialized or not, followed by 32 bytes (256 bits) of
- * Master Key.
- */
-
-#define HAL_OK CMIS_HAL_OK
-#include "stm-init.h"
-#include "stm-keystore.h"
-#undef HAL_OK
-
-#define HAL_OK LIBHAL_OK
-#include "hal.h"
-#include "masterkey.h"
-#undef HAL_OK
-
-#include <string.h>
-
-
-static int volatile_init = 0, flash_init = 0;
-static hal_core_t *core = NULL;
-
-#define MKM_VOLATILE_STATUS_ADDRESS 0
-#define MKM_VOLATILE_SCLK_DIV 0x20
-#define MKM_FLASH_STATUS_ADDRESS (KEYSTORE_SECTOR_SIZE * (KEYSTORE_NUM_SECTORS - 1))
-#define KEK_LENGTH (256 / 8)
-
-/* Match uninitialized flash for the "not set" value.
- * Leave some bits at 1 for the "set" value to allow
- * for adding more values later, if needed.
- */
-#define MKM_STATUS_NOT_SET 0xffffffff
-#define MKM_STATUS_SET 0x0000ffff
-#define MKM_STATUS_ERASED 0x00000000
-
-
-hal_error_t masterkey_volatile_init()
-{
- hal_error_t err;
- uint32_t status;
-
- if (! volatile_init) {
- if ((core = hal_core_find(MKMIF_NAME, NULL)) == NULL) {
- return HAL_ERROR_CORE_NOT_FOUND;
- }
-
- if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != LIBHAL_OK ||
- (err = hal_mkmif_init(core)) != LIBHAL_OK ||
- (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK)
- return err;
-
- if (status != MKM_STATUS_SET && status != MKM_STATUS_NOT_SET) {
- /* XXX Something is a bit fishy here. If we just write the status word, it reads back wrong sometimes,
- * while if we write the full buf too it is consistently right afterwards.
- */
- uint8_t buf[KEK_LENGTH] = {0};
- if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK ||
- (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK)
- return err;
- }
-
- volatile_init = 1;
- }
- return LIBHAL_OK;
-}
-
-hal_error_t masterkey_volatile_read(uint8_t *buf, size_t len)
-{
- hal_error_t err;
- uint32_t status;
-
- if (len && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
-
- if ((err = masterkey_volatile_init()) != LIBHAL_OK ||
- (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK)
- return err;
-
- if (buf != NULL && len) {
- /* Don't return the random bytes in the RAM memory in case it isn't initialized.
- * Or maybe we should fill the buffer with proper random data in that case... hmm.
- */
- if (status == MKM_STATUS_SET) {
- if ((err = hal_mkmif_read(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK) {
- return err;
- }
- } else {
- memset(buf, 0x0, len);
- }
- }
-
- if (status == MKM_STATUS_SET) return LIBHAL_OK;
- if (status == MKM_STATUS_NOT_SET) return HAL_ERROR_MASTERKEY_NOT_SET;
-
- return HAL_ERROR_MASTERKEY_FAIL;
-}
-
-hal_error_t masterkey_volatile_write(uint8_t *buf, size_t len)
-{
- hal_error_t err;
-
- if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
- if (! buf) return HAL_ERROR_MASTERKEY_FAIL;
-
- if ((err = masterkey_volatile_init()) != LIBHAL_OK ||
- (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK ||
- (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != LIBHAL_OK)
- return err;
-
- return LIBHAL_OK;
-}
-
-hal_error_t masterkey_volatile_erase(size_t len)
-{
- uint8_t buf[KEK_LENGTH] = {0};
- hal_error_t err;
-
- if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
-
- if ((err = masterkey_volatile_init()) != LIBHAL_OK ||
- (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK ||
- (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK)
- return err;
-
- return LIBHAL_OK;
-}
-
-hal_error_t masterkey_flash_init()
-{
- if (! flash_init) {
- if (! keystore_check_id()) return HAL_ERROR_IO_UNEXPECTED;
- flash_init = 1;
- }
- return LIBHAL_OK;
-}
-
-hal_error_t masterkey_flash_read(uint8_t *buf, size_t len)
-{
- uint8_t page[KEYSTORE_PAGE_SIZE];
- uint32_t *status = (uint32_t *) page;
- hal_error_t err;
-
- if (len && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
-
- if ((err = masterkey_flash_init()) != LIBHAL_OK) return err;
-
- if (! keystore_read_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page))) {
- memset(page, 0, sizeof(page));
- return HAL_ERROR_MASTERKEY_FAIL;
- }
-
- if (buf != NULL && len) {
- /* Don't return what's in the flash memory in case it isn't initialized.
- * Or maybe we should fill the buffer with proper random data in that case... hmm.
- */
- if (*status == MKM_STATUS_SET) {
- memcpy(buf, page + 4, len);
- } else {
- memset(buf, 0x0, len);
- }
- }
-
- memset(page + 4, 0, sizeof(page) - 4);
-
- if (*status == MKM_STATUS_SET) return LIBHAL_OK;
- if (*status == MKM_STATUS_ERASED || *status == MKM_STATUS_NOT_SET) return HAL_ERROR_MASTERKEY_NOT_SET;
-
- return HAL_ERROR_MASTERKEY_FAIL;
-}
-
-hal_error_t masterkey_flash_write(uint8_t *buf, size_t len)
-{
- uint8_t page[KEYSTORE_PAGE_SIZE] = {0xff};
- uint32_t *status = (uint32_t *) page;
- int res;
-
- if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
- if (buf == NULL) return HAL_ERROR_MASTERKEY_FAIL;
-
- if (masterkey_flash_init() != LIBHAL_OK) return HAL_ERROR_MASTERKEY_FAIL;
-
- *status = MKM_STATUS_SET;
- memcpy(page + 4, buf, len);
-
- res = keystore_write_data(MKM_FLASH_STATUS_ADDRESS, page, sizeof(page));
- memset(page, 0, sizeof(page));
- if (res != 1) {
- return HAL_ERROR_MASTERKEY_FAIL;
- }
-
- return LIBHAL_OK;
-}
-
-hal_error_t masterkey_flash_erase(size_t len)
-{
- if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH;
-
- if (keystore_erase_sectors(MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE,
- MKM_FLASH_STATUS_ADDRESS / KEYSTORE_SECTOR_SIZE) != 1) {
- return HAL_ERROR_MASTERKEY_FAIL;
- }
-
- return LIBHAL_OK;
-}
diff --git a/mkm.c b/mkm.c
new file mode 100644
index 0000000..2b2141f
--- /dev/null
+++ b/mkm.c
@@ -0,0 +1,230 @@
+/*
+ * mkm.c
+ * -----
+ * Master Key Memory functions.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Code to load the Master key (Key Encryption Key) from either the volatile MKM
+ * (by asking the FPGA to provide it, using the mkmif) or from the last sector in
+ * the keystore flash.
+ *
+ * Storing the master key in flash is a pretty Bad Idea, but since the Alpha board
+ * doesn't have a battery mounted (only pin headers for attaching one), it might
+ * help in non-production use where one doesn't have tamper protection anyways.
+ *
+ * For production use on the Alpha, one option is to have the Master Key on paper
+ * and enter it into volatile RAM after each power on.
+ *
+ * In both volatile memory and flash, the data is stored as a 32 bit status to
+ * know if the memory is initialized or not, followed by 32 bytes (256 bits) of
+ * Master Key.
+ */
+
+#define HAL_OK CMIS_HAL_OK
+#include "stm-init.h"
+#include "stm-keystore.h"
+#undef HAL_OK
+
+#define HAL_OK LIBHAL_OK
+#include "hal.h"
+#include "hal_internal.h"
+#undef HAL_OK
+
+#include <string.h>
+
+
+static int volatile_init = 0;
+static hal_core_t *core = NULL;
+
+#define MKM_VOLATILE_STATUS_ADDRESS 0
+#define MKM_VOLATILE_SCLK_DIV 0x20
+#define MKM_FLASH_STATUS_ADDRESS (KEYSTORE_SECTOR_SIZE * (KEYSTORE_NUM_SECTORS - 1))
+
+/*
+ * Match uninitialized flash for the "not set" value.
+ * Leave some bits at 1 for the "set" value to allow
+ * for adding more values later, if needed.
+ */
+#define MKM_STATUS_NOT_SET 0xffffffff
+#define MKM_STATUS_SET 0x0000ffff
+#define MKM_STATUS_ERASED 0x00000000
+
+
+static hal_error_t hal_mkm_volatile_init(void)
+{
+ if (volatile_init)
+ return LIBHAL_OK;
+
+ hal_error_t err;
+ uint32_t status;
+
+ if ((core = hal_core_find(MKMIF_NAME, NULL)) == NULL)
+ return HAL_ERROR_CORE_NOT_FOUND;
+
+ if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != LIBHAL_OK ||
+ (err = hal_mkmif_init(core)) != LIBHAL_OK ||
+ (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK)
+ return err;
+
+ if (status != MKM_STATUS_SET && status != MKM_STATUS_NOT_SET) {
+ /*
+ * XXX Something is a bit fishy here. If we just write the status word, it reads back wrong sometimes,
+ * while if we write the full buf too it is consistently right afterwards.
+ */
+ uint8_t buf[KEK_LENGTH] = {0};
+ if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK ||
+ (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK)
+ return err;
+ }
+
+ volatile_init = 1;
+ return LIBHAL_OK;
+}
+
+hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len)
+{
+ hal_error_t err;
+ uint32_t status;
+
+ if (len && len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ if ((err = hal_mkm_volatile_init()) != LIBHAL_OK ||
+ (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK)
+ return err;
+
+ if (buf != NULL && len) {
+ /*
+ * Don't return the random bytes in the RAM memory in case it isn't initialized.
+ * Or maybe we should fill the buffer with proper random data in that case... hmm.
+ */
+ if (status != MKM_STATUS_SET)
+ memset(buf, 0x0, len);
+ else if ((err = hal_mkmif_read(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK)
+ return err;
+ }
+
+ if (status == MKM_STATUS_SET)
+ return LIBHAL_OK;
+
+ if (status == MKM_STATUS_NOT_SET)
+ return HAL_ERROR_MASTERKEY_NOT_SET;
+
+ return HAL_ERROR_MASTERKEY_FAIL;
+}
+
+hal_error_t hal_mkm_volatile_write(const uint8_t * const buf, const size_t len)
+{
+ hal_error_t err;
+
+ if (len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ if (buf == NULL)
+ return HAL_ERROR_MASTERKEY_FAIL;
+
+ if ((err = hal_mkm_volatile_init()) != LIBHAL_OK ||
+ (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK ||
+ (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != LIBHAL_OK)
+ return err;
+
+ return LIBHAL_OK;
+}
+
+hal_error_t hal_mkm_volatile_erase(const size_t len)
+{
+ uint8_t buf[KEK_LENGTH] = {0};
+ hal_error_t err;
+
+ if (len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ if ((err = hal_mkm_volatile_init()) != LIBHAL_OK ||
+ (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK ||
+ (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK)
+ return err;
+
+ return LIBHAL_OK;
+}
+
+/*
+ * hal_mkm_flash_*() functions moved to ks_flash.c, to keep all the code that
+ * knows intimate details of the keystore flash layout in one place.
+ */
+
+hal_error_t hal_mkm_get_kek(uint8_t *kek,
+ size_t *kek_len,
+ const size_t kek_max)
+{
+ if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) :
+ (kek_max < bitsToBytes(256)) ? bitsToBytes(192) :
+ bitsToBytes(256));
+
+ hal_error_t err = hal_mkm_volatile_read(kek, len);
+
+ if (err == LIBHAL_OK) {
+ *kek_len = len;
+ return LIBHAL_OK;
+ }
+
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
+
+ if (hal_mkm_flash_read(kek, len) == LIBHAL_OK) {
+ *kek_len = len;
+ return LIBHAL_OK;
+ }
+
+#endif
+
+ /*
+ * Both keystores returned an error, probably HAL_ERROR_MASTERKEY_NOT_SET.
+ * I could try to be clever and compare the errors, but really the volatile
+ * keystore is the important one (you shouldn't store the master key in
+ * flash), so return that error.
+ */
+ return err;
+}
+
+/*
+ * "Any programmer who fails to comply with the standard naming, formatting,
+ * or commenting conventions should be shot. If it so happens that it is
+ * inconvenient to shoot him, then he is to be politely requested to recode
+ * his program in adherence to the above standard."
+ * -- Michael Spier, Digital Equipment Corporation
+ *
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/rpc_api.c b/rpc_api.c
index a19bdb4..6ffd7a0 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -75,7 +75,7 @@ static inline int check_pkey_flags(const hal_key_flags_t flags)
return (flags &~ (HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE |
HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT |
HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT |
- HAL_KEY_FLAG_PROXIMATE)) == 0;
+ HAL_KEY_FLAG_TOKEN)) == 0;
}
static inline int check_pkey_type_curve_flags(const hal_key_type_t type,
@@ -218,36 +218,30 @@ hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- if (pkey == NULL || name == NULL || der == NULL || der_len == 0 ||
- !check_pkey_type_curve_flags(type, curve, flags))
+ if (pkey == NULL || name == NULL || der == NULL || der_len == 0 || !check_pkey_type_curve_flags(type, curve, flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->load(client, session, pkey, type, curve, name, name_len, der, der_len, flags);
+ return hal_rpc_pkey_dispatch->load(client, session, pkey, type, curve, name, der, der_len, flags);
}
-hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client,
+hal_error_t hal_rpc_pkey_open(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- if (pkey == NULL || name == NULL || !check_pkey_type(type))
+ if (pkey == NULL || name == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->find(client, session, pkey, type, name, name_len, flags);
+ return hal_rpc_pkey_dispatch->open(client, session, pkey, name, flags);
}
hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_len,
const uint8_t * const exp, const size_t exp_len,
const hal_key_flags_t flags)
@@ -255,24 +249,20 @@ hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client,
if (pkey == NULL || name == NULL || key_len == 0 || (key_len & 7) != 0 ||
exp == NULL || exp_len == 0 || !check_pkey_flags(flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->generate_rsa(client, session, pkey, name, name_len, key_len, exp, exp_len, flags);
+ return hal_rpc_pkey_dispatch->generate_rsa(client, session, pkey, name, key_len, exp, exp_len, flags);
}
hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
if (pkey == NULL || name == NULL ||
!check_pkey_type_curve_flags(HAL_KEY_TYPE_EC_PRIVATE, curve, flags))
return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, name_len, curve, flags);
+ return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, curve, flags);
}
hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey)
@@ -285,16 +275,6 @@ hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey)
return hal_rpc_pkey_dispatch->delete(pkey);
}
-hal_error_t hal_rpc_pkey_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- if (name == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
- if (name_len > HAL_RPC_PKEY_NAME_MAX)
- return HAL_ERROR_KEY_NAME_TOO_LONG;
- return hal_rpc_pkey_dispatch->rename(pkey, name, name_len);
-}
-
hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey,
hal_key_type_t *type)
{
@@ -303,6 +283,14 @@ hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey,
return hal_rpc_pkey_dispatch->get_key_type(pkey, type);
}
+hal_error_t hal_rpc_pkey_get_key_curve(const hal_pkey_handle_t pkey,
+ hal_curve_name_t *curve)
+{
+ if (curve == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hal_rpc_pkey_dispatch->get_key_curve(pkey, curve);
+}
+
hal_error_t hal_rpc_pkey_get_key_flags(const hal_pkey_handle_t pkey,
hal_key_flags_t *flags)
{
@@ -324,8 +312,7 @@ hal_error_t hal_rpc_pkey_get_public_key(const hal_pkey_handle_t pkey,
return hal_rpc_pkey_dispatch->get_public_key(pkey, der, der_len, der_max);
}
-hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+hal_error_t hal_rpc_pkey_sign(const hal_pkey_handle_t pkey,
const hal_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)
@@ -333,11 +320,10 @@ hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session,
if (signature == NULL || signature_len == NULL || signature_max == 0 ||
(hash.handle == HAL_HANDLE_NONE) == (input == NULL || input_len == 0))
return HAL_ERROR_BAD_ARGUMENTS;
- return hal_rpc_pkey_dispatch->sign(session, pkey, hash, input, input_len, signature, signature_len, signature_max);
+ return hal_rpc_pkey_dispatch->sign(pkey, hash, input, input_len, signature, signature_len, signature_max);
}
-hal_error_t hal_rpc_pkey_verify(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+hal_error_t hal_rpc_pkey_verify(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
const uint8_t * const input, const size_t input_len,
const uint8_t * const signature, const size_t signature_len)
@@ -345,17 +331,54 @@ hal_error_t hal_rpc_pkey_verify(const hal_session_handle_t session,
if (signature == NULL || signature_len == 0 ||
(hash.handle == HAL_HANDLE_NONE) == (input == NULL || input_len == 0))
return HAL_ERROR_BAD_ARGUMENTS;
- return hal_rpc_pkey_dispatch->verify(session, pkey, hash, input, input_len, signature, signature_len);
+ return hal_rpc_pkey_dispatch->verify(pkey, hash, input, input_len, signature, signature_len);
+}
+
+hal_error_t hal_rpc_pkey_match(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
+{
+ if ((attributes == NULL && attributes_len > 0) || previous_uuid == NULL ||
+ result == NULL || result_len == NULL || result_max == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (attributes != NULL)
+ for (int i = 0; i < attributes_len; i++)
+ if (attributes[i].value == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return hal_rpc_pkey_dispatch->match(client, session, type, curve, flags,
+ attributes, attributes_len,
+ result, result_len, result_max, previous_uuid);
+}
+
+hal_error_t hal_rpc_pkey_set_attributes(const hal_pkey_handle_t pkey,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
+{
+ if (attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hal_rpc_pkey_dispatch->set_attributes(pkey, attributes, attributes_len);
}
-hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max,
- hal_key_flags_t flags)
+hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
{
- if (result == NULL || result_len == NULL || result_max == 0)
+ if (attributes == NULL || attributes_len == 0)
return HAL_ERROR_BAD_ARGUMENTS;
- return hal_rpc_pkey_dispatch->list(result, result_len, result_max, flags);
+ return hal_rpc_pkey_dispatch->get_attributes(pkey, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len);
}
/*
diff --git a/rpc_client.c b/rpc_client.c
index c4ceedd..4adf247 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -101,6 +101,16 @@ static hal_error_t read_matching_packet(const rpc_func_num_t expected_func,
/*
* RPC calls.
+ *
+ * In reading these, it helps to know that every call takes a minimum
+ * of two arguments (function code and client handle, even if the
+ * latter is just a dummy), and that every call returns a minimum of
+ * three values (function code, client handle, and return status).
+ * This may seem a bit redundant, but There Are Reasons:
+ * read_matching_packet() wants to make sure the result we're getting
+ * is from the function we thought we called, and having the client
+ * handle always present in a known place vastly simplifies the task
+ * of the client-side MUX daemon.
*/
static hal_error_t get_version(uint32_t *version)
@@ -292,13 +302,14 @@ static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
check(hal_xdr_encode_int(&optr, olimit, alg));
check(hal_xdr_encode_int(&optr, olimit, len_max));
check(hal_rpc_send(outbuf, optr - outbuf));
- check(read_matching_packet(RPC_FUNC_HASH_GET_DIGEST_LEN, inbuf, sizeof(inbuf), &iptr, &ilimit));
+ check(read_matching_packet(RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID,
+ inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
@@ -411,13 +422,14 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(8) + pad(name_len) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(7) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
@@ -425,7 +437,6 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, type));
check(hal_xdr_encode_int(&optr, olimit, curve));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_buffer(&optr, olimit, der, der_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -433,35 +444,39 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_LOAD, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
-static hal_error_t pkey_remote_find(const hal_client_handle_t client,
+static hal_error_t pkey_remote_open(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t outbuf[nargs(5) + pad(sizeof(name->uuid))], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
hal_error_t rpc_ret;
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_FIND));
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_OPEN));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
- check(hal_xdr_encode_int(&optr, olimit, type));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
+ check(hal_xdr_encode_buffer(&optr, olimit, name->uuid, sizeof(name->uuid)));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
- check(read_matching_packet(RPC_FUNC_PKEY_FIND, inbuf, sizeof(inbuf), &iptr, &ilimit));
+ check(read_matching_packet(RPC_FUNC_PKEY_OPEN, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+
if (rpc_ret == HAL_OK)
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
@@ -471,20 +486,20 @@ static hal_error_t pkey_remote_find(const hal_client_handle_t client,
static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_len,
const uint8_t * const exp, const size_t exp_len,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(7) + pad(name_len) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(6) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_int(&optr, olimit, key_len));
check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
@@ -493,8 +508,13 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_GENERATE_RSA, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
@@ -502,19 +522,19 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
- uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4)];
+ uint8_t outbuf[nargs(5)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_xdr_encode_int(&optr, olimit, curve));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -522,8 +542,13 @@ static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
check(read_matching_packet(RPC_FUNC_PKEY_GENERATE_EC, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
- if (rpc_ret == HAL_OK)
+
+ if (rpc_ret == HAL_OK) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
return rpc_ret;
}
@@ -566,49 +591,52 @@ static hal_error_t pkey_remote_delete(const hal_pkey_handle_t pkey)
return rpc_ret;
}
-static hal_error_t pkey_remote_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
+static hal_error_t pkey_remote_get_key_type(const hal_pkey_handle_t pkey,
+ hal_key_type_t *type)
{
- uint8_t outbuf[nargs(4) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(3)];
+ uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(4)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t type32;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_RENAME));
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
check(hal_rpc_send(outbuf, optr - outbuf));
- check(read_matching_packet(RPC_FUNC_PKEY_RENAME, inbuf, sizeof(inbuf), &iptr, &ilimit));
+ check(read_matching_packet(RPC_FUNC_PKEY_GET_KEY_TYPE, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+ if (rpc_ret == HAL_OK) {
+ check(hal_xdr_decode_int(&iptr, ilimit, &type32));
+ *type = (hal_key_type_t)type32;
+ }
return rpc_ret;
}
-
-static hal_error_t pkey_remote_get_key_type(const hal_pkey_handle_t pkey,
- hal_key_type_t *type)
+static hal_error_t pkey_remote_get_key_curve(const hal_pkey_handle_t pkey,
+ hal_curve_name_t *curve)
{
uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t type32;
+ uint32_t curve32;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE));
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_CURVE));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
check(hal_rpc_send(outbuf, optr - outbuf));
- check(read_matching_packet(RPC_FUNC_PKEY_GET_KEY_TYPE, inbuf, sizeof(inbuf), &iptr, &ilimit));
+ check(read_matching_packet(RPC_FUNC_PKEY_GET_KEY_CURVE, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_int(&iptr, ilimit, &type32));
- *type = (hal_key_type_t)type32;
+ check(hal_xdr_decode_int(&iptr, ilimit, &curve32));
+ *curve = (hal_curve_name_t)curve32;
}
return rpc_ret;
}
@@ -689,13 +717,12 @@ static hal_error_t pkey_remote_get_public_key(const hal_pkey_handle_t pkey,
return rpc_ret;
}
-static hal_error_t pkey_remote_sign(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_remote_sign(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
- const uint8_t * const input, const size_t input_len,
+ const uint8_t * const input, const size_t input_len,
uint8_t * signature, size_t *signature_len, const size_t signature_max)
{
- uint8_t outbuf[nargs(7) + pad(input_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t outbuf[nargs(6) + pad(input_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4) + pad(signature_max)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
uint32_t slen32 = signature_max;
@@ -704,7 +731,6 @@ static hal_error_t pkey_remote_sign(const hal_session_handle_t session,
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_SIGN));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
- check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
check(hal_xdr_encode_int(&optr, olimit, hash.handle));
check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
@@ -721,13 +747,12 @@ static hal_error_t pkey_remote_sign(const hal_session_handle_t session,
return rpc_ret;
}
-static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_remote_verify(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
const uint8_t * const input, const size_t input_len,
const uint8_t * const signature, const size_t signature_len)
{
- uint8_t outbuf[nargs(7) + pad(input_len) + pad(signature_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t outbuf[nargs(6) + pad(input_len) + pad(signature_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(3)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
hal_client_handle_t dummy_client = {0};
@@ -735,7 +760,6 @@ static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_VERIFY));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
- check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
check(hal_xdr_encode_int(&optr, olimit, hash.handle));
check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
@@ -748,46 +772,143 @@ static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
return rpc_ret;
}
-static hal_error_t hal_xdr_decode_pkey_info(const uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info)
+static hal_error_t pkey_remote_match(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
{
- uint32_t i32;
+ size_t attributes_buffer_len = 0;
+ if (attributes != NULL)
+ for (int i = 0; i < attributes_len; i++)
+ attributes_buffer_len += pad(attributes[i].length);
+
+ uint8_t outbuf[nargs(9 + attributes_len * 2) + attributes_buffer_len + pad(sizeof(hal_uuid_t))];
+ uint8_t *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(4) + pad(result_max * sizeof(hal_uuid_t))];
+ const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ hal_error_t rpc_ret;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->type = i32;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->curve = i32;
- check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->flags = i32;
- check(hal_xdr_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32;
- return HAL_OK;
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_MATCH));
+ check(hal_xdr_encode_int(&optr, olimit, client.handle));
+ check(hal_xdr_encode_int(&optr, olimit, session.handle));
+ check(hal_xdr_encode_int(&optr, olimit, type));
+ check(hal_xdr_encode_int(&optr, olimit, curve));
+ check(hal_xdr_encode_int(&optr, olimit, flags));
+ check(hal_xdr_encode_int(&optr, olimit, attributes_len));
+ if (attributes != NULL) {
+ for (int i = 0; i < attributes_len; i++) {
+ check(hal_xdr_encode_int(&optr, olimit, attributes[i].type));
+ check(hal_xdr_encode_buffer(&optr, olimit, attributes[i].value, attributes[i].length));
+ }
+ }
+ check(hal_xdr_encode_int(&optr, olimit, result_max));
+ check(hal_xdr_encode_buffer(&optr, olimit, previous_uuid->uuid, sizeof(previous_uuid->uuid)));
+ check(hal_rpc_send(outbuf, optr - outbuf));
+
+ check(read_matching_packet(RPC_FUNC_PKEY_MATCH, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+ check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+ if (rpc_ret == HAL_OK) {
+ uint32_t array_len;
+ *result_len = 0;
+ check(hal_xdr_decode_int(&iptr, ilimit, &array_len));
+ for (int i = 0; i < array_len; ++i) {
+ uint32_t uuid_len = sizeof(result[i].uuid);
+ check(hal_xdr_decode_buffer(&iptr, ilimit, result[i].uuid, &uuid_len));
+ if (uuid_len != sizeof(result[i].uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
+ *result_len = array_len;
+ }
+ return rpc_ret;
}
-static hal_error_t pkey_remote_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max,
- hal_key_flags_t flags)
+static hal_error_t pkey_remote_set_attributes(const hal_pkey_handle_t pkey,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
{
- uint8_t outbuf[nargs(4)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
- uint8_t inbuf[nargs(4) + pad(result_max * sizeof(hal_pkey_info_t))];
+ size_t outbuf_len = nargs(4 + 2 * attributes_len);
+ for (int i = 0; i < attributes_len; i++)
+ outbuf_len += pad(attributes[i].length);
+
+ uint8_t outbuf[outbuf_len], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(3)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t len;
hal_client_handle_t dummy_client = {0};
- hal_error_t ret, rpc_ret;
+ hal_error_t rpc_ret;
- check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LIST));
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_SET_ATTRIBUTES));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
- check(hal_xdr_encode_int(&optr, olimit, result_max));
- check(hal_xdr_encode_int(&optr, olimit, flags));
+ check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+ check(hal_xdr_encode_int(&optr, olimit, attributes_len));
+ for (int i = 0; i < attributes_len; i++) {
+ check(hal_xdr_encode_int(&optr, olimit, attributes[i].type));
+ if (attributes[i].length == HAL_PKEY_ATTRIBUTE_NIL)
+ check(hal_xdr_encode_int(&optr, olimit, HAL_PKEY_ATTRIBUTE_NIL));
+ else
+ check(hal_xdr_encode_buffer(&optr, olimit, attributes[i].value, attributes[i].length));
+ }
check(hal_rpc_send(outbuf, optr - outbuf));
- check(read_matching_packet(RPC_FUNC_PKEY_LIST, inbuf, sizeof(inbuf), &iptr, &ilimit));
+ check(read_matching_packet(RPC_FUNC_PKEY_SET_ATTRIBUTES, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+ check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+ return rpc_ret;
+}
+
+static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
+{
+ /* inbuf[] here includes one extra word per attribute for padding */
+ uint8_t outbuf[nargs(5 + attributes_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(3 + 3 * attributes_len) + attributes_buffer_len];
+ const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ hal_client_handle_t dummy_client = {0};
+ hal_error_t rpc_ret;
+
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_ATTRIBUTES));
+ check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
+ check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+ check(hal_xdr_encode_int(&optr, olimit, attributes_len));
+ for (int i = 0; i < attributes_len; i++)
+ check(hal_xdr_encode_int(&optr, olimit, attributes[i].type));
+ check(hal_xdr_encode_int(&optr, olimit, attributes_buffer_len));
+ check(hal_rpc_send(outbuf, optr - outbuf));
+
+ check(read_matching_packet(RPC_FUNC_PKEY_GET_ATTRIBUTES, inbuf, sizeof(inbuf), &iptr, &ilimit));
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- int i;
- check(hal_xdr_decode_int(&iptr, ilimit, &len));
- *result_len = len;
- for (i = 0; i < len; ++i) {
- if ((ret = hal_xdr_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) {
- *result_len = 0;
- return ret;
+ uint8_t *abuf = attributes_buffer;
+ uint32_t u32;
+ check(hal_xdr_decode_int(&iptr, ilimit, &u32));
+ if (u32 != attributes_len)
+ return HAL_ERROR_RPC_PROTOCOL_ERROR;
+ for (int i = 0; i < attributes_len; i++) {
+ check(hal_xdr_decode_int(&iptr, ilimit, &u32));
+ if (u32 != attributes[i].type)
+ return HAL_ERROR_RPC_PROTOCOL_ERROR;
+ if (attributes_buffer_len == 0) {
+ check(hal_xdr_decode_int(&iptr, ilimit, &u32));
+ attributes[i].value = NULL;
+ attributes[i].length = u32;
+ }
+ else {
+ u32 = attributes_buffer + attributes_buffer_len - abuf;
+ check(hal_xdr_decode_buffer(&iptr, ilimit, abuf, &u32));
+ attributes[i].value = abuf;
+ attributes[i].length = u32;
+ abuf += u32;
}
}
}
@@ -795,41 +916,21 @@ static hal_error_t pkey_remote_list(hal_pkey_info_t *result,
}
#if RPC_CLIENT == RPC_CLIENT_MIXED
+
/*
* "Mixed" mode pkey operations, where the public key operation itself
* takes place on the HSM but the hashing takes place locally. If
* we're given a hash context in this case, it's local, so we have to
* pull the digest from the hash context and send that to the HSM.
- *
- * These methods are also responsible for dispatching pkey operations
- * to the local or remote key store based on the PROXIMATE flags.
- * These flags are only meaningful when operating in mixed mode.
*/
-static inline const hal_rpc_pkey_dispatch_t *mixed_flags_dispatch(const hal_key_flags_t flags)
-{
- if ((flags & HAL_KEY_FLAG_PROXIMATE) == 0)
- return &hal_rpc_remote_pkey_dispatch;
- else
- return &hal_rpc_local_pkey_dispatch;
-}
-
-static inline const hal_rpc_pkey_dispatch_t *mixed_handle_dispatch(const hal_pkey_handle_t pkey)
-{
- if ((pkey.handle & HAL_PKEY_HANDLE_PROXIMATE_FLAG) == 0)
- return &hal_rpc_remote_pkey_dispatch;
- else
- return &hal_rpc_local_pkey_dispatch;
-}
-
-static hal_error_t pkey_mixed_sign(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_mixed_sign(const hal_pkey_handle_t pkey,
const hal_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)
{
if (input != NULL)
- return mixed_handle_dispatch(pkey)->sign(session, pkey, hash, input, input_len,
+ return hal_rpc_remote_pkey_dispatch.sign(pkey, hash, input, input_len,
signature, signature_len, signature_max);
hal_digest_algorithm_t alg;
@@ -848,7 +949,7 @@ static hal_error_t pkey_mixed_sign(const hal_session_handle_t session,
case HAL_KEY_TYPE_RSA_PRIVATE:
case HAL_KEY_TYPE_RSA_PUBLIC:
- if ((err = hal_rpc_pkey_pkcs1_construct_digestinfo(hash, digest, &digest_len, sizeof(digest))) != HAL_OK)
+ if ((err = hal_rpc_pkcs1_construct_digestinfo(hash, digest, &digest_len, sizeof(digest))) != HAL_OK)
return err;
break;
@@ -858,18 +959,17 @@ static hal_error_t pkey_mixed_sign(const hal_session_handle_t session,
}
- return mixed_handle_dispatch(pkey)->sign(session, pkey, hal_hash_handle_none, digest, digest_len,
+ return hal_rpc_remote_pkey_dispatch.sign(pkey, hal_hash_handle_none, digest, digest_len,
signature, signature_len, signature_max);
}
-static hal_error_t pkey_mixed_verify(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_mixed_verify(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
const uint8_t * const input, const size_t input_len,
const uint8_t * const signature, const size_t signature_len)
{
if (input != NULL)
- return mixed_handle_dispatch(pkey)->verify(session, pkey, hash, input, input_len,
+ return hal_rpc_remote_pkey_dispatch.verify(pkey, hash, input, input_len,
signature, signature_len);
hal_digest_algorithm_t alg;
@@ -888,7 +988,7 @@ static hal_error_t pkey_mixed_verify(const hal_session_handle_t session,
case HAL_KEY_TYPE_RSA_PRIVATE:
case HAL_KEY_TYPE_RSA_PUBLIC:
- if ((err = hal_rpc_pkey_pkcs1_construct_digestinfo(hash, digest, &digest_len, sizeof(digest))) != HAL_OK)
+ if ((err = hal_rpc_pkcs1_construct_digestinfo(hash, digest, &digest_len, sizeof(digest))) != HAL_OK)
return err;
break;
@@ -898,103 +998,10 @@ static hal_error_t pkey_mixed_verify(const hal_session_handle_t session,
}
- return mixed_handle_dispatch(pkey)->verify(session, pkey, hal_hash_handle_none,
+ return hal_rpc_remote_pkey_dispatch.verify(pkey, hal_hash_handle_none,
digest, digest_len, signature, signature_len);
}
-static hal_error_t pkey_mixed_load(const hal_client_handle_t client,
- const hal_session_handle_t session,
- hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
- const uint8_t * const der, const size_t der_len,
- const hal_key_flags_t flags)
-{
- return mixed_flags_dispatch(flags)->load(client, session, pkey, type, curve,
- name, name_len, der, der_len, flags);
-}
-
-static hal_error_t pkey_mixed_find(const hal_client_handle_t client,
- const hal_session_handle_t session,
- hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
- const hal_key_flags_t flags)
-{
- return mixed_flags_dispatch(flags)->find(client, session, pkey, type,
- name, name_len, flags);
-}
-
-static hal_error_t pkey_mixed_generate_rsa(const hal_client_handle_t client,
- const hal_session_handle_t session,
- hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
- const unsigned key_length,
- const uint8_t * const public_exponent, const size_t public_exponent_len,
- const hal_key_flags_t flags)
-{
- return mixed_flags_dispatch(flags)->generate_rsa(client, session, pkey,
- name, name_len, key_length,
- public_exponent, public_exponent_len, flags);
-}
-
-static hal_error_t pkey_mixed_generate_ec(const hal_client_handle_t client,
- const hal_session_handle_t session,
- hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
- const hal_curve_name_t curve,
- const hal_key_flags_t flags)
-{
- return mixed_flags_dispatch(flags)->generate_ec(client, session, pkey, name, name_len, curve, flags);
-}
-
-static hal_error_t pkey_mixed_close(const hal_pkey_handle_t pkey)
-{
- return mixed_handle_dispatch(pkey)->close(pkey);
-}
-
-static hal_error_t pkey_mixed_delete(const hal_pkey_handle_t pkey)
-{
- return mixed_handle_dispatch(pkey)->delete(pkey);
-}
-
-static hal_error_t pkey_mixed_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
-{
- return mixed_handle_dispatch(pkey)->rename(pkey, name, name_len);
-}
-
-static hal_error_t pkey_mixed_get_key_type(const hal_pkey_handle_t pkey,
- hal_key_type_t *key_type)
-{
- return mixed_handle_dispatch(pkey)->get_key_type(pkey, key_type);
-}
-
-static hal_error_t pkey_mixed_get_key_flags(const hal_pkey_handle_t pkey,
- hal_key_flags_t *flags)
-{
- return mixed_handle_dispatch(pkey)->get_key_flags(pkey, flags);
-}
-
-static size_t pkey_mixed_get_public_key_len(const hal_pkey_handle_t pkey)
-{
- return mixed_handle_dispatch(pkey)->get_public_key_len(pkey);
-}
-
-static hal_error_t pkey_mixed_get_public_key(const hal_pkey_handle_t pkey,
- uint8_t *der, size_t *der_len, const size_t der_max)
-{
- return mixed_handle_dispatch(pkey)->get_public_key(pkey, der, der_len, der_max);
-}
-
-static hal_error_t pkey_mixed_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max,
- hal_key_flags_t flags)
-{
- return mixed_flags_dispatch(flags)->list(result, result_len, result_max, flags);
-}
#endif /* RPC_CLIENT == RPC_CLIENT_MIXED */
/*
@@ -1002,57 +1009,61 @@ static hal_error_t pkey_mixed_list(hal_pkey_info_t *result,
*/
const hal_rpc_misc_dispatch_t hal_rpc_remote_misc_dispatch = {
- set_pin,
- login,
- logout,
- logout_all,
- is_logged_in,
- get_random,
- get_version
+ .set_pin = set_pin,
+ .login = login,
+ .logout = logout,
+ .logout_all = logout_all,
+ .is_logged_in = is_logged_in,
+ .get_random = get_random,
+ .get_version = get_version
};
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
+ .get_digest_length = hash_get_digest_len,
+ .get_digest_algorithm_id = hash_get_digest_algorithm_id,
+ .get_algorithm = hash_get_algorithm,
+ .initialize = hash_initialize,
+ .update = hash_update,
+ .finalize = hash_finalize
};
const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
- pkey_remote_load,
- pkey_remote_find,
- pkey_remote_generate_rsa,
- pkey_remote_generate_ec,
- pkey_remote_close,
- pkey_remote_delete,
- pkey_remote_rename,
- pkey_remote_get_key_type,
- pkey_remote_get_key_flags,
- pkey_remote_get_public_key_len,
- pkey_remote_get_public_key,
- pkey_remote_sign,
- pkey_remote_verify,
- pkey_remote_list
+ .load = pkey_remote_load,
+ .open = pkey_remote_open,
+ .generate_rsa = pkey_remote_generate_rsa,
+ .generate_ec = pkey_remote_generate_ec,
+ .close = pkey_remote_close,
+ .delete = pkey_remote_delete,
+ .get_key_type = pkey_remote_get_key_type,
+ .get_key_curve = pkey_remote_get_key_curve,
+ .get_key_flags = pkey_remote_get_key_flags,
+ .get_public_key_len = pkey_remote_get_public_key_len,
+ .get_public_key = pkey_remote_get_public_key,
+ .sign = pkey_remote_sign,
+ .verify = pkey_remote_verify,
+ .match = pkey_remote_match,
+ .set_attributes = pkey_remote_set_attributes,
+ .get_attributes = pkey_remote_get_attributes
};
#if RPC_CLIENT == RPC_CLIENT_MIXED
const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
- pkey_mixed_load,
- pkey_mixed_find,
- pkey_mixed_generate_rsa,
- pkey_mixed_generate_ec,
- pkey_mixed_close,
- pkey_mixed_delete,
- pkey_mixed_rename,
- pkey_mixed_get_key_type,
- pkey_mixed_get_key_flags,
- pkey_mixed_get_public_key_len,
- pkey_mixed_get_public_key,
- pkey_mixed_sign,
- pkey_mixed_verify,
- pkey_mixed_list
+ .load = pkey_remote_load,
+ .open = pkey_remote_open,
+ .generate_rsa = pkey_remote_generate_rsa,
+ .generate_ec = pkey_remote_generate_ec,
+ .close = pkey_remote_close,
+ .delete = pkey_remote_delete,
+ .get_key_type = pkey_remote_get_key_type,
+ .get_key_curve = pkey_remote_get_key_curve,
+ .get_key_flags = pkey_remote_get_key_flags,
+ .get_public_key_len = pkey_remote_get_public_key_len,
+ .get_public_key = pkey_remote_get_public_key,
+ .sign = pkey_mixed_sign,
+ .verify = pkey_mixed_verify,
+ .match = pkey_remote_match,
+ .set_attributes = pkey_remote_set_attributes,
+ .get_attributes = pkey_remote_get_attributes
};
#endif /* RPC_CLIENT == RPC_CLIENT_MIXED */
diff --git a/rpc_hash.c b/rpc_hash.c
index 7cae484..0811e81 100644
--- a/rpc_hash.c
+++ b/rpc_hash.c
@@ -157,12 +157,12 @@ static inline void free_handle(handle_slot_t *slot)
static inline const hal_hash_descriptor_t *alg_to_descriptor(const hal_digest_algorithm_t alg)
{
switch (alg) {
- case hal_digest_algorithm_sha1: return hal_hash_sha1;
- case hal_digest_algorithm_sha256: return hal_hash_sha256;
- case hal_digest_algorithm_sha512_224: return hal_hash_sha512_224;
- case hal_digest_algorithm_sha512_256: return hal_hash_sha512_256;
- case hal_digest_algorithm_sha384: return hal_hash_sha384;
- case hal_digest_algorithm_sha512: return hal_hash_sha512;
+ case HAL_DIGEST_ALGORITHM_SHA1: return hal_hash_sha1;
+ case HAL_DIGEST_ALGORITHM_SHA256: return hal_hash_sha256;
+ case HAL_DIGEST_ALGORITHM_SHA512_224: return hal_hash_sha512_224;
+ case HAL_DIGEST_ALGORITHM_SHA512_256: return hal_hash_sha512_256;
+ case HAL_DIGEST_ALGORITHM_SHA384: return hal_hash_sha384;
+ case HAL_DIGEST_ALGORITHM_SHA512: return hal_hash_sha512;
default: return NULL;
}
}
@@ -303,12 +303,12 @@ static hal_error_t finalize(const hal_hash_handle_t handle,
}
const hal_rpc_hash_dispatch_t hal_rpc_local_hash_dispatch = {
- get_digest_length,
- get_digest_algorithm_id,
- get_algorithm,
- initialize,
- update,
- finalize
+ .get_digest_length = get_digest_length,
+ .get_digest_algorithm_id = get_digest_algorithm_id,
+ .get_algorithm = get_algorithm,
+ .initialize = initialize,
+ .update = update,
+ .finalize = finalize
};
/*
diff --git a/rpc_misc.c b/rpc_misc.c
index 1902b71..d6fc71d 100644
--- a/rpc_misc.c
+++ b/rpc_misc.c
@@ -133,7 +133,7 @@ static hal_error_t login(const hal_client_handle_t client,
const hal_ks_pin_t *p;
hal_error_t err;
- if ((err = hal_ks_get_pin(user, &p)) != HAL_OK)
+ if ((err = hal_get_pin(user, &p)) != HAL_OK)
return err;
uint8_t buf[sizeof(p->pin)];
@@ -207,7 +207,7 @@ static hal_error_t set_pin(const hal_client_handle_t client,
const hal_ks_pin_t *pp;
hal_error_t err;
- if ((err = hal_ks_get_pin(user, &pp)) != HAL_OK)
+ if ((err = hal_get_pin(user, &pp)) != HAL_OK)
return err;
hal_ks_pin_t p = *pp;
@@ -219,7 +219,7 @@ static hal_error_t set_pin(const hal_client_handle_t client,
(const uint8_t *) newpin, newpin_len,
p.salt, sizeof(p.salt),
p.pin, sizeof(p.pin), p.iterations)) != HAL_OK ||
- (err = hal_ks_set_pin(user, &p)) != HAL_OK)
+ (err = hal_set_pin(user, &p)) != HAL_OK)
return err;
return HAL_OK;
@@ -238,13 +238,13 @@ hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client,
}
const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch = {
- set_pin,
- login,
- logout,
- logout_all,
- is_logged_in,
- get_random,
- get_version
+ .set_pin = set_pin,
+ .login = login,
+ .logout = logout,
+ .logout_all = logout_all,
+ .is_logged_in = is_logged_in,
+ .get_random = get_random,
+ .get_version = get_version
};
/*
diff --git a/masterkey.h b/rpc_pkcs1.c
index 1d5e7a5..2dcf9dd 100644
--- a/masterkey.h
+++ b/rpc_pkcs1.c
@@ -1,7 +1,7 @@
/*
- * masterkey.h
+ * rpc_pkcs1.c
* -----------
- * Code to handle the Master Key that wraps all the keys in the keystore.
+ * PKCS #1 (RSA) support code layered on top of RPC hash API.
*
* Copyright (c) 2016, NORDUnet A/S All rights reserved.
*
@@ -32,15 +32,51 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __STM32_HSM_MASTERKEY_H
-#define __STM32_HSM_MASTERKEY_H
+#include <assert.h>
-extern hal_error_t masterkey_volatile_read(uint8_t *buf, size_t len);
-extern hal_error_t masterkey_volatile_write(uint8_t *buf, size_t len);
-extern hal_error_t masterkey_volatile_erase(size_t len);
+#include "hal.h"
+#include "hal_internal.h"
-extern hal_error_t masterkey_flash_read(uint8_t *buf, size_t len);
-extern hal_error_t masterkey_flash_write(uint8_t *buf, size_t len);
-extern hal_error_t masterkey_flash_erase(size_t len);
+/*
+ * Construct a PKCS #1 DigestInfo object. This requires some (very
+ * basic) ASN.1 encoding, which we perform inline.
+ */
+
+hal_error_t hal_rpc_pkcs1_construct_digestinfo(const hal_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);
-#endif /* __STM32_HSM_MASTERKEY_H */
+ return hal_rpc_hash_finalize(handle, d, len);
+}
diff --git a/rpc_pkey.c b/rpc_pkey.c
index d6efbe7..e2e42c9 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -39,35 +39,12 @@
#include "hal.h"
#include "hal_internal.h"
-typedef struct {
- hal_client_handle_t client_handle;
- hal_session_handle_t session_handle;
- hal_pkey_handle_t pkey_handle;
- hal_key_type_t type;
- hal_curve_name_t curve;
- hal_key_flags_t flags;
- uint8_t name[HAL_RPC_PKEY_NAME_MAX];
- size_t name_len;
- int ks_hint;
- /*
- * This might be where we'd stash a (hal_core_t *) pointing to a
- * core which has already been loaded with the key, if we were
- * trying to be clever about using multiple signing cores. Moot
- * point (ie, no way we could possibly test such a thing) as long as
- * the FPGA is too small to hold more than one modexp core and ECDSA
- * is entirely software, so skip it for now, but the implied
- * semantics are interesting: a pkey handle starts to resemble an
- * initialized signing core, and once all the cores are in use, one
- * can't load another key without closing an existing pkey handle.
- */
-} pkey_slot_t;
-
#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
#define HAL_STATIC_PKEY_STATE_BLOCKS 0
#endif
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
-static pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
+static hal_pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
#endif
/*
@@ -78,27 +55,28 @@ static pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS];
* soon, to help identify use-after-free bugs in calling code.
*
* The high order bit of the pkey handle is left free for
- * HAL_PKEY_HANDLE_PROXIMATE_FLAG, which is used by the mixed-mode
+ * HAL_PKEY_HANDLE_TOKEN_FLAG, which is used by the mixed-mode
* handlers to route calls to the appropriate destination.
*/
-static inline pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
+static inline hal_pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
{
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
static uint16_t next_glop = 0;
uint32_t glop = ++next_glop << 16;
next_glop %= 0x7FFF;
- assert((glop & HAL_PKEY_HANDLE_PROXIMATE_FLAG) == 0);
+ assert((glop & HAL_PKEY_HANDLE_TOKEN_FLAG) == 0);
- if ((flags & HAL_KEY_FLAG_PROXIMATE) != 0)
- glop |= HAL_PKEY_HANDLE_PROXIMATE_FLAG;
+ if ((flags & HAL_KEY_FLAG_TOKEN) != 0)
+ glop |= HAL_PKEY_HANDLE_TOKEN_FLAG;
for (int i = 0; i < sizeof(pkey_handle)/sizeof(*pkey_handle); i++) {
if (pkey_handle[i].type != HAL_KEY_TYPE_NONE)
continue;
+ memset(&pkey_handle[i], 0, sizeof(pkey_handle[i]));
pkey_handle[i].pkey_handle.handle = i | glop;
- pkey_handle[i].ks_hint = -1;
+ pkey_handle[i].hint = -1;
return &pkey_handle[i];
}
#endif
@@ -111,7 +89,7 @@ static inline pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
* the right glop. Returns slot pointer on success, NULL otherwise.
*/
-static inline pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
+static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
{
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
const int i = (int) (handle.handle & 0xFFFF);
@@ -123,61 +101,67 @@ static inline pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
return NULL;
}
-#warning Still need access control on pkey objects based on current login state
/*
- * This would be simple, except for PKCS #11 non-token objects (CKA_TOKEN = CK_FALSE).
- * Need to check detailed PKCS #11 rules, but, from memory, we may be supposed to allow
- * access to non-token objects even when not logged in. Maybe. Rules are complex.
+ * Access rules are a bit complicated, mostly due to PKCS #11.
*
- * I think the libhal translation of this resolves around what we've
- * been calling the PROXIMATE flags (which probably ought to be
- * renamed to *_NONTOKEN_*, slightly less confusing name). For token
- * objects, we insist on being logged in properly; for non-token
- * objects, we do whatever silly thing PKCS #11 wants us to do,
- * probably defaulting to requiring login if PKCS #11 gives us a choice.
- */
-
-/*
- * Construct a PKCS #1 DigestInfo object. This requires some (very
- * basic) ASN.1 encoding, which we perform inline.
+ * The simple, obvious rule would be that one must be logged in as
+ * HAL_USER_NORMAL to create, see, use, or delete a key, full stop.
+ *
+ * That's almost the rule that PKCS #11 follows for so-called
+ * "private" objects (CKA_PRIVATE = CK_TRUE), but PKCS #11 has a more
+ * model which not only allows wider visibility to "public" objects
+ * (CKA_PRIVATE = CK_FALSE) but also allows write access to "public
+ * session" (CKA_PRIVATE = CK_FALSE, CKA_TOKEN = CK_FALSE) objects
+ * regardless of login state.
+ *
+ * PKCS #11 also has a concept of read-only sessions, which we don't
+ * bother to implement at all on the HSM, since the PIN is required to
+ * be the same as for the corresponding read-write session, so this
+ * would just be additional compexity without adding any security on
+ * the HSM; the PKCS #11 library still has to support read-only
+ * sessions, but that's not our problem here.
+ *
+ * In general, non-PKCS #11 users of this API should probably never
+ * set HAL_KEY_FLAG_PUBLIC, in which case they'll get the simple rule.
+ *
+ * Note that keystore drivers may need to implement additional
+ * additional checks, eg, ks_volatile needs to enforce the rule that
+ * session objects are only visible to the client which created them
+ * (not the session, that would be too simple, thanks PKCS #11). In
+ * practice, this should not be a serious problem, since such checks
+ * will likely only apply to existing objects. The thing we really
+ * want to avoid is doing all the work to create a large key only to
+ * have the keystore driver reject access at the end, but since, by
+ * definition, that only occurs when creating new objects, the access
+ * decision doesn't depend on preexisting data, so the rules here
+ * should suffice. That's the theory, anyway, if this is wrong we may
+ * need to refactor.
*/
-hal_error_t hal_rpc_pkey_pkcs1_construct_digestinfo(const hal_hash_handle_t handle,
- uint8_t *digest_info, size_t *digest_info_len, const size_t digest_info_max)
+static inline hal_error_t check_normal_or_wheel(const hal_client_handle_t client)
{
- 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);
+ const hal_error_t err = hal_rpc_is_logged_in(client, HAL_USER_NORMAL);
+ return (err == HAL_ERROR_FORBIDDEN
+ ? hal_rpc_is_logged_in(client, HAL_USER_WHEEL)
+ : err);
+}
- if ((err = hal_rpc_hash_get_digest_algorithm_id(alg, d, NULL, alg_len)) != HAL_OK)
- return err;
- d += alg_len;
+static inline hal_error_t check_readable(const hal_client_handle_t client,
+ const hal_key_flags_t flags)
+{
+ if ((flags & HAL_KEY_FLAG_PUBLIC) != 0)
+ return HAL_OK;
- *d++ = 0x04; /* OCTET STRING */
- *d++ = (uint8_t) len;
+ return check_normal_or_wheel(client);
+}
- assert(digest_info + *digest_info_len == d + len);
+static inline hal_error_t check_writable(const hal_client_handle_t client,
+ const hal_key_flags_t flags)
+{
+ if ((flags & (HAL_KEY_FLAG_TOKEN | HAL_KEY_FLAG_PUBLIC)) == HAL_KEY_FLAG_PUBLIC)
+ return HAL_OK;
- return hal_rpc_hash_finalize(handle, d, len);
+ return check_normal_or_wheel(client);
}
/*
@@ -223,6 +207,18 @@ static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len
}
/*
+ * Given key flags, open appropriate keystore driver.
+ */
+
+static inline hal_error_t ks_open_from_flags(hal_ks_t **ks, const hal_key_flags_t flags)
+{
+ return hal_ks_open((flags & HAL_KEY_FLAG_TOKEN) == 0
+ ? hal_ks_volatile_driver
+ : hal_ks_token_driver,
+ ks);
+}
+
+/*
* Receive key from application, store it with supplied name, return a key handle.
*/
@@ -231,30 +227,44 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
hal_pkey_handle_t *pkey,
const hal_key_type_t type,
const hal_curve_name_t curve,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
+ assert(pkey != NULL && name != NULL);
+
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ if ((err = check_writable(client, flags)) != HAL_OK)
+ return err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- if ((err = hal_ks_store(type, curve, flags, name, name_len, der, der_len, &slot->ks_hint)) != HAL_OK)
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
return err;
- memcpy(slot->name, name, name_len);
- slot->client_handle = client;
+ slot->client_handle = client;
slot->session_handle = session;
- slot->type = type;
+ slot->type = type;
slot->curve = curve;
slot->flags = flags;
- slot->name_len = name_len;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
+ return err;
+ }
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -262,29 +272,38 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
* Look up a key given its name, return a key handle.
*/
-static hal_error_t pkey_local_find(const hal_client_handle_t client,
+static hal_error_t pkey_local_open(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const uint8_t * const name, const size_t name_len,
+ const hal_uuid_t * const name,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
+ assert(pkey != NULL && name != NULL);
+
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ if ((err = check_readable(client, flags)) != HAL_OK)
+ return err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- if ((err = hal_ks_fetch(type, name, name_len, &slot->curve, &slot->flags, NULL, NULL, 0, &slot->ks_hint)) != HAL_OK)
- return err;
-
- memcpy(slot->name, name, name_len);
+ slot->name = *name;
slot->client_handle = client;
slot->session_handle = session;
- slot->type = type;
- slot->name_len = name_len;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, NULL, NULL, 0)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
+ return err;
+ }
*pkey = slot->pkey_handle;
return HAL_OK;
@@ -297,48 +316,60 @@ static hal_error_t pkey_local_find(const hal_client_handle_t client,
static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const unsigned key_length,
const uint8_t * const public_exponent, const size_t public_exponent_len,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
+ assert(pkey != NULL && name != NULL && (key_length & 7) == 0);
+
+ uint8_t keybuf[hal_rsa_key_t_size];
+ hal_rsa_key_t *key = NULL;
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- assert(sizeof(slot->name) >= name_len && pkey != NULL && (key_length & 7) == 0);
+ if ((err = check_writable(client, flags)) != HAL_OK)
+ return err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- uint8_t keybuf[hal_rsa_key_t_size];
- hal_rsa_key_t *key = NULL;
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
+ return err;
+
+ slot->client_handle = client;
+ slot->session_handle = session;
+ slot->type = HAL_KEY_TYPE_RSA_PRIVATE;
+ slot->curve = HAL_CURVE_NONE;
+ slot->flags = flags;
if ((err = hal_rsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), key_length / 8,
- public_exponent, public_exponent_len)) != HAL_OK)
+ public_exponent, public_exponent_len)) != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
return err;
+ }
uint8_t der[hal_rsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_store(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, flags,
- name, name_len, der, der_len, &slot->ks_hint);
+ if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
+ (err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
- if (err != HAL_OK)
+ if (err != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
return err;
-
- memcpy(slot->name, name, name_len);
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = HAL_KEY_TYPE_RSA_PRIVATE;
- slot->curve = HAL_CURVE_NONE;
- slot->flags = flags;
- slot->name_len = name_len;
+ }
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -350,46 +381,58 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const uint8_t * const name, const size_t name_len,
+ hal_uuid_t *name,
const hal_curve_name_t curve,
const hal_key_flags_t flags)
{
- pkey_slot_t *slot;
+ assert(pkey != NULL && name != NULL);
+
+ uint8_t keybuf[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *key = NULL;
+ hal_pkey_slot_t *slot;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- assert(sizeof(slot->name) >= name_len && pkey != NULL);
+ if ((err = check_writable(client, flags)) != HAL_OK)
+ return err;
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- uint8_t keybuf[hal_ecdsa_key_t_size];
- hal_ecdsa_key_t *key = NULL;
+ if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
+ return err;
- if ((err = hal_ecdsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), curve)) != HAL_OK)
+ slot->client_handle = client;
+ slot->session_handle = session;
+ slot->type = HAL_KEY_TYPE_EC_PRIVATE;
+ slot->curve = curve;
+ slot->flags = flags;
+
+ if ((err = hal_ecdsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), curve)) != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
return err;
+ }
uint8_t der[hal_ecdsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_store(HAL_KEY_TYPE_EC_PRIVATE, curve, flags,
- name, name_len, der, der_len, &slot->ks_hint);
+ if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
+ (err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_store(ks, slot, der, der_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
- if (err != HAL_OK)
+ if (err != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
return err;
-
- memcpy(slot->name, name, name_len);
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = HAL_KEY_TYPE_EC_PRIVATE;
- slot->curve = curve;
- slot->flags = flags;
- slot->name_len = name_len;
+ }
*pkey = slot->pkey_handle;
+ *name = slot->name;
return HAL_OK;
}
@@ -399,7 +442,7 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
static hal_error_t pkey_local_close(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot;
+ hal_pkey_slot_t *slot;
if ((slot = find_handle(pkey)) == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -415,12 +458,22 @@ static hal_error_t pkey_local_close(const hal_pkey_handle_t pkey)
static hal_error_t pkey_local_delete(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- hal_error_t err = hal_ks_delete(slot->type, slot->name, slot->name_len, &slot->ks_hint);
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = check_writable(slot->client_handle, slot->flags)) != HAL_OK)
+ return err;
+
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_delete(ks, slot)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK || err == HAL_ERROR_KEY_NOT_FOUND)
memset(slot, 0, sizeof(*slot));
@@ -429,45 +482,41 @@ static hal_error_t pkey_local_delete(const hal_pkey_handle_t pkey)
}
/*
- * Rename a key in the key store, given its key handle and a new name.
+ * Get type of key associated with handle.
*/
-static hal_error_t pkey_local_rename(const hal_pkey_handle_t pkey,
- const uint8_t * const name, const size_t name_len)
+static hal_error_t pkey_local_get_key_type(const hal_pkey_handle_t pkey,
+ hal_key_type_t *type)
{
- pkey_slot_t *slot = find_handle(pkey);
+ if (type == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- hal_error_t err = hal_ks_rename(slot->type, slot->name, slot->name_len, name, name_len, &slot->ks_hint);
-
- if (err == HAL_OK) {
- assert(name_len <= sizeof(slot->name));
- memcpy(slot->name, name, name_len);
- memset(slot->name + name_len, 0, sizeof(slot->name) - name_len);
- slot->name_len = name_len;
- }
+ *type = slot->type;
- return err;
+ return HAL_OK;
}
/*
- * Get type of key associated with handle.
+ * Get curve of key associated with handle.
*/
-static hal_error_t pkey_local_get_key_type(const hal_pkey_handle_t pkey,
- hal_key_type_t *type)
+static hal_error_t pkey_local_get_key_curve(const hal_pkey_handle_t pkey,
+ hal_curve_name_t *curve)
{
- if (type == NULL)
+ if (curve == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- *type = slot->type;
+ *curve = slot->curve;
return HAL_OK;
}
@@ -482,7 +531,7 @@ static hal_error_t pkey_local_get_key_flags(const hal_pkey_handle_t pkey,
if (flags == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -498,7 +547,7 @@ static hal_error_t pkey_local_get_key_flags(const hal_pkey_handle_t pkey,
static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return 0;
@@ -510,9 +559,16 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
- if (hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL,
- der, &der_len, sizeof(der), &slot->ks_hint) == HAL_OK) {
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -548,7 +604,7 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
uint8_t *der, size_t *der_len, const size_t der_max)
{
- pkey_slot_t *slot = find_handle(pkey);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -558,10 +614,16 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t buf[HAL_KS_WRAPPED_KEYSIZE];
size_t buf_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL,
- buf, &buf_len, sizeof(buf), &slot->ks_hint)) == HAL_OK) {
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, buf, &buf_len, sizeof(buf))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -622,8 +684,8 @@ static hal_error_t pkey_local_sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
if (*signature_len > signature_max)
return HAL_ERROR_RESULT_TOO_LONG;
- if (input == NULL) {
- if ((err = hal_rpc_pkey_pkcs1_construct_digestinfo(hash, signature, &input_len, *signature_len)) != HAL_OK)
+ if (input == NULL || input_len == 0) {
+ if ((err = hal_rpc_pkcs1_construct_digestinfo(hash, signature, &input_len, *signature_len)) != HAL_OK)
return err;
input = signature;
}
@@ -650,7 +712,7 @@ static hal_error_t pkey_local_sign_ecdsa(uint8_t *keybuf, const size_t keybuf_le
if ((err = hal_ecdsa_private_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
return err;
- if (input == NULL) {
+ if (input == NULL || input_len == 0) {
hal_digest_algorithm_t alg;
if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK ||
@@ -672,13 +734,12 @@ static hal_error_t pkey_local_sign_ecdsa(uint8_t *keybuf, const size_t keybuf_le
return HAL_OK;
}
-static hal_error_t pkey_local_sign(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey,
const hal_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);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -703,9 +764,14 @@ static hal_error_t pkey_local_sign(const hal_session_handle_t session,
uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint);
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK)
err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len, signature_max);
@@ -750,8 +816,8 @@ static hal_error_t pkey_local_verify_rsa(uint8_t *keybuf, const size_t keybuf_le
if (err != HAL_OK)
return err;
- if (input == NULL) {
- if ((err = hal_rpc_pkey_pkcs1_construct_digestinfo(hash, expected, &input_len, sizeof(expected))) != HAL_OK)
+ if (input == NULL || input_len == 0) {
+ if ((err = hal_rpc_pkcs1_construct_digestinfo(hash, expected, &input_len, sizeof(expected))) != HAL_OK)
return err;
input = expected;
}
@@ -797,7 +863,7 @@ static hal_error_t pkey_local_verify_ecdsa(uint8_t *keybuf, const size_t keybuf_
if (err != HAL_OK)
return err;
- if (input == NULL) {
+ if (input == NULL || input_len == 0) {
hal_digest_algorithm_t alg;
if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK ||
@@ -814,13 +880,12 @@ static hal_error_t pkey_local_verify_ecdsa(uint8_t *keybuf, const size_t keybuf_
return HAL_OK;
}
-static hal_error_t pkey_local_verify(const hal_session_handle_t session,
- const hal_pkey_handle_t pkey,
+static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey,
const hal_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);
+ hal_pkey_slot_t *slot = find_handle(pkey);
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
@@ -847,9 +912,14 @@ static hal_error_t pkey_local_verify(const hal_session_handle_t session,
uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
+ hal_ks_t *ks = NULL;
hal_error_t err;
- err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint);
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
if (err == HAL_OK)
err = verifier(keybuf, sizeof(keybuf), slot->type, der, der_len, hash, input, input_len, signature, signature_len);
@@ -860,34 +930,107 @@ static hal_error_t pkey_local_verify(const hal_session_handle_t session,
return err;
}
+static hal_error_t pkey_local_match(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
+{
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
-/*
- * List keys in the key store.
- */
+ err = check_readable(client, flags);
+
+ if (err == HAL_ERROR_FORBIDDEN) {
+ assert(result_len != NULL);
+ *result_len = 0;
+ return HAL_OK;
+ }
+
+ if (err != HAL_OK)
+ return err;
+
+ if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+ (err = hal_ks_match(ks, client, session, type, curve, flags, attributes, attributes_len,
+ result, result_len, result_max, previous_uuid)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ return err;
+}
+
+static hal_error_t pkey_local_set_attributes(const hal_pkey_handle_t pkey,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len)
+{
+ hal_pkey_slot_t *slot = find_handle(pkey);
+
+ if (slot == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = check_writable(slot->client_handle, slot->flags)) != HAL_OK)
+ return err;
+
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_set_attributes(ks, slot, attributes, attributes_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ return err;
+}
-static hal_error_t pkey_local_list(hal_pkey_info_t *result,
- unsigned *result_len,
- const unsigned result_max,
- hal_key_flags_t flags)
+static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t pkey,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len)
{
- return hal_ks_list(result, result_len, result_max);
+ hal_pkey_slot_t *slot = find_handle(pkey);
+
+ if (slot == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+ (err = hal_ks_get_attributes(ks, slot, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ return err;
}
const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
- pkey_local_load,
- pkey_local_find,
- pkey_local_generate_rsa,
- pkey_local_generate_ec,
- pkey_local_close,
- pkey_local_delete,
- pkey_local_rename,
- pkey_local_get_key_type,
- pkey_local_get_key_flags,
- pkey_local_get_public_key_len,
- pkey_local_get_public_key,
- pkey_local_sign,
- pkey_local_verify,
- pkey_local_list
+ .load = pkey_local_load,
+ .open = pkey_local_open,
+ .generate_rsa = pkey_local_generate_rsa,
+ .generate_ec = pkey_local_generate_ec,
+ .close = pkey_local_close,
+ .delete = pkey_local_delete,
+ .get_key_type = pkey_local_get_key_type,
+ .get_key_curve = pkey_local_get_key_curve,
+ .get_key_flags = pkey_local_get_key_flags,
+ .get_public_key_len = pkey_local_get_public_key_len,
+ .get_public_key = pkey_local_get_public_key,
+ .sign = pkey_local_sign,
+ .verify = pkey_local_verify,
+ .match = pkey_local_match,
+ .set_attributes = pkey_local_set_attributes,
+ .get_attributes = pkey_local_get_attributes
};
/*
diff --git a/rpc_server.c b/rpc_server.c
index a0de42d..a21679a 100644
--- a/rpc_server.c
+++ b/rpc_server.c
@@ -44,6 +44,8 @@
#define pad(n) (((n) + 3) & ~3)
+#define nargs(n) ((n) * 4)
+
static hal_error_t get_version(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
@@ -54,7 +56,8 @@ static hal_error_t get_version(const uint8_t **iptr, const uint8_t * const ilimi
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.get_version(&version);
+ ret = hal_rpc_get_version(&version);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, version));
@@ -77,7 +80,7 @@ static hal_error_t get_random(const uint8_t **iptr, const uint8_t * const ilimit
/* call the local function */
/* get the data directly into the output buffer */
check(hal_xdr_encode_int(optr, olimit, length));
- ret = hal_rpc_local_misc_dispatch.get_random(*optr, (size_t)length);
+ ret = hal_rpc_get_random(*optr, (size_t)length);
if (ret == HAL_OK)
*optr += pad(length);
else
@@ -101,7 +104,8 @@ static hal_error_t set_pin(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.set_pin(client, user, (const char * const)pin, pin_len);
+ ret = hal_rpc_set_pin(client, user, (const char * const)pin, pin_len);
+
return ret;
}
@@ -119,7 +123,8 @@ static hal_error_t login(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.login(client, user, (const char * const)pin, pin_len);
+ ret = hal_rpc_login(client, user, (const char * const)pin, pin_len);
+
return ret;
}
@@ -132,7 +137,8 @@ static hal_error_t logout(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.logout(client);
+ ret = hal_rpc_logout(client);
+
return ret;
}
@@ -145,7 +151,8 @@ static hal_error_t logout_all(const uint8_t **iptr, const uint8_t * const ilimit
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.logout_all();
+ ret = hal_rpc_logout_all();
+
return ret;
}
@@ -160,7 +167,8 @@ static hal_error_t is_logged_in(const uint8_t **iptr, const uint8_t * const ilim
check(hal_xdr_decode_int(iptr, ilimit, &user));
/* call the local function */
- ret = hal_rpc_local_misc_dispatch.is_logged_in(client, user);
+ ret = hal_rpc_is_logged_in(client, user);
+
return ret;
}
@@ -176,9 +184,11 @@ static hal_error_t hash_get_digest_len(const uint8_t **iptr, const uint8_t * con
check(hal_xdr_decode_int(iptr, ilimit, &alg));
/* call the local function */
- ret = hal_rpc_local_hash_dispatch.get_digest_length(alg, &length);
+ ret = hal_rpc_hash_get_digest_length(alg, &length);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, length));
+
return ret;
}
@@ -202,7 +212,7 @@ static hal_error_t hash_get_digest_algorithm_id(const uint8_t **iptr, const uint
/* call the local function */
/* get the data directly into the output buffer */
*optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_local_hash_dispatch.get_digest_algorithm_id(alg, *optr, &len, (size_t)len_max);
+ ret = hal_rpc_hash_get_digest_algorithm_id(alg, *optr, &len, (size_t)len_max);
if (ret == HAL_OK) {
*optr = optr_orig;
check(hal_xdr_encode_int(optr, olimit, len));
@@ -227,9 +237,11 @@ static hal_error_t hash_get_algorithm(const uint8_t **iptr, const uint8_t * cons
check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
/* call the local function */
- ret = hal_rpc_local_hash_dispatch.get_algorithm(hash, &alg);
+ ret = hal_rpc_hash_get_algorithm(hash, &alg);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, alg));
+
return ret;
}
@@ -250,9 +262,11 @@ static hal_error_t hash_initialize(const uint8_t **iptr, const uint8_t * const i
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &key, &key_len));
/* call the local function */
- ret = hal_rpc_local_hash_dispatch.initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len);
+ ret = hal_rpc_hash_initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, hash.handle));
+
return ret;
}
@@ -270,7 +284,8 @@ static hal_error_t hash_update(const uint8_t **iptr, const uint8_t * const ilimi
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &data, &length));
/* call the local function */
- ret = hal_rpc_local_hash_dispatch.update(hash, data, (size_t)length);
+ ret = hal_rpc_hash_update(hash, data, (size_t)length);
+
return ret;
}
@@ -292,7 +307,7 @@ static hal_error_t hash_finalize(const uint8_t **iptr, const uint8_t * const ili
/* call the local function */
/* get the data directly into the output buffer */
check(hal_xdr_encode_int(optr, olimit, length));
- ret = hal_rpc_local_hash_dispatch.finalize(hash, *optr, (size_t)length);
+ ret = hal_rpc_hash_finalize(hash, *optr, (size_t)length);
if (ret == HAL_OK)
*optr += pad(length);
else
@@ -309,8 +324,9 @@ static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
hal_pkey_handle_t pkey;
uint32_t type;
uint32_t curve;
- const uint8_t *name, *der;
- uint32_t name_len, der_len;
+ hal_uuid_t name;
+ const uint8_t *der;
+ uint32_t der_len;
hal_key_flags_t flags;
hal_error_t ret;
@@ -318,39 +334,47 @@ static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
check(hal_xdr_decode_int(iptr, ilimit, &type));
check(hal_xdr_decode_int(iptr, ilimit, &curve));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &der, &der_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.load(client, session, &pkey, type, curve, name, name_len, der, der_len, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_pkey_load(client, session, &pkey, type, curve, &name, der, der_len, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
-static hal_error_t pkey_find(const uint8_t **iptr, const uint8_t * const ilimit,
+static hal_error_t pkey_open(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
hal_client_handle_t client;
hal_session_handle_t session;
hal_pkey_handle_t pkey;
- uint32_t type;
- const uint8_t *name;
+ const uint8_t *name_ptr;
uint32_t name_len;
hal_key_flags_t flags;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &type));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
+ check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name_ptr, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
+ if (name_len != sizeof(hal_uuid_t))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.find(client, session, &pkey, type, name, name_len, flags);
+ ret = hal_rpc_pkey_open(client, session, &pkey, (const hal_uuid_t *) name_ptr, flags);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+
return ret;
}
@@ -360,8 +384,7 @@ static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const
hal_client_handle_t client;
hal_session_handle_t session;
hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
+ hal_uuid_t name;
uint32_t key_len;
const uint8_t *exp;
uint32_t exp_len;
@@ -370,15 +393,20 @@ static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &key_len));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.generate_rsa(client, session, &pkey, name, name_len, key_len, exp, exp_len, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_pkey_generate_rsa(client, session, &pkey, &name, key_len, exp, exp_len, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
@@ -388,22 +416,26 @@ static hal_error_t pkey_generate_ec(const uint8_t **iptr, const uint8_t * const
hal_client_handle_t client;
hal_session_handle_t session;
hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
+ hal_uuid_t name;
uint32_t curve;
hal_key_flags_t flags;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
check(hal_xdr_decode_int(iptr, ilimit, &curve));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.generate_ec(client, session, &pkey, name, name_len, curve, flags);
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
+ ret = hal_rpc_pkey_generate_ec(client, session, &pkey, &name, curve, flags);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ if ((ret = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
@@ -418,7 +450,8 @@ static hal_error_t pkey_close(const uint8_t **iptr, const uint8_t * const ilimit
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.close(pkey);
+ ret = hal_rpc_pkey_close(pkey);
+
return ret;
}
@@ -433,43 +466,48 @@ static hal_error_t pkey_delete(const uint8_t **iptr, const uint8_t * const ilimi
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.delete(pkey);
+ ret = hal_rpc_pkey_delete(pkey);
+
return ret;
}
-static hal_error_t pkey_rename(const uint8_t **iptr, const uint8_t * const ilimit,
- uint8_t **optr, const uint8_t * const olimit)
+static hal_error_t pkey_get_key_type(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
{
hal_client_handle_t client __attribute__((unused));
hal_pkey_handle_t pkey;
- const uint8_t *name;
- uint32_t name_len;
+ hal_key_type_t type;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.rename(pkey, name, name_len);
+ ret = hal_rpc_pkey_get_key_type(pkey, &type);
+
+ if (ret == HAL_OK)
+ check(hal_xdr_encode_int(optr, olimit, type));
+
return ret;
}
-static hal_error_t pkey_get_key_type(const uint8_t **iptr, const uint8_t * const ilimit,
+static hal_error_t pkey_get_key_curve(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
+ hal_client_handle_t client;
hal_pkey_handle_t pkey;
- hal_key_type_t type;
+ hal_curve_name_t curve;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.get_key_type(pkey, &type);
+ ret = hal_rpc_pkey_get_key_curve(pkey, &curve);
+
if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, type));
+ check(hal_xdr_encode_int(optr, olimit, curve));
+
return ret;
}
@@ -485,9 +523,11 @@ static hal_error_t pkey_get_key_flags(const uint8_t **iptr, const uint8_t * cons
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.get_key_flags(pkey, &flags);
+ ret = hal_rpc_pkey_get_key_flags(pkey, &flags);
+
if (ret == HAL_OK)
check(hal_xdr_encode_int(optr, olimit, flags));
+
return ret;
}
@@ -502,8 +542,10 @@ static hal_error_t pkey_get_public_key_len(const uint8_t **iptr, const uint8_t *
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
/* call the local function */
- len = hal_rpc_local_pkey_dispatch.get_public_key_len(pkey);
+ len = hal_rpc_pkey_get_public_key_len(pkey);
+
check(hal_xdr_encode_int(optr, olimit, len));
+
return HAL_OK;
}
@@ -527,7 +569,7 @@ static hal_error_t pkey_get_public_key(const uint8_t **iptr, const uint8_t * con
/* call the local function */
/* get the data directly into the output buffer */
*optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_local_pkey_dispatch.get_public_key(pkey, *optr, &len, len_max);
+ ret = hal_rpc_pkey_get_public_key(pkey, *optr, &len, len_max);
if (ret == HAL_OK) {
*optr = optr_orig;
check(hal_xdr_encode_int(optr, olimit, len));
@@ -540,11 +582,10 @@ static hal_error_t pkey_get_public_key(const uint8_t **iptr, const uint8_t * con
return ret;
}
-static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const ilimit,
- uint8_t **optr, const uint8_t * const olimit)
+static hal_error_t pkey_sign(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
- hal_session_handle_t session;
+ hal_client_handle_t client;
hal_pkey_handle_t pkey;
hal_hash_handle_t hash;
const uint8_t *input;
@@ -555,7 +596,6 @@ static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
@@ -567,7 +607,7 @@ static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const
/* call the local function */
/* get the data directly into the output buffer */
*optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_local_pkey_dispatch.sign(session, pkey, hash, input, input_len, *optr, &sig_len, sig_max);
+ ret = hal_rpc_pkey_sign(pkey, hash, input, input_len, *optr, &sig_len, sig_max);
*optr = optr_orig;
if (ret == HAL_OK) {
check(hal_xdr_encode_int(optr, olimit, sig_len));
@@ -576,11 +616,10 @@ static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const
return ret;
}
-static hal_error_t pkey_remote_verify(const uint8_t **iptr, const uint8_t * const ilimit,
- uint8_t **optr, const uint8_t * const olimit)
+static hal_error_t pkey_verify(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
- hal_session_handle_t session;
+ hal_client_handle_t client;
hal_pkey_handle_t pkey;
hal_hash_handle_t hash;
const uint8_t *input;
@@ -590,62 +629,160 @@ static hal_error_t pkey_remote_verify(const uint8_t **iptr, const uint8_t * cons
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &sig, &sig_len));
/* call the local function */
- ret = hal_rpc_local_pkey_dispatch.verify(session, pkey, hash, input, input_len, sig, sig_len);
+ ret = hal_rpc_pkey_verify(pkey, hash, input, input_len, sig, sig_len);
+
return ret;
}
-static hal_error_t hal_xdr_encode_pkey_info(uint8_t **optr, const uint8_t * const olimit, const hal_pkey_info_t *info)
+static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
{
- uint8_t *optr_orig = *optr;
+ hal_client_handle_t client;
+ hal_session_handle_t session;
+ uint32_t type, curve, attributes_len, result_max, previous_uuid_len;
+ const uint8_t *previous_uuid_ptr;
+ hal_key_flags_t flags;
hal_error_t ret;
- if ((ret = hal_xdr_encode_int(optr, olimit, info->type)) != HAL_OK ||
- (ret = hal_xdr_encode_int(optr, olimit, info->curve)) != HAL_OK ||
- (ret = hal_xdr_encode_int(optr, olimit, info->flags)) != HAL_OK ||
- (ret = hal_xdr_encode_buffer(optr, olimit, (uint8_t *)&info->name[0], info->name_len)) != HAL_OK)
- *optr = optr_orig;
+ check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+ check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
+ check(hal_xdr_decode_int(iptr, ilimit, &type));
+ check(hal_xdr_decode_int(iptr, ilimit, &curve));
+ check(hal_xdr_decode_int(iptr, ilimit, &flags));
+ check(hal_xdr_decode_int(iptr, ilimit, &attributes_len));
+
+ hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
+
+ for (int i = 0; i < attributes_len; i++) {
+ hal_pkey_attribute_t *a = &attributes[i];
+ const uint8_t *value;
+ uint32_t value_len;
+ check(hal_xdr_decode_int(iptr, ilimit, &a->type));
+ check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &value, &value_len));
+ a->value = value;
+ a->length = value_len;
+ }
+
+ check(hal_xdr_decode_int(iptr, ilimit, &result_max));
+ check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &previous_uuid_ptr, &previous_uuid_len));
+
+ if (previous_uuid_len != sizeof(hal_uuid_t))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+
+ const hal_uuid_t * const previous_uuid = (const void *) previous_uuid_ptr;
+
+ hal_uuid_t result[result_max];
+ unsigned result_len;
+
+ ret = hal_rpc_pkey_match(client, session, type, curve, flags,
+ attributes, attributes_len,
+ result, &result_len, result_max,
+ previous_uuid);
+
+ if (ret == HAL_OK) {
+ uint8_t *optr_orig = *optr;
+ ret = hal_xdr_encode_int(optr, olimit, result_len);
+ for (int i = 0; ret == HAL_OK && i < result_len; ++i)
+ ret = hal_xdr_encode_buffer(optr, olimit, result[i].uuid,
+ sizeof(result[i].uuid));
+ if (ret != HAL_OK)
+ *optr = optr_orig;
+ }
+
return ret;
}
+static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
+{
+ hal_client_handle_t client;
+ hal_pkey_handle_t pkey;
+ uint32_t attributes_len;
+ hal_error_t ret;
-static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
- uint8_t **optr, const uint8_t * const olimit)
+ check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+ check(hal_xdr_decode_int(iptr, ilimit, &attributes_len));
+
+ hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
+
+ for (int i = 0; i < attributes_len; i++) {
+ hal_pkey_attribute_t *a = &attributes[i];
+ check(hal_xdr_decode_int(iptr, ilimit, &a->type));
+ const uint8_t *iptr_prior_to_decoding_length = *iptr;
+ check(hal_xdr_decode_int(iptr, ilimit, &a->length));
+ if (a->length == HAL_PKEY_ATTRIBUTE_NIL) {
+ a->value = NULL;
+ }
+ else {
+ *iptr = iptr_prior_to_decoding_length;
+ const uint8_t *value;
+ check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &value, &a->length));
+ a->value = value;
+ }
+ }
+
+ ret = hal_rpc_pkey_set_attributes(pkey, attributes, attributes_len);
+
+ return ret;
+}
+
+static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
+ hal_client_handle_t client;
+ hal_pkey_handle_t pkey;
+ uint32_t attributes_len, u32;
uint8_t *optr_orig = *optr;
- uint32_t result_max;
- hal_key_flags_t flags;
hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &result_max));
- check(hal_xdr_decode_int(iptr, ilimit, &flags));
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+ check(hal_xdr_decode_int(iptr, ilimit, &attributes_len));
- hal_pkey_info_t result[result_max];
- unsigned result_len;
+ hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
+
+ for (int i = 0; i < attributes_len; i++)
+ check(hal_xdr_decode_int(iptr, ilimit, &attributes[i].type));
+
+ check(hal_xdr_decode_int(iptr, ilimit, &u32));
+
+ const size_t attributes_buffer_len = u32;
+
+ if (nargs(1 + 2 * attributes_len) + attributes_buffer_len > olimit - *optr)
+ return HAL_ERROR_RPC_PACKET_OVERFLOW;
+
+ uint8_t attributes_buffer[attributes_buffer_len > 0 ? attributes_buffer_len : 1];
+
+ ret = hal_rpc_pkey_get_attributes(pkey, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len);
- /* call the local function */
- ret = hal_rpc_local_pkey_dispatch.list(result, &result_len, result_max, flags);
if (ret == HAL_OK) {
- int i;
- check(hal_xdr_encode_int(optr, olimit, result_len));
- for (i = 0; i < result_len; ++i) {
- if ((ret = hal_xdr_encode_pkey_info(optr, olimit, &result[i])) != HAL_OK) {
- *optr = optr_orig;
+ ret = hal_xdr_encode_int(optr, olimit, attributes_len);
+ for (int i = 0; ret == HAL_OK && i < attributes_len; i++) {
+ ret = hal_xdr_encode_int(optr, olimit, attributes[i].type);
+ if (ret != HAL_OK)
break;
- }
+ if (attributes_buffer_len == 0)
+ ret = hal_xdr_encode_int(optr, olimit, attributes[i].length);
+ else
+ ret = hal_xdr_encode_buffer(optr, olimit, attributes[i].value, attributes[i].length);
}
}
+
+ if (ret != HAL_OK)
+ *optr = optr_orig;
+
return ret;
}
+
hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen,
uint8_t * const obuf, size_t * const olen)
{
@@ -656,96 +793,108 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
uint32_t rpc_func_num;
uint32_t client_handle;
hal_error_t ret;
+ hal_error_t (*handler)(const uint8_t **iptr, const uint8_t * const ilimit,
+ uint8_t **optr, const uint8_t * const olimit) = NULL;
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_func_num));
check(hal_xdr_decode_int(&iptr, ilimit, &client_handle));
check(hal_xdr_undecode_int(&iptr));
+
switch (rpc_func_num) {
case RPC_FUNC_GET_VERSION:
- ret = get_version(&iptr, ilimit, &optr, olimit);
+ handler = get_version;
break;
case RPC_FUNC_GET_RANDOM:
- ret = get_random(&iptr, ilimit, &optr, olimit);
+ handler = get_random;
break;
case RPC_FUNC_SET_PIN:
- ret = set_pin(&iptr, ilimit, &optr, olimit);
+ handler = set_pin;
break;
case RPC_FUNC_LOGIN:
- ret = login(&iptr, ilimit, &optr, olimit);
+ handler = login;
break;
case RPC_FUNC_LOGOUT:
- ret = logout(&iptr, ilimit, &optr, olimit);
+ handler = logout;
break;
case RPC_FUNC_LOGOUT_ALL:
- ret = logout_all(&iptr, ilimit, &optr, olimit);
+ handler = logout_all;
break;
case RPC_FUNC_IS_LOGGED_IN:
- ret = is_logged_in(&iptr, ilimit, &optr, olimit);
+ handler = is_logged_in;
break;
case RPC_FUNC_HASH_GET_DIGEST_LEN:
- ret = hash_get_digest_len(&iptr, ilimit, &optr, olimit);
+ handler = hash_get_digest_len;
break;
case RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID:
- ret = hash_get_digest_algorithm_id(&iptr, ilimit, &optr, olimit);
+ handler = hash_get_digest_algorithm_id;
break;
case RPC_FUNC_HASH_GET_ALGORITHM:
- ret = hash_get_algorithm(&iptr, ilimit, &optr, olimit);
+ handler = hash_get_algorithm;
break;
case RPC_FUNC_HASH_INITIALIZE:
- ret = hash_initialize(&iptr, ilimit, &optr, olimit);
+ handler = hash_initialize;
break;
case RPC_FUNC_HASH_UPDATE:
- ret = hash_update(&iptr, ilimit, &optr, olimit);
+ handler = hash_update;
break;
case RPC_FUNC_HASH_FINALIZE:
- ret = hash_finalize(&iptr, ilimit, &optr, olimit);
+ handler = hash_finalize;
break;
case RPC_FUNC_PKEY_LOAD:
- ret = pkey_load(&iptr, ilimit, &optr, olimit);
+ handler = pkey_load;
break;
- case RPC_FUNC_PKEY_FIND:
- ret = pkey_find(&iptr, ilimit, &optr, olimit);
+ case RPC_FUNC_PKEY_OPEN:
+ handler = pkey_open;
break;
case RPC_FUNC_PKEY_GENERATE_RSA:
- ret = pkey_generate_rsa(&iptr, ilimit, &optr, olimit);
+ handler = pkey_generate_rsa;
break;
case RPC_FUNC_PKEY_GENERATE_EC:
- ret = pkey_generate_ec(&iptr, ilimit, &optr, olimit);
+ handler = pkey_generate_ec;
break;
case RPC_FUNC_PKEY_CLOSE:
- ret = pkey_close(&iptr, ilimit, &optr, olimit);
+ handler = pkey_close;
break;
case RPC_FUNC_PKEY_DELETE:
- ret = pkey_delete(&iptr, ilimit, &optr, olimit);
+ handler = pkey_delete;
break;
case RPC_FUNC_PKEY_GET_KEY_TYPE:
- ret = pkey_get_key_type(&iptr, ilimit, &optr, olimit);
+ handler = pkey_get_key_type;
+ break;
+ case RPC_FUNC_PKEY_GET_KEY_CURVE:
+ handler = pkey_get_key_curve;
break;
case RPC_FUNC_PKEY_GET_KEY_FLAGS:
- ret = pkey_get_key_flags(&iptr, ilimit, &optr, olimit);
+ handler = pkey_get_key_flags;
break;
case RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN:
- ret = pkey_get_public_key_len(&iptr, ilimit, &optr, olimit);
+ handler = pkey_get_public_key_len;
break;
case RPC_FUNC_PKEY_GET_PUBLIC_KEY:
- ret = pkey_get_public_key(&iptr, ilimit, &optr, olimit);
+ handler = pkey_get_public_key;
break;
case RPC_FUNC_PKEY_SIGN:
- ret = pkey_remote_sign(&iptr, ilimit, &optr, olimit);
+ handler = pkey_sign;
break;
case RPC_FUNC_PKEY_VERIFY:
- ret = pkey_remote_verify(&iptr, ilimit, &optr, olimit);
+ handler = pkey_verify;
break;
- case RPC_FUNC_PKEY_LIST:
- ret = pkey_list(&iptr, ilimit, &optr, olimit);
+ case RPC_FUNC_PKEY_MATCH:
+ handler = pkey_match;
break;
- case RPC_FUNC_PKEY_RENAME:
- ret = pkey_rename(&iptr, ilimit, &optr, olimit);
+ case RPC_FUNC_PKEY_SET_ATTRIBUTES:
+ handler = pkey_set_attributes;
break;
- default:
- ret = HAL_ERROR_RPC_BAD_FUNCTION;
+ case RPC_FUNC_PKEY_GET_ATTRIBUTES:
+ handler = pkey_get_attributes;
break;
}
+
+ if (handler)
+ ret = handler(&iptr, ilimit, &optr, olimit);
+ else
+ ret = HAL_ERROR_RPC_BAD_FUNCTION;
+
/* Encode opcode, client ID, and response code at the beginning of the payload */
*olen = optr - obuf;
optr = obuf;
@@ -788,12 +937,26 @@ const hal_rpc_pkey_dispatch_t *hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispa
hal_error_t hal_rpc_server_init(void)
{
- return hal_rpc_server_transport_init();
+ hal_error_t err;
+
+ if ((err = hal_ks_init(hal_ks_volatile_driver, 1)) != HAL_OK ||
+ (err = hal_ks_init(hal_ks_token_driver, 1)) != HAL_OK ||
+ (err = hal_rpc_server_transport_init()) != HAL_OK)
+ return err;
+
+ return HAL_OK;
}
hal_error_t hal_rpc_server_close(void)
{
- return hal_rpc_server_transport_close();
+ hal_error_t err;
+
+ if ((err = hal_rpc_server_transport_close()) != HAL_OK ||
+ (err = hal_ks_shutdown(hal_ks_token_driver)) != HAL_OK ||
+ (err = hal_ks_shutdown(hal_ks_volatile_driver)) != HAL_OK)
+ return err;
+
+ return HAL_OK;
}
diff --git a/slip.c b/slip.c
index 689fff8..b28b7e1 100644
--- a/slip.c
+++ b/slip.c
@@ -148,7 +148,7 @@ hal_error_t hal_slip_recv(uint8_t * const buf, size_t * const len, const size_t
{
int complete;
hal_error_t ret;
-
+
while (1) {
ret = hal_slip_recv_char(buf, len, maxlen, &complete);
if ((ret != HAL_OK) || complete)
diff --git a/tests/test-bus.c b/tests/test-bus.c
index b4a3e1c..94d7a70 100644
--- a/tests/test-bus.c
+++ b/tests/test-bus.c
@@ -68,7 +68,8 @@ static int sanity(const hal_core_t *board_core)
}
if (data != rnd) {
- printf("Data bus fail: expected %08x, got %08x, diff %08x\n", rnd, data, data ^ rnd);
+ printf("Data bus fail: expected %08lx, got %08lx, diff %08lx\n",
+ (unsigned long) rnd, (unsigned long) data, (unsigned long) (data ^ rnd));
return 1;
}
diff --git a/tests/test-mkmif.c b/tests/test-mkmif.c
index ab5801e..3645577 100644
--- a/tests/test-mkmif.c
+++ b/tests/test-mkmif.c
@@ -61,12 +61,12 @@ static hal_error_t write_test(hal_core_t *core)
uint32_t write_address;
int i;
hal_error_t err;
-
+
for (write_data = 0x01020304, write_address = 0, i = 0;
i < 0x10;
write_data += 0x01010101, write_address += 4, ++i) {
- printf("Trying to write 0x%08x to memory address 0x%08x.\n",
+ printf("Trying to write 0x%08x to memory address 0x%08x.\n",
(unsigned int)write_data, (unsigned int)write_address);
if ((err = hal_mkmif_write_word(core, write_address, write_data)) != HAL_OK) {
@@ -84,7 +84,7 @@ static hal_error_t read_test(hal_core_t *core)
uint32_t read_address;
int i;
hal_error_t err;
-
+
for (read_address = 0, i = 0;
i < 0x10;
read_address += 4, ++i) {
@@ -115,7 +115,7 @@ static hal_error_t write_read_test(hal_core_t *core)
printf("write error: %s\n", hal_error_string(err));
return err;
}
-
+
if ((err = hal_mkmif_read_word(core, 0x00000000, &readback)) != HAL_OK) {
printf("read error: %s\n", hal_error_string(err));
return err;
@@ -125,7 +125,7 @@ static hal_error_t write_read_test(hal_core_t *core)
printf("read %08x, expected %08x\n", (unsigned int)readback, (unsigned int)data);
return HAL_ERROR_IO_UNEXPECTED;
}
-
+
return HAL_OK;
}
diff --git a/tests/test-rpc_bighash.c b/tests/test-rpc_bighash.c
index e18d9b0..823baf6 100644
--- a/tests/test-rpc_bighash.c
+++ b/tests/test-rpc_bighash.c
@@ -108,7 +108,7 @@ int main (int argc, char *argv[])
expected = NULL;
check(hal_rpc_client_init());
- check(hal_rpc_hash_initialize(client, session, &hash, hal_digest_algorithm_sha256, NULL, 0));
+ check(hal_rpc_hash_initialize(client, session, &hash, HAL_DIGEST_ALGORITHM_SHA256, NULL, 0));
for (int i = 0; i < iterations; ++i) {
check(hal_rpc_hash_update(hash, block, sizeof(block)));
diff --git a/tests/test-rpc_hash.c b/tests/test-rpc_hash.c
index a0c571c..24f8ede 100644
--- a/tests/test-rpc_hash.c
+++ b/tests/test-rpc_hash.c
@@ -656,52 +656,52 @@ int main (int argc, char *argv[])
ok &= hal_rpc_client_init();
- ok &= test_hash(hal_digest_algorithm_sha1, nist_512_single, sha1_single_digest, "SHA-1 single block");
- ok &= test_hash(hal_digest_algorithm_sha1, nist_512_double, sha1_double_digest, "SHA-1 double block");
-
- ok &= test_hash(hal_digest_algorithm_sha256, nist_512_single, sha256_single_digest, "SHA-256 single block");
- ok &= test_hash(hal_digest_algorithm_sha256, nist_512_double, sha256_double_digest, "SHA-256 double block");
-
- ok &= test_hash(hal_digest_algorithm_sha512_224, nist_1024_single, sha512_224_single_digest, "SHA-512/224 single block");
- ok &= test_hash(hal_digest_algorithm_sha512_224, nist_1024_double, sha512_224_double_digest, "SHA-512/224 double block");
-
- ok &= test_hash(hal_digest_algorithm_sha512_256, nist_1024_single, sha512_256_single_digest, "SHA-512/256 single block");
- ok &= test_hash(hal_digest_algorithm_sha512_256, nist_1024_double, sha512_256_double_digest, "SHA-512/256 double block");
-
- ok &= test_hash(hal_digest_algorithm_sha384, nist_1024_single, sha384_single_digest, "SHA-384 single block");
- ok &= test_hash(hal_digest_algorithm_sha384, nist_1024_double, sha384_double_digest, "SHA-384 double block");
-
- ok &= test_hash(hal_digest_algorithm_sha512, nist_1024_single, sha512_single_digest, "SHA-512 single block");
- ok &= test_hash(hal_digest_algorithm_sha512, nist_1024_double, sha512_double_digest, "SHA-512 double block");
-
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_1_key, hmac_sha1_tc_1_data, hmac_sha1_tc_1_result_sha1, "HMAC-SHA-1 test case 1");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_2_key, hmac_sha1_tc_2_data, hmac_sha1_tc_2_result_sha1, "HMAC-SHA-1 test case 2");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_3_key, hmac_sha1_tc_3_data, hmac_sha1_tc_3_result_sha1, "HMAC-SHA-1 test case 3");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_4_key, hmac_sha1_tc_4_data, hmac_sha1_tc_4_result_sha1, "HMAC-SHA-1 test case 4");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_5_key, hmac_sha1_tc_5_data, hmac_sha1_tc_5_result_sha1, "HMAC-SHA-1 test case 5");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_6_key, hmac_sha1_tc_6_data, hmac_sha1_tc_6_result_sha1, "HMAC-SHA-1 test case 6");
- ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_7_key, hmac_sha1_tc_7_data, hmac_sha1_tc_7_result_sha1, "HMAC-SHA-1 test case 7");
-
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha256, "HMAC-SHA-256 test case 1");
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha256, "HMAC-SHA-256 test case 2");
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha256, "HMAC-SHA-256 test case 3");
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha256, "HMAC-SHA-256 test case 4");
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha256, "HMAC-SHA-256 test case 6");
- ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha256, "HMAC-SHA-256 test case 7");
-
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha384, "HMAC-SHA-384 test case 1");
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha384, "HMAC-SHA-384 test case 2");
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha384, "HMAC-SHA-384 test case 3");
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha384, "HMAC-SHA-384 test case 4");
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha384, "HMAC-SHA-384 test case 6");
- ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha384, "HMAC-SHA-384 test case 7");
-
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha512, "HMAC-SHA-512 test case 1");
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha512, "HMAC-SHA-512 test case 2");
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha512, "HMAC-SHA-512 test case 3");
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha512, "HMAC-SHA-512 test case 4");
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha512, "HMAC-SHA-512 test case 6");
- ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha512, "HMAC-SHA-512 test case 7");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA1, nist_512_single, sha1_single_digest, "SHA-1 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA1, nist_512_double, sha1_double_digest, "SHA-1 double block");
+
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA256, nist_512_single, sha256_single_digest, "SHA-256 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA256, nist_512_double, sha256_double_digest, "SHA-256 double block");
+
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512_224, nist_1024_single, sha512_224_single_digest, "SHA-512/224 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512_224, nist_1024_double, sha512_224_double_digest, "SHA-512/224 double block");
+
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512_256, nist_1024_single, sha512_256_single_digest, "SHA-512/256 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512_256, nist_1024_double, sha512_256_double_digest, "SHA-512/256 double block");
+
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA384, nist_1024_single, sha384_single_digest, "SHA-384 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA384, nist_1024_double, sha384_double_digest, "SHA-384 double block");
+
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512, nist_1024_single, sha512_single_digest, "SHA-512 single block");
+ ok &= test_hash(HAL_DIGEST_ALGORITHM_SHA512, nist_1024_double, sha512_double_digest, "SHA-512 double block");
+
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_1_key, hmac_sha1_tc_1_data, hmac_sha1_tc_1_result_sha1, "HMAC-SHA-1 test case 1");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_2_key, hmac_sha1_tc_2_data, hmac_sha1_tc_2_result_sha1, "HMAC-SHA-1 test case 2");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_3_key, hmac_sha1_tc_3_data, hmac_sha1_tc_3_result_sha1, "HMAC-SHA-1 test case 3");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_4_key, hmac_sha1_tc_4_data, hmac_sha1_tc_4_result_sha1, "HMAC-SHA-1 test case 4");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_5_key, hmac_sha1_tc_5_data, hmac_sha1_tc_5_result_sha1, "HMAC-SHA-1 test case 5");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_6_key, hmac_sha1_tc_6_data, hmac_sha1_tc_6_result_sha1, "HMAC-SHA-1 test case 6");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA1, hmac_sha1_tc_7_key, hmac_sha1_tc_7_data, hmac_sha1_tc_7_result_sha1, "HMAC-SHA-1 test case 7");
+
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha256, "HMAC-SHA-256 test case 1");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha256, "HMAC-SHA-256 test case 2");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha256, "HMAC-SHA-256 test case 3");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha256, "HMAC-SHA-256 test case 4");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha256, "HMAC-SHA-256 test case 6");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA256, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha256, "HMAC-SHA-256 test case 7");
+
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha384, "HMAC-SHA-384 test case 1");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha384, "HMAC-SHA-384 test case 2");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha384, "HMAC-SHA-384 test case 3");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha384, "HMAC-SHA-384 test case 4");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha384, "HMAC-SHA-384 test case 6");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA384, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha384, "HMAC-SHA-384 test case 7");
+
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha512, "HMAC-SHA-512 test case 1");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha512, "HMAC-SHA-512 test case 2");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha512, "HMAC-SHA-512 test case 3");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha512, "HMAC-SHA-512 test case 4");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha512, "HMAC-SHA-512 test case 6");
+ ok &= test_hmac(HAL_DIGEST_ALGORITHM_SHA512, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha512, "HMAC-SHA-512 test case 7");
ok &= hal_rpc_client_close();
diff --git a/tests/test-rpc_pkey.c b/tests/test-rpc_pkey.c
index f6b6f15..c07a318 100644
--- a/tests/test-rpc_pkey.c
+++ b/tests/test-rpc_pkey.c
@@ -44,6 +44,8 @@
#include "test-rsa.h"
#include "test-ecdsa.h"
+#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0)
+
static inline const char *ecdsa_curve_to_string(const hal_curve_name_t curve)
{
switch (curve) {
@@ -54,287 +56,452 @@ static inline const char *ecdsa_curve_to_string(const hal_curve_name_t curve)
}
}
-static int test_rsa_testvec(const rsa_tc_t * const tc)
+static int test_attributes(const hal_pkey_handle_t pkey,
+ const hal_uuid_t * const name,
+ const hal_key_flags_t flags)
+{
+ static const size_t sizes[] = { 32, 100, 260, 1000, 2000, 0 };
+ static const char format[] = "Test attribute %lu";
+
+ hal_error_t err;
+
+ for (const size_t *size = sizes; *size; size++) {
+ uint8_t buf_1[*size], buf_2[*size];
+ memset(buf_1, 0x55, sizeof(buf_1));
+ snprintf((char *) buf_1, sizeof(buf_1), format, (unsigned long) *size);
+ hal_pkey_attribute_t attr_set = { .type = *size, .length = sizeof(buf_1), .value = buf_1 };
+ hal_pkey_attribute_t attr_get = { .type = *size };
+ hal_pkey_attribute_t attr_del = { .type = *size, .length = HAL_PKEY_ATTRIBUTE_NIL };
+
+ if ((err = hal_rpc_pkey_set_attributes(pkey, &attr_set, 1)) != HAL_OK)
+ lose("Could not set attribute %lu: %s\n",
+ (unsigned long) *size, hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_get_attributes(pkey, &attr_get, 1, buf_2, sizeof(buf_2))) != HAL_OK)
+ lose("Could not get attribute %lu: %s\n",
+ (unsigned long) *size, hal_error_string(err));
+
+ if (attr_get.length != *size)
+ lose("Unexpected size returned for attribute %lu: %lu\n",
+ (unsigned long) *size, (unsigned long) attr_get.length);
+
+ if ((err = hal_rpc_pkey_set_attributes(pkey, &attr_del, 1)) != HAL_OK)
+ lose("Could not delete attribute %lu: %s\n",
+ (unsigned long) *size, hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_set_attributes(pkey, &attr_set, 1)) != HAL_OK)
+ lose("Could not (re)set attribute %lu: %s\n",
+ (unsigned long) *size, hal_error_string(err));
+ }
+
+ {
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_uuid_t result[10], previous_uuid = {{0}};
+ unsigned result_len;
+
+ if ((err = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, flags, NULL, 0,
+ result, &result_len, sizeof(result)/sizeof(*result),
+ &previous_uuid)) != HAL_OK)
+ lose("Unrestricted match() failed: %s\n", hal_error_string(err));
+
+ if (result_len == 0)
+ lose("Unrestricted match found no results\n");
+
+ for (const size_t *size = sizes; *size; size++) {
+ uint8_t buf[*size];
+ memset(buf, 0x55, sizeof(buf));
+ snprintf((char *) buf, sizeof(buf), format, (unsigned long) *size);
+ hal_pkey_attribute_t attribute[1] = {{ *size, sizeof(buf), buf }};
+
+ if ((err = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, flags,
+ attribute, sizeof(attribute)/sizeof(*attribute),
+ result, &result_len, sizeof(result)/sizeof(*result),
+ &previous_uuid)) != HAL_OK)
+ lose("Restricted match() for attribute %lu failed: %s\n",
+ (unsigned long) *size, hal_error_string(err));
+
+ if (result_len == 0)
+ lose("Restricted match for attribute %lu found no results\n", (unsigned long) *size);
+ }
+
+#warning More hal_rpc_pkey_match() testing here.
+
+ }
+
+ return 1;
+
+ fail:
+ return 0;
+}
+
+static int test_rsa_testvec(const rsa_tc_t * const tc, hal_key_flags_t flags)
{
- const hal_client_handle_t client = {0};
- const hal_session_handle_t session = {0};
- hal_pkey_handle_t private_key, public_key;
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t private_key = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t public_key = {HAL_HANDLE_NONE};
hal_error_t err;
size_t len;
assert(tc != NULL);
- printf("Starting %lu-bit RSA test vector tests\n", (unsigned long) tc->size);
+ {
+ flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
- uint8_t tc_keybuf[hal_rsa_key_t_size];
- hal_rsa_key_t *tc_key = NULL;
+ printf("Starting %lu-bit RSA test vector tests, flags 0x%lx\n",
+ (unsigned long) tc->size, (unsigned long) flags);
- if ((err = hal_rsa_key_load_private(&tc_key,
- tc_keybuf, sizeof(tc_keybuf),
- tc->n.val, tc->n.len,
- tc->e.val, tc->e.len,
- tc->d.val, tc->d.len,
- tc->p.val, tc->p.len,
- tc->q.val, tc->q.len,
- tc->u.val, tc->u.len,
- tc->dP.val, tc->dP.len,
- tc->dQ.val, tc->dQ.len)) != HAL_OK)
- return printf("Could not load RSA private key from test vector: %s\n", hal_error_string(err)), 0;
+ uint8_t tc_keybuf[hal_rsa_key_t_size];
+ hal_rsa_key_t *tc_key = NULL;
- const uint8_t private_label[] = "RSA private key", public_label[] = "RSA public key";
+ if ((err = hal_rsa_key_load_private(&tc_key,
+ tc_keybuf, sizeof(tc_keybuf),
+ tc->n.val, tc->n.len,
+ tc->e.val, tc->e.len,
+ tc->d.val, tc->d.len,
+ tc->p.val, tc->p.len,
+ tc->q.val, tc->q.len,
+ tc->u.val, tc->u.len,
+ tc->dP.val, tc->dP.len,
+ tc->dQ.val, tc->dQ.len)) != HAL_OK)
+ lose("Could not load RSA private key from test vector: %s\n", hal_error_string(err));
- uint8_t private_der[hal_rsa_private_key_to_der_len(tc_key)];
- uint8_t public_der[hal_rsa_public_key_to_der_len(tc_key)];
+ hal_uuid_t private_name, public_name;
- if ((err = hal_rsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK)
- return printf("Could not DER encode private key from test vector: %s\n", hal_error_string(err)), 0;
+ uint8_t private_der[hal_rsa_private_key_to_der_len(tc_key)];
+ uint8_t public_der[hal_rsa_public_key_to_der_len(tc_key)];
- assert(len == sizeof(private_der));
+ if ((err = hal_rsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK)
+ lose("Could not DER encode private key from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE,
- private_label, sizeof(private_label), private_der, sizeof(private_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load private key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(private_der));
- if ((err = hal_rsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK)
- return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE,
+ &private_name, private_der, sizeof(private_der), flags)) != HAL_OK)
+ lose("Could not load private key into RPC: %s\n", hal_error_string(err));
- assert(len == sizeof(public_der));
+ if ((err = hal_rsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK)
+ lose("Could not DER encode public key from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE,
- public_label, sizeof(public_label), public_der, sizeof(public_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(public_der));
- uint8_t sig[tc->s.len];
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE,
+ &public_name, public_der, sizeof(public_der), flags)) != HAL_OK)
+ lose("Could not load public key into RPC: %s\n", hal_error_string(err));
- /*
- * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo.
- */
- assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff);
- const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2);
- assert(digestinfo != NULL);
- const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo;
+ uint8_t sig[tc->s.len];
- if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none,
- digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK)
- return printf("Could not sign: %s\n", hal_error_string(err)), 0;
+ /*
+ * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo.
+ */
+ assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff);
+ const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2);
+ assert(digestinfo != NULL);
+ const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo;
- if (tc->s.len != len || memcmp(sig, tc->s.val, tc->s.len) != 0)
- return printf("MISMATCH\n"), 0;
+ if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none,
+ digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK)
+ lose("Could not sign: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none,
- digestinfo, digestinfo_len, tc->s.val, tc->s.len)) != HAL_OK)
- return printf("Could not verify: %s\n", hal_error_string(err)), 0;
+ if (tc->s.len != len || memcmp(sig, tc->s.val, tc->s.len) != 0)
+ lose("MISMATCH\n");
- if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
- return printf("Could not delete private key: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ digestinfo, digestinfo_len, tc->s.val, tc->s.len)) != HAL_OK)
+ lose("Could not verify: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
- return printf("Could not delete public key: %s\n", hal_error_string(err)), 0;
+ if (!test_attributes(private_key, &private_name, flags) || !test_attributes(public_key, &public_name, flags))
+ goto fail;
- printf("OK\n");
- return 1;
+ if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ lose("Could not delete private key: %s\n", hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ lose("Could not delete public key: %s\n", hal_error_string(err));
+
+ printf("OK\n");
+ return 1;
+ }
+
+ fail:
+ if (private_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ printf("Warning: could not delete private key: %s\n", hal_error_string(err));
+
+ if (public_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ printf("Warning: could not delete public key: %s\n", hal_error_string(err));
+
+ return 0;
}
-static int test_ecdsa_testvec(const ecdsa_tc_t * const tc)
+static int test_ecdsa_testvec(const ecdsa_tc_t * const tc, hal_key_flags_t flags)
{
- const hal_client_handle_t client = {0};
- const hal_session_handle_t session = {0};
- hal_pkey_handle_t private_key, public_key;
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t private_key = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t public_key = {HAL_HANDLE_NONE};
hal_error_t err;
size_t len;
assert(tc != NULL);
- printf("Starting ECDSA %s test vector tests\n", ecdsa_curve_to_string(tc->curve));
+ {
+ flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
- uint8_t tc_keybuf[hal_ecdsa_key_t_size];
- hal_ecdsa_key_t *tc_key = NULL;
+ printf("Starting ECDSA %s test vector tests, flags 0x%lx\n",
+ ecdsa_curve_to_string(tc->curve), (unsigned long) flags);
- if ((err = hal_ecdsa_key_load_private(&tc_key, tc_keybuf, sizeof(tc_keybuf), tc->curve,
- tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len,
- tc->d, tc->d_len)) != HAL_OK)
- return printf("Could not load ECDSA private key from test vector: %s\n", hal_error_string(err)), 0;
+ uint8_t tc_keybuf[hal_ecdsa_key_t_size];
+ hal_ecdsa_key_t *tc_key = NULL;
- const uint8_t private_label[] = "ECDSA private key", public_label[] = "ECDSA public key";
+ if ((err = hal_ecdsa_key_load_private(&tc_key, tc_keybuf, sizeof(tc_keybuf), tc->curve,
+ tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len,
+ tc->d, tc->d_len)) != HAL_OK)
+ lose("Could not load ECDSA private key from test vector: %s\n", hal_error_string(err));
- uint8_t private_der[hal_ecdsa_private_key_to_der_len(tc_key)];
- uint8_t public_der[hal_ecdsa_public_key_to_der_len(tc_key)];
+ hal_uuid_t private_name, public_name;
- if ((err = hal_ecdsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK)
- return printf("Could not DER encode private key from test vector: %s\n", hal_error_string(err)), 0;
+ uint8_t private_der[hal_ecdsa_private_key_to_der_len(tc_key)];
+ uint8_t public_der[hal_ecdsa_public_key_to_der_len(tc_key)];
- assert(len == sizeof(private_der));
+ if ((err = hal_ecdsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK)
+ lose("Could not DER encode private key from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_EC_PRIVATE, tc->curve,
- private_label, sizeof(private_label), private_der, sizeof(private_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load private key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(private_der));
- if ((err = hal_ecdsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK)
- return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_EC_PRIVATE, tc->curve,
+ &private_name, private_der, sizeof(private_der), flags)) != HAL_OK)
+ lose("Could not load private key into RPC: %s\n", hal_error_string(err));
- assert(len == sizeof(public_der));
+ if ((err = hal_ecdsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK)
+ lose("Could not DER encode public key from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve,
- public_label, sizeof(public_label), public_der, sizeof(public_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(public_der));
- if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none,
- tc->H, tc->H_len, tc->sig, tc->sig_len)) != HAL_OK)
- return printf("Could not verify signature from test vector: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve,
+ &public_name, public_der, sizeof(public_der), flags)) != HAL_OK)
+ lose("Could not load public key into RPC: %s\n", hal_error_string(err));
- uint8_t sig[tc->sig_len + 4];
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ tc->H, tc->H_len, tc->sig, tc->sig_len)) != HAL_OK)
+ lose("Could not verify signature from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none,
- tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK)
- return printf("Could not sign: %s\n", hal_error_string(err)), 0;
+ uint8_t sig[tc->sig_len + 4];
- if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none,
- tc->H, tc->H_len, sig, len)) != HAL_OK)
- return printf("Could not verify own signature: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none,
+ tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK)
+ lose("Could not sign: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
- return printf("Could not delete private key: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ tc->H, tc->H_len, sig, len)) != HAL_OK)
+ lose("Could not verify own signature: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
- return printf("Could not delete public key: %s\n", hal_error_string(err)), 0;
+ if (!test_attributes(private_key, &private_name, flags) || !test_attributes(public_key, &public_name, flags))
+ goto fail;
- printf("OK\n");
- return 1;
+ if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ lose("Could not delete private key: %s\n", hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ lose("Could not delete public key: %s\n", hal_error_string(err));
+
+ printf("OK\n");
+ return 1;
+ }
+
+ fail:
+ if (private_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ printf("Warning: could not delete private key: %s\n", hal_error_string(err));
+
+ if (public_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ printf("Warning: could not delete public key: %s\n", hal_error_string(err));
+
+ return 0;
}
-static int test_rsa_generate(const rsa_tc_t * const tc)
+static int test_rsa_generate(const rsa_tc_t * const tc, hal_key_flags_t flags)
{
- const hal_client_handle_t client = {0};
- const hal_session_handle_t session = {0};
- hal_pkey_handle_t private_key, public_key;
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t private_key = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t public_key = {HAL_HANDLE_NONE};
hal_error_t err;
size_t len;
assert(tc != NULL);
- printf("Starting %lu-bit RSA key generation tests\n", (unsigned long) tc->size);
+ {
+ flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
- const uint8_t private_label[] = "Generated RSA private key", public_label[] = "Generated RSA public key";
+ printf("Starting %lu-bit RSA key generation tests, flags 0x%lx\n",
+ (unsigned long) tc->size, (unsigned long) flags);
- if ((err = hal_rpc_pkey_generate_rsa(client, session, &private_key, private_label, sizeof(private_label),
- tc->size, tc->e.val, tc->e.len,
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not generate RSA private key: %s\n", hal_error_string(err)), 0;
+ hal_uuid_t private_name, public_name;
- uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)];
+ if ((err = hal_rpc_pkey_generate_rsa(client, session, &private_key, &private_name,
+ tc->size, tc->e.val, tc->e.len, flags)) != HAL_OK)
+ lose("Could not generate RSA private key: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK)
- return printf("Could not DER encode RPC RSA public key from RPC RSA private key: %s\n", hal_error_string(err)), 0;
+ uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)];
- assert(len == sizeof(public_der));
+ if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK)
+ lose("Could not DER encode RPC RSA public key from RPC RSA private key: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE,
- public_label, sizeof(public_label), public_der, sizeof(public_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(public_der));
- uint8_t sig[tc->s.len];
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE,
+ &public_name, public_der, sizeof(public_der), flags)) != HAL_OK)
+ lose("Could not load public key into RPC: %s\n", hal_error_string(err));
- /*
- * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo.
- */
- assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff);
- const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2);
- assert(digestinfo != NULL);
- const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo;
+ uint8_t sig[tc->s.len];
- if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none,
- digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK)
- return printf("Could not sign: %s\n", hal_error_string(err)), 0;
+ /*
+ * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo.
+ */
+ assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff);
+ const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2);
+ assert(digestinfo != NULL);
+ const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo;
- if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none,
- digestinfo, digestinfo_len, sig, len)) != HAL_OK)
- return printf("Could not verify: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none,
+ digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK)
+ lose("Could not sign: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
- return printf("Could not delete private key: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ digestinfo, digestinfo_len, sig, len)) != HAL_OK)
+ lose("Could not verify: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
- return printf("Could not delete public key: %s\n", hal_error_string(err)), 0;
+ if (!test_attributes(private_key, &private_name, flags) || !test_attributes(public_key, &public_name, flags))
+ goto fail;
- printf("OK\n");
- return 1;
+ if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ lose("Could not delete private key: %s\n", hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ lose("Could not delete public key: %s\n", hal_error_string(err));
+
+ printf("OK\n");
+ return 1;
+ }
+
+ fail:
+ if (private_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ printf("Warning: could not delete private key: %s\n", hal_error_string(err));
+
+ if (public_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ printf("Warning: could not delete public key: %s\n", hal_error_string(err));
+
+ return 0;
}
-static int test_ecdsa_generate(const ecdsa_tc_t * const tc)
+static int test_ecdsa_generate(const ecdsa_tc_t * const tc, hal_key_flags_t flags)
{
- const hal_client_handle_t client = {0};
- const hal_session_handle_t session = {0};
- hal_pkey_handle_t private_key, public_key;
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t private_key = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t public_key = {HAL_HANDLE_NONE};
hal_error_t err;
size_t len;
assert(tc != NULL);
- printf("Starting ECDSA %s key generation tests\n", ecdsa_curve_to_string(tc->curve));
+ {
+ flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
- const uint8_t private_label[] = "Generated ECDSA private key", public_label[] = "Generated ECDSA public key";
+ printf("Starting ECDSA %s key generation tests, flags 0x%lx\n",
+ ecdsa_curve_to_string(tc->curve), (unsigned long) flags);
- if ((err = hal_rpc_pkey_generate_ec(client, session, &private_key,
- private_label, sizeof(private_label),
- tc->curve, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not generate EC key pair: %s\n", hal_error_string(err)), 0;
+ hal_uuid_t private_name, public_name;
- uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)];
+ if ((err = hal_rpc_pkey_generate_ec(client, session, &private_key, &private_name, tc->curve, flags)) != HAL_OK)
+ lose("Could not generate EC key pair: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK)
- return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0;
+ uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)];
- assert(len == sizeof(public_der));
+ if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK)
+ lose("Could not DER encode public key from test vector: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve,
- public_label, sizeof(public_label), public_der, sizeof(public_der),
- HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK)
- return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0;
+ assert(len == sizeof(public_der));
- uint8_t sig[tc->sig_len + 4];
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve,
+ &public_name, public_der, sizeof(public_der), flags)) != HAL_OK)
+ lose("Could not load public key into RPC: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none,
- tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK)
- return printf("Could not sign: %s\n", hal_error_string(err)), 0;
+ uint8_t sig[tc->sig_len + 4];
- if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none,
- tc->H, tc->H_len, sig, len)) != HAL_OK)
- return printf("Could not verify own signature: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none,
+ tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK)
+ lose("Could not sign: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
- return printf("Could not delete private key: %s\n", hal_error_string(err)), 0;
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ tc->H, tc->H_len, sig, len)) != HAL_OK)
+ lose("Could not verify own signature: %s\n", hal_error_string(err));
- if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
- return printf("Could not delete public key: %s\n", hal_error_string(err)), 0;
+ if (!test_attributes(private_key, &private_name, flags) || !test_attributes(public_key, &public_name, flags))
+ goto fail;
- printf("OK\n");
- return 1;
+ if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ lose("Could not delete private key: %s\n", hal_error_string(err));
+
+ if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ lose("Could not delete public key: %s\n", hal_error_string(err));
+
+ printf("OK\n");
+ return 1;
+ }
+
+ fail:
+ if (private_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(private_key)) != HAL_OK)
+ printf("Warning: could not delete private key: %s\n", hal_error_string(err));
+
+ if (public_key.handle != HAL_HANDLE_NONE &&
+ (err = hal_rpc_pkey_delete(public_key)) != HAL_OK)
+ printf("Warning: could not delete public key: %s\n", hal_error_string(err));
+
+ return 0;
}
int main (int argc, char *argv[])
{
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const char *pin = argc > 1 ? argv[1] : "fnord";
+ hal_error_t err;
int ok = 1;
- hal_rpc_client_init();
+ if ((err = hal_rpc_client_init()) != HAL_OK)
+ printf("Warning: Trouble initializing RPC client: %s\n", hal_error_string(err));
+
+ if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK)
+ printf("Warning: Trouble logging into HSM: %s\n", hal_error_string(err));
for (int i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++)
- ok &= test_rsa_testvec(&rsa_tc[i]);
+ for (int j = 0; j < 2; j++)
+ ok &= test_rsa_testvec(&rsa_tc[i], j * HAL_KEY_FLAG_TOKEN);
for (int i = 0; i < (sizeof(ecdsa_tc)/sizeof(*ecdsa_tc)); i++)
- ok &= test_ecdsa_testvec(&ecdsa_tc[i]);
+ for (int j = 0; j < 2; j++)
+ ok &= test_ecdsa_testvec(&ecdsa_tc[i], j * HAL_KEY_FLAG_TOKEN);
for (int i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++)
- ok &= test_rsa_generate(&rsa_tc[i]);
+ for (int j = 0; j < 2; j++)
+ ok &= test_rsa_generate(&rsa_tc[i], j * HAL_KEY_FLAG_TOKEN);
for (int i = 0; i < (sizeof(ecdsa_tc)/sizeof(*ecdsa_tc)); i++)
- ok &= test_ecdsa_generate(&ecdsa_tc[i]);
+ for (int j = 0; j < 2; j++)
+ ok &= test_ecdsa_generate(&ecdsa_tc[i], j * HAL_KEY_FLAG_TOKEN);
+
+ if ((err = hal_rpc_logout(client)) != HAL_OK)
+ printf("Warning: Trouble logging out of HSM: %s\n", hal_error_string(err));
- ok &= hal_rpc_client_close();
+ if ((err = hal_rpc_client_close()) != HAL_OK)
+ printf("Warning: Trouble shutting down RPC client: %s\n", hal_error_string(err));
return !ok;
}
diff --git a/tests/test-trng.c b/tests/test-trng.c
index ebfe701..f570752 100644
--- a/tests/test-trng.c
+++ b/tests/test-trng.c
@@ -84,7 +84,7 @@ static hal_error_t test_random(const char *name)
return err;
}
- printf("%08x ", rnd);
+ printf("%08lx ", (unsigned long) rnd);
}
printf("\n");
@@ -106,7 +106,7 @@ int main(void)
}
else {
for (i = 0; i < 8; ++i) {
- printf("%08x ", rnd[i]);
+ printf("%08lx ", (unsigned long) rnd[i]);
}
printf("\n");
}
diff --git a/unit-tests.py b/unit-tests.py
new file mode 100644
index 0000000..a8779c5
--- /dev/null
+++ b/unit-tests.py
@@ -0,0 +1,1035 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016, NORDUnet A/S
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of the NORDUnet nor the names of its contributors may
+# be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+LibHAL unit tests, using libhal.py and the Python unit_test framework.
+"""
+
+# There's some overlap between these tests and the PKCS #11 unit tests,
+# because in many cases we're testing the same functionality, just via
+# different APIs.
+
+import unittest
+import datetime
+import sys
+
+from libhal import *
+
+try:
+ from Crypto.Util.number import inverse
+ from Crypto.PublicKey import RSA
+ from Crypto.Signature import PKCS1_v1_5
+ from Crypto.Hash.SHA256 import SHA256Hash as SHA256
+ from Crypto.Hash.SHA384 import SHA384Hash as SHA384
+ from Crypto.Hash.SHA512 import SHA512Hash as SHA512
+ pycrypto_loaded = True
+except ImportError:
+ pycrypto_loaded = False
+
+
+try:
+ from ecdsa.keys import SigningKey as ECDSA_SigningKey, VerifyingKey as ECDSA_VerifyingKey
+ from ecdsa.ellipticcurve import Point
+ from ecdsa.curves import NIST256p, NIST384p, NIST521p
+ if not pycrypto_loaded:
+ from hashlib import sha256 as SHA256, sha384 as SHA384, sha512 as SHA512
+ ecdsa_loaded = True
+except ImportError:
+ ecdsa_loaded = False
+
+
+def log(msg):
+ if not args.quiet:
+ sys.stderr.write(msg)
+ sys.stderr.write("\n")
+
+
+def main():
+ from sys import argv
+ global args
+ args = parse_arguments(argv[1:])
+ argv = argv[:1] + args.only_test
+ unittest.main(verbosity = 1 if args.quiet else 2, argv = argv, catchbreak = True, testRunner = TextTestRunner)
+
+def parse_arguments(argv = ()):
+ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+ parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter)
+ parser.add_argument("--quiet", action = "store_true", help = "suppress chatter")
+ parser.add_argument("--wheel-pin", default = "fnord", help = "PIN for wheel user")
+ parser.add_argument("--so-pin", default = "fnord", help = "PIN for security officer")
+ parser.add_argument("--user-pin", default = "fnord", help = "PIN for normal user")
+ parser.add_argument("--all-tests", action = "store_true", help = "enable tests usually skipped")
+ parser.add_argument("--only-test", default = [], nargs = "+", help = "only run tests named here")
+ return parser.parse_args(argv)
+
+args = parse_arguments()
+hsm = None
+
+pin_map = { HAL_USER_NORMAL : "user_pin", HAL_USER_SO : "so_pin", HAL_USER_WHEEL : "wheel_pin" }
+
+
+def setUpModule():
+ global hsm
+ hsm = HSM()
+
+def tearDownModule():
+ hsm.logout()
+ #hsm.close()
+
+
+# Subclass a few bits of unittest to add timing reports for individual tests.
+
+class TestCase(unittest.TestCase):
+
+ def setUp(self):
+ super(TestCase, self).setUp()
+ self.startTime = datetime.datetime.now()
+
+ def tearDown(self):
+ self.endTime = datetime.datetime.now()
+ super(TestCase, self).tearDown()
+
+class TextTestResult(unittest.TextTestResult):
+
+ def addSuccess(self, test):
+ if self.showAll and hasattr(test, "startTime") and hasattr(test, "endTime"):
+ self.stream.write("runtime {} ... ".format(test.endTime - test.startTime))
+ self.stream.flush()
+ super(TextTestResult, self).addSuccess(test)
+
+class TextTestRunner(unittest.TextTestRunner):
+ resultclass = TextTestResult
+
+
+# Tests below here
+
+
+class TestBasic(TestCase):
+ """
+ Test basic functions that don't involve keys, digests, or PINs.
+ """
+
+ def test_get_version(self):
+ version = hsm.get_version()
+ # Might want to inspect the result here
+ self.assertIsInstance(version, int)
+
+ def test_get_random(self):
+ length = 32
+ random = hsm.get_random(length)
+ self.assertIsInstance(random, str)
+ self.assertEqual(length, len(random))
+
+
+class TestPIN(TestCase):
+ """
+ Test functions involving PINs.
+ """
+
+ def setUp(self):
+ hsm.logout()
+ super(TestPIN, self).setUp()
+
+ def tearDown(self):
+ super(TestPIN, self).tearDown()
+ hsm.logout()
+
+ def test_is_logged_in(self):
+ for user in pin_map:
+ self.assertRaises(HAL_ERROR_FORBIDDEN, hsm.is_logged_in, user)
+
+ def login_logout(self, user1):
+ pin = getattr(args, pin_map[user1])
+ hsm.login(user1, pin)
+ for user2 in pin_map:
+ if user2 == user1:
+ hsm.is_logged_in(user2)
+ else:
+ self.assertRaises(HAL_ERROR_FORBIDDEN, hsm.is_logged_in, user2)
+ hsm.logout()
+
+ def test_login_wheel(self):
+ self.login_logout(HAL_USER_WHEEL)
+
+ def test_login_so(self):
+ self.login_logout(HAL_USER_SO)
+
+ def test_login_user(self):
+ self.login_logout(HAL_USER_NORMAL)
+
+ # Eventually we will want a test of set_pin(), probably under a
+ # @unittest.skipUnless to prevent it from being run unless the
+ # user requests it. Punt that one for the moment.
+
+
+class TestDigest(TestCase):
+ """
+ Test digest/HMAC functions.
+ """
+
+ # Should use NIST test vectors, this is just a placeholder.
+
+ def test_basic_hash(self):
+ h = hsm.hash_initialize(HAL_DIGEST_ALGORITHM_SHA256)
+ h.update("Hi, Mom")
+ h.finalize()
+
+ def test_basic_hmac(self):
+ h = hsm.hash_initialize(HAL_DIGEST_ALGORITHM_SHA256, key = "secret")
+ h.update("Hi, Dad")
+ h.finalize()
+
+
+# Will need something to test for pkey access when not logged in
+# properly (ie, test that we get an appropriate exception under a long
+# list of screwy conditions and that we don't get it under another
+# long list of screwy conditions, due to the PKCS #11 compatible
+# access check semantics). Defer for now.
+
+
+class TestCaseLoggedIn(TestCase):
+ """
+ Abstract class to handle login for PKey tests.
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ hsm.login(HAL_USER_NORMAL, args.user_pin)
+
+ @classmethod
+ def tearDownClass(cls):
+ hsm.logout()
+
+
+class TestPKeyGen(TestCaseLoggedIn):
+ """
+ Tests involving key generation.
+ """
+
+ def sign_verify(self, hashalg, k1, k2):
+ h = hsm.hash_initialize(hashalg)
+ h.update("Your mother was a hamster")
+ data = h.finalize()
+ sig = k1.sign(data = data)
+ k1.verify(signature = sig, data = data)
+ k2.verify(signature = sig, data = data)
+
+ def gen_sign_verify_rsa(self, hashalg, keylen):
+ k1 = hsm.pkey_generate_rsa(keylen)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, k1.public_key)
+ self.addCleanup(k2.delete)
+ self.sign_verify(hashalg, k1, k2)
+
+ def gen_sign_verify_ecdsa(self, hashalg, curve):
+ k1 = hsm.pkey_generate_ec(curve)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve, k1.public_key)
+ self.addCleanup(k2.delete)
+ self.sign_verify(hashalg, k1, k2)
+
+ def test_gen_sign_verify_ecdsa_p256_sha256(self):
+ self.gen_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256)
+
+ def test_gen_sign_verify_ecdsa_p384_sha384(self):
+ self.gen_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384)
+
+ def test_gen_sign_verify_ecdsa_p521_sha512(self):
+ self.gen_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521)
+
+ def test_gen_sign_verify_rsa_1024_p256_sha256(self):
+ self.gen_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024)
+
+ @unittest.skipUnless(args.all_tests, "Slow")
+ def test_gen_sign_verify_rsa_2048_sha384(self):
+ self.gen_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048)
+
+ @unittest.skipUnless(args.all_tests, "Hideously slow")
+ def test_gen_sign_verify_rsa_4096_sha512(self):
+ self.gen_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096)
+
+ def test_gen_unsupported_length(self):
+ with self.assertRaises(HAL_ERROR_BAD_ARGUMENTS):
+ hsm.pkey_generate_rsa(1028).delete()
+
+class TestPKeyHashing(TestCaseLoggedIn):
+ """
+ Tests involving various ways of doing the hashing for public key operations.
+ """
+
+ def load_sign_verify_rsa(self, alg, keylen, method):
+ k1 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE,
+ PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, keylen].der)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE,
+ PreloadedKey.db[HAL_KEY_TYPE_RSA_PUBLIC, keylen].der)
+ self.addCleanup(k2.delete)
+ method(alg, k1, k2)
+
+ def load_sign_verify_ecdsa(self, alg, curve, method):
+ k1 = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, curve,
+ PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, curve].der)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve,
+ PreloadedKey.db[HAL_KEY_TYPE_EC_PUBLIC, curve].der)
+ self.addCleanup(k2.delete)
+ method(alg, k1, k2)
+
+ @staticmethod
+ def h(alg, mixed_mode = False):
+ h = hsm.hash_initialize(alg, mixed_mode = mixed_mode)
+ h.update("Your mother was a hamster")
+ return h
+
+ def sign_verify_data(self, alg, k1, k2):
+ data = self.h(alg, mixed_mode = True).finalize()
+ sig = k1.sign(data = data)
+ k1.verify(signature = sig, data = data)
+ k2.verify(signature = sig, data = data)
+
+ def sign_verify_remote_remote(self, alg, k1, k2):
+ sig = k1.sign(hash = self.h(alg, mixed_mode = False))
+ k1.verify(signature = sig, hash = self.h(alg, mixed_mode = False))
+ k2.verify(signature = sig, hash = self.h(alg, mixed_mode = False))
+
+ def sign_verify_remote_local(self, alg, k1, k2):
+ sig = k1.sign(hash = self.h(alg, mixed_mode = False))
+ k1.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
+ k2.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
+
+ def sign_verify_local_remote(self, alg, k1, k2):
+ sig = k1.sign(hash = self.h(alg, mixed_mode = True))
+ k1.verify(signature = sig, hash = self.h(alg, mixed_mode = False))
+ k2.verify(signature = sig, hash = self.h(alg, mixed_mode = False))
+
+ def sign_verify_local_local(self, alg, k1, k2):
+ sig = k1.sign(hash = self.h(alg, mixed_mode = True))
+ k1.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
+ k2.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
+
+ def test_load_sign_verify_rsa_1024_sha256_data(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_data)
+
+ def test_load_sign_verify_rsa_2048_sha384_data(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_data)
+
+ def test_load_sign_verify_rsa_4096_sha512_data(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_data)
+
+ def test_load_sign_verify_ecdsa_p256_sha256_data(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256, self.sign_verify_data)
+
+ def test_load_sign_verify_ecdsa_p384_sha384_data(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384, self.sign_verify_data)
+
+ def test_load_sign_verify_ecdsa_p521_sha512_data(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_data)
+
+ def test_load_sign_verify_rsa_1024_sha256_remote_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_rsa_2048_sha384_remote_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_rsa_4096_sha512_remote_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_ecdsa_p256_sha256_remote_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_ecdsa_p384_sha384_remote_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_ecdsa_p521_sha512_remote_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_remote_remote)
+
+ def test_load_sign_verify_rsa_1024_sha256_remote_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_rsa_2048_sha384_remote_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_rsa_4096_sha512_remote_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_ecdsa_p256_sha256_remote_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_ecdsa_p384_sha384_remote_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_ecdsa_p521_sha512_remote_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_remote_local)
+
+ def test_load_sign_verify_rsa_1024_sha256_local_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_rsa_2048_sha384_local_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_rsa_4096_sha512_local_remote(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_ecdsa_p256_sha256_local_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_ecdsa_p384_sha384_local_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_ecdsa_p521_sha512_local_remote(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_local_remote)
+
+ def test_load_sign_verify_rsa_1024_sha256_local_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_local_local)
+
+ def test_load_sign_verify_rsa_2048_sha384_local_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_local_local)
+
+ def test_load_sign_verify_rsa_4096_sha512_local_local(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_local_local)
+
+ def test_load_sign_verify_ecdsa_p256_sha256_local_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256, self.sign_verify_local_local)
+
+ def test_load_sign_verify_ecdsa_p384_sha384_local_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, HAL_CURVE_P384, self.sign_verify_local_local)
+
+ def test_load_sign_verify_ecdsa_p521_sha512_local_local(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_local_local)
+
+
+@unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+class TestPKeyRSAInterop(TestCaseLoggedIn):
+
+ @staticmethod
+ def h(alg, text):
+ h = hsm.hash_initialize(alg, mixed_mode = True)
+ h.update(text)
+ return h
+
+ def load_sign_verify_rsa(self, alg, pyhash, keylen):
+ hamster = "Your mother was a hamster"
+ sk = PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, keylen]
+ vk = PreloadedKey.db[HAL_KEY_TYPE_RSA_PUBLIC, keylen]
+ k1 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, sk.der)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, vk.der)
+ self.addCleanup(k2.delete)
+ sig1 = k1.sign(hash = self.h(alg, hamster))
+ sig2 = sk.sign(hamster, pyhash)
+ self.assertEqual(sig1, sig2)
+ k1.verify(signature = sig2, hash = self.h(alg, hamster))
+ k2.verify(signature = sig2, hash = self.h(alg, hamster))
+ sk.verify(hamster, pyhash, sig1)
+ vk.verify(hamster, pyhash, sig1)
+
+ def test_interop_rsa_1024_sha256(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, SHA256, 1024)
+
+ def test_interop_rsa_2048_sha384(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, SHA384, 2048)
+
+ def test_interop_rsa_4096_sha512(self):
+ self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, SHA512, 4096)
+
+
+@unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package")
+class TestPKeyECDSAInterop(TestCaseLoggedIn):
+
+ @staticmethod
+ def h(alg, text):
+ h = hsm.hash_initialize(alg, mixed_mode = True)
+ h.update(text)
+ return h
+
+ def load_sign_verify_ecdsa(self, alg, pyhash, curve):
+ hamster = "Your mother was a hamster"
+ sk = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, curve]
+ vk = PreloadedKey.db[HAL_KEY_TYPE_EC_PUBLIC, curve]
+ k1 = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, curve, sk.der)
+ self.addCleanup(k1.delete)
+ k2 = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, curve, vk.der)
+ self.addCleanup(k2.delete)
+ sig1 = k1.sign(hash = self.h(alg, hamster))
+ sig2 = sk.sign(hamster, pyhash)
+ k1.verify(signature = sig2, hash = self.h(alg, hamster))
+ k2.verify(signature = sig2, hash = self.h(alg, hamster))
+ vk.verify(hamster, pyhash, sig1)
+
+ def test_interop_ecdsa_p256_sha256(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, SHA256, HAL_CURVE_P256)
+
+ def test_interop_ecdsa_p384_sha384(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA384, SHA384, HAL_CURVE_P384)
+
+ def test_interop_ecdsa_p521_sha512(self):
+ self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, SHA512, HAL_CURVE_P521)
+
+
+class TestPKeyList(TestCaseLoggedIn):
+ """
+ Tests involving PKey list and match functions.
+ """
+
+ def load_keys(self, flags):
+ uuids = set()
+ for obj in PreloadedKey.db.itervalues():
+ with hsm.pkey_load(obj.keytype, obj.curve, obj.der, flags) as k:
+ self.addCleanup(lambda uuid: hsm.pkey_open(uuid, flags = flags).delete(), k.uuid)
+ uuids.add(k.uuid)
+ k.set_attributes(dict((i, a) for i, a in enumerate((str(obj.keytype), str(obj.fn2)))))
+ return uuids
+
+ def match(self, flags, **kwargs):
+ uuids = kwargs.pop("uuids", None)
+ kwargs.update(flags = flags)
+ n = 0
+ for uuid in hsm.pkey_match(**kwargs):
+ if uuids is None or uuid in uuids:
+ with hsm.pkey_open(uuid, flags) as k:
+ n += 1
+ yield n, k
+
+ def ks_match(self, flags):
+ tags = []
+ uuids = set()
+ for i in xrange(2):
+ uuids |= self.load_keys(flags)
+ tags.extend(PreloadedKey.db)
+ self.assertEqual(len(tags), len(uuids))
+
+ matched_uuids = set(k.uuid for n, k in self.match(flags = flags))
+ self.assertGreaterEqual(matched_uuids, uuids)
+
+ for keytype in set(HALKeyType.index.itervalues()) - {HAL_KEY_TYPE_NONE}:
+ for n, k in self.match(flags = flags, uuids = uuids, type = keytype):
+ self.assertEqual(k.key_type, keytype)
+ self.assertEqual(k.get_attributes({0}).pop(0), str(keytype))
+ self.assertEqual(n, sum(1 for t1, t2 in tags if t1 == keytype))
+
+ for curve in set(HALCurve.index.itervalues()) - {HAL_CURVE_NONE}:
+ for n, k in self.match(flags = flags, uuids = uuids, curve = curve):
+ self.assertEqual(k.key_curve, curve)
+ self.assertEqual(k.get_attributes({1}).pop(1), str(curve))
+ self.assertIn(k.key_type, (HAL_KEY_TYPE_EC_PUBLIC,
+ HAL_KEY_TYPE_EC_PRIVATE))
+ self.assertEqual(n, sum(1 for t1, t2 in tags if t2 == curve))
+
+ for keylen in set(kl for kt, kl in tags if not isinstance(kl, Enum)):
+ for n, k in self.match(flags = flags, uuids = uuids,
+ attributes = {1 : str(keylen)}):
+ self.assertEqual(keylen, int(k.get_attributes({1}).pop(1)))
+ self.assertIn(k.key_type, (HAL_KEY_TYPE_RSA_PUBLIC,
+ HAL_KEY_TYPE_RSA_PRIVATE))
+ self.assertEqual(n, sum(1 for t1, t2 in tags
+ if not isinstance(t2, Enum) and t2 == keylen))
+
+ for n, k in self.match(flags = flags, uuids = uuids,
+ type = HAL_KEY_TYPE_RSA_PUBLIC, attributes = {1 : "2048"}):
+ self.assertEqual(k.key_type, HAL_KEY_TYPE_RSA_PUBLIC)
+ self.assertEqual(n, sum(1 for t1, t2 in tags
+ if t1 == HAL_KEY_TYPE_RSA_PUBLIC and t2 == 2048))
+
+ def test_ks_match_token(self):
+ self.ks_match(HAL_KEY_FLAG_TOKEN)
+
+ def test_ks_match_volatile(self):
+ self.ks_match(0)
+
+
+class TestPKeyAttribute(TestCaseLoggedIn):
+ """
+ Attribute creation/lookup/deletion tests.
+ """
+
+ def load_and_fill(self, flags, n_keys = 1, n_attrs = 2, n_fill = 0):
+ pinwheel = Pinwheel()
+ for i in xrange(n_keys):
+ for obj in PreloadedKey.db.itervalues():
+ with hsm.pkey_load(obj.keytype, obj.curve, obj.der, flags) as k:
+ pinwheel()
+ self.addCleanup(lambda uuid: hsm.pkey_open(uuid, flags = flags).delete(), k.uuid)
+ k.set_attributes(dict((j, "Attribute {}{}".format(j, "*" * n_fill))
+ for j in xrange(n_attrs)))
+ pinwheel()
+
+ def test_attribute_bloat_volatile_many(self):
+ self.load_and_fill(0, n_attrs = 128) # 192
+
+ def test_attribute_bloat_volatile_big(self):
+ self.load_and_fill(0, n_attrs = 6, n_fill = 512)
+
+ def test_attribute_bloat_token_many(self):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128)
+
+ def test_attribute_bloat_token_big(self):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 4, n_fill = 512) # [16, 1024]
+
+
+class TestPKeyAttributeP11(TestCaseLoggedIn):
+ """
+ Attribute creation/lookup/deletion tests based on a PKCS #11 trace.
+ """
+
+ def setUp(self):
+ der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der
+ self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, HAL_KEY_FLAG_TOKEN)
+ self.addCleanup(self.k.delete)
+ super(TestPKeyAttributeP11, self).setUp()
+
+ def test_set_many_attributes(self):
+ self.k.set_attributes({
+ 0x001 : "\x01",
+ 0x108 : "\x01",
+ 0x105 : "\x00",
+ 0x002 : "\x01",
+ 0x107 : "\x00",
+ 0x102 : "\x45\x43\x2d\x50\x32\x35\x36",
+ 0x003 : "\x45\x43\x2d\x50\x32\x35\x36",
+ 0x162 : "\x00",
+ 0x103 : "\x01",
+ 0x000 : "\x03\x00\x00\x00",
+ 0x100 : "\x03\x00\x00\x00",
+ 0x101 : "",
+ 0x109 : "\x00",
+ 0x10c : "\x00",
+ 0x110 : "",
+ 0x111 : "",
+ 0x163 : "\x00",
+ 0x166 : "\xff\xff\xff\xff",
+ 0x170 : "\x01",
+ 0x210 : "\x00",
+ 0x163 : "\x01",
+ 0x166 : "\x40\x10\x00\x00",
+ 0x180 : "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" })
+
+ def test_set_many_attributes_with_deletions(self):
+ self.k.set_attributes({
+ 0x001 : "\x01",
+ 0x108 : "\x01",
+ 0x105 : "\x00",
+ 0x002 : "\x01",
+ 0x107 : "\x00",
+ 0x102 : "\x45\x43\x2d\x50\x32\x35\x36",
+ 0x003 : "\x45\x43\x2d\x50\x32\x35\x36",
+ 0x162 : "\x00",
+ 0x103 : "\x01",
+ 0x000 : "\x03\x00\x00\x00",
+ 0x100 : "\x03\x00\x00\x00",
+ 0x101 : None,
+ 0x109 : "\x00",
+ 0x10c : "\x00",
+ 0x110 : None,
+ 0x111 : None,
+ 0x163 : "\x00",
+ 0x166 : "\xff\xff\xff\xff",
+ 0x170 : "\x01",
+ 0x210 : "\x00",
+ 0x163 : "\x01",
+ 0x166 : "\x40\x10\x00\x00",
+ 0x180 : "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07" })
+
+
+class TestPKeyAttributeWriteSpeedToken(TestCaseLoggedIn):
+ """
+ Attribute speed tests.
+ """
+
+ def setUp(self):
+ der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der
+ self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, HAL_KEY_FLAG_TOKEN)
+ self.addCleanup(self.k.delete)
+ super(TestPKeyAttributeWriteSpeedToken, self).setUp()
+
+ def set_attributes(self, n_attrs):
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs)))
+
+ def test_set_1_attribute(self):
+ self.set_attributes(1)
+
+ def test_set_6_attributes(self):
+ self.set_attributes(6)
+
+ def test_set_12_attributes(self):
+ self.set_attributes(12)
+
+class TestPKeyAttributeWriteSpeedVolatile(TestCaseLoggedIn):
+ """
+ Attribute speed tests.
+ """
+
+ def setUp(self):
+ der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der
+ self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, 0)
+ self.addCleanup(self.k.delete)
+ super(TestPKeyAttributeWriteSpeedVolatile, self).setUp()
+
+ def set_attributes(self, n_attrs):
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs)))
+
+ def test_set_1_attribute(self):
+ self.set_attributes(1)
+
+ def test_set_6_attributes(self):
+ self.set_attributes(6)
+
+ def test_set_12_attributes(self):
+ self.set_attributes(12)
+
+class TestPKeyAttributeReadSpeedToken(TestCaseLoggedIn):
+ """
+ Attribute speed tests.
+ """
+
+ def setUp(self):
+ der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der
+ self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, HAL_KEY_FLAG_TOKEN)
+ self.addCleanup(self.k.delete)
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(12)))
+ super(TestPKeyAttributeReadSpeedToken, self).setUp()
+
+ def verify_attributes(self, n_attrs, attributes):
+ expected = dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs))
+ self.assertEqual(attributes, expected)
+
+ def get_attributes(self, n_attrs):
+ attributes = self.k.get_attributes(range(n_attrs))
+ self.verify_attributes(n_attrs, attributes)
+
+ def test_get_1_attribute(self):
+ self.get_attributes(1)
+
+ def test_get_6_attributes(self):
+ self.get_attributes(6)
+
+ def test_get_12_attributes(self):
+ self.get_attributes(12)
+
+class TestPKeyAttributeReadSpeedVolatile(TestCaseLoggedIn):
+ """
+ Attribute speed tests.
+ """
+
+ def setUp(self):
+ der = PreloadedKey.db[HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256].der
+ self.k = hsm.pkey_load(HAL_KEY_TYPE_EC_PRIVATE, HAL_CURVE_P256, der, 0)
+ self.addCleanup(self.k.delete)
+ self.k.set_attributes(dict((i, "Attribute {}".format(i))
+ for i in xrange(12)))
+ super(TestPKeyAttributeReadSpeedVolatile, self).setUp()
+
+ def verify_attributes(self, n_attrs, attributes):
+ expected = dict((i, "Attribute {}".format(i))
+ for i in xrange(n_attrs))
+ self.assertEqual(attributes, expected)
+
+ def get_attributes(self, n_attrs):
+ attributes = self.k.get_attributes(range(n_attrs))
+ self.verify_attributes(n_attrs, attributes)
+
+ def test_get_1_attribute(self):
+ self.get_attributes(1)
+
+ def test_get_6_attributes(self):
+ self.get_attributes(6)
+
+ def test_get_12_attributes(self):
+ self.get_attributes(12)
+
+
+@unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package")
+class TestPkeyECDSAVerificationNIST(TestCaseLoggedIn):
+ """
+ ECDSA verification tests based on Suite B Implementer's Guide to FIPS 186-3.
+ """
+
+ def verify(self, Qx, Qy, H, r, s, hal_curve, py_curve, py_hash):
+ Q = ECDSA_VerifyingKey.from_public_point(Point(py_curve.curve, Qx, Qy),
+ py_curve, py_hash).to_der()
+ k = hsm.pkey_load(HAL_KEY_TYPE_EC_PUBLIC, hal_curve, Q)
+ self.addCleanup(k.delete)
+ k.verify(signature = (r + s).decode("hex"), data = H.decode("hex"))
+
+ def test_suite_b_p256_verify(self):
+ self.verify(
+ Qx = 0x8101ece47464a6ead70cf69a6e2bd3d88691a3262d22cba4f7635eaff26680a8,
+ Qy = 0xd8a12ba61d599235f67d9cb4d58f1783d3ca43e78f0a5abaa624079936c0c3a9,
+ H = "7c3e883ddc8bd688f96eac5e9324222c8f30f9d6bb59e9c5f020bd39ba2b8377",
+ r = "7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c",
+ s = "7d1ff961980f961bdaa3233b6209f4013317d3e3f9e1493592dbeaa1af2bc367",
+ hal_curve = HAL_CURVE_P256,
+ py_curve = NIST256p,
+ py_hash = SHA256)
+
+ def test_suite_b__p384_verify(self):
+ self.verify(
+ Qx = 0x1fbac8eebd0cbf35640b39efe0808dd774debff20a2a329e91713baf7d7f3c3e81546d883730bee7e48678f857b02ca0,
+ Qy = 0xeb213103bd68ce343365a8a4c3d4555fa385f5330203bdd76ffad1f3affb95751c132007e1b240353cb0a4cf1693bdf9,
+ H = "b9210c9d7e20897ab86597266a9d5077e8db1b06f7220ed6ee75bd8b45db37891f8ba5550304004159f4453dc5b3f5a1",
+ r = "a0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856",
+ s = "20ab3f45b74f10b6e11f96a2c8eb694d206b9dda86d3c7e331c26b22c987b7537726577667adadf168ebbe803794a402",
+ hal_curve = HAL_CURVE_P384,
+ py_curve = NIST384p,
+ py_hash = SHA384)
+
+
+# Entire classes of tests still missing:
+#
+# * pkey attribute functions
+#
+# * pkey list and match functions
+#
+# * token vs session key tests
+#
+# Preloaded keys should suffice for all of these.
+
+
+
+class Pinwheel(object):
+ """
+ Activity pinwheel, as needed.
+ """
+
+ def __init__(self):
+ self.pinwheel = tuple("\b\b{} ".format(c) for c in "-/|\\")
+ self.modulo = len(self.pinwheel)
+ self.position = 0
+ if not args.quiet:
+ from sys import stdout
+ stdout.write(". ")
+ stdout.flush()
+
+ def __call__(self):
+ if not args.quiet:
+ from sys import stdout
+ stdout.write(self.pinwheel[self.position])
+ stdout.flush()
+ self.position = (self.position + 1) % self.modulo
+
+
+class PreloadedKey(object):
+ """
+ Keys for preload tests, here at the end because they're large.
+ For the moment, we use PKCS #1.5 format for RSA and secg format
+ for ECDSA, because those are the formats that everything
+ (including our own ASN.1 code) supports. Arguably, we should be
+ using PKCS #8 to get a single, consistent, self-identifying
+ private key format, but we're not there yet and it's not
+ particularly urgent given widespread availablity of conversion
+ tools (eg, "openssl pkcs8").
+ """
+
+ db = {}
+
+ def __init__(self, keytype, fn2, obj, der, keylen = None, curve = HAL_CURVE_NONE):
+ self.keytype = keytype
+ self.fn2 = fn2
+ self.obj = obj
+ self.der = der
+ self.keylen = keylen
+ self.curve = curve
+ self.db[keytype, fn2] = self
+
+class PreloadedRSAKey(PreloadedKey):
+
+ @classmethod
+ def importKey(cls, keylen, pem):
+ if pycrypto_loaded:
+ k1 = RSA.importKey(pem)
+ k2 = k1.publickey()
+ cls(HAL_KEY_TYPE_RSA_PRIVATE, keylen, k1, k1.exportKey("DER"), keylen = keylen)
+ cls(HAL_KEY_TYPE_RSA_PUBLIC, keylen, k2, k2.exportKey("DER"), keylen = keylen)
+
+ def sign(self, text, hash):
+ return PKCS1_v1_5.PKCS115_SigScheme(self.obj).sign(hash(text))
+
+ def verify(self, text, hash, signature):
+ return PKCS1_v1_5.PKCS115_SigScheme(self.obj).verify(hash(text), signature)
+
+class PreloadedECKey(PreloadedKey):
+
+ @classmethod
+ def importKey(cls, curve, pem):
+ if ecdsa_loaded:
+ k1 = ECDSA_SigningKey.from_pem(pem)
+ k2 = k1.get_verifying_key()
+ cls(HAL_KEY_TYPE_EC_PRIVATE, curve, k1, k1.to_der(), curve = curve)
+ cls(HAL_KEY_TYPE_EC_PUBLIC, curve, k2, k2.to_der(), curve = curve)
+
+ def sign(self, text, hash):
+ return self.obj.sign(text, hashfunc = hash)
+
+ def verify(self, text, hash, signature):
+ return self.obj.verify(signature, text, hashfunc = hash)
+
+
+# openssl genrsa 1024
+PreloadedRSAKey.importKey(1024, '''\
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC95QlDOvlQhdCe/a7eIoX9SGPVfXfA8/62ilnF+NcwLrhxkr2R
+4EVQB65+9AbxqM8Hqol6fhZzmDs48cl2tOFGJpE8iMhiFm4i6SGl2RXYaG0xi+lJ
+FrXXCLFQovIEMuukBE129wra1xIB72tYR14lu8REX+Mhpbuz44M1jlCrlQIDAQAB
+AoGAeU928l8bZIiH9PnlG318kYkMVhd4SGjXQK/zl9hXSC2goNV4i1d1kCHIJMwq
+H3mTALe+aeVg3GnU85Tq+g2llzogoyXl8q902KbvImrM/XSbsue9/oj0OSgw+jKB
+faFzX6FxAtNV5pmU9QiwauBIl/3yPCF9ifim5zg+pWCqLaECQQD59Z/R6TrTHxp6
+w2vH4CJyP5KORcf+eMa50SAriMVBXsJzsBiLLVxKIZfWbQn9gytJqJZKmIHezZQm
+dyam84fpAkEAwnvSF27RhxLXE037+t7k5MZti6BfNTeUBrwffteepL6qax9HK+h9
+IQZ1vfNIqjZm8i7kQQyy4L8tRnk8mjZmzQJBAIUwfXWTilW+yBRMFx1M7+3itAv9
+YODWqEWRCkxIN5tqi8CrP5jBleCmX8rRFTaxcxpvq42aD/GRp3SLntvs/ikCQCSg
+GOKc1gyv+Z0DFK8cBtMmoz6mRwfInbHe/7dtd8zis0lVLJwSPm5Xvxi0ljyn3h9B
+wW6Wq6Ezn50j+8u27wkCQQCcIFE01BDAdtFHtTJ3aaEM9IdMCYrcJ0I/Y0NTE2M6
+lsTSiPyQjc4dQQJxFduvWHLx28bx+l7FTav7FaKntCJo
+-----END RSA PRIVATE KEY-----
+''')
+
+# openssl genrsa 2048
+PreloadedRSAKey.importKey(2048, '''\
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAsbvq6syhDXD/OMVAuLoMceGQLUIiezfShVqFfyMqADjqhFRW
+Wbonn0XV9ZkypU4Ib9n6PtLATNaefhpsUlI4s+20YTlQ7GiwJ9p97/N1o1u060ja
+4LdqhfYtn8GZX+JAfa5NqpmLKCJ58XJ3q28MPLRwYp5yKckjkzchZHFyjs1W7r5a
+JfeJ/vsQusX3klmCehJ1jxSHPh8o6lTjFMnBK8t360YTu0UGK/RUcEAYO7l7FWjd
+8PjZfawXIrOAhCLkVvDFfpsl2oyFIL9d1QE87WdyyZXAtWLs62gnX+kiBq9gUhu5
+GsgcQifHBcRiGZfH0TRIMgIsSjsorzHqJ9uoQwIDAQABAoIBAGqzx5/5A8NfEEpT
+2bxNLcV8xqL1LmBNLh0TMEwYn1GM2fZh74lkwf7T3VTaCVbGlzgXZC4tNneq7XIF
+iPyPEi2rSnyH/XZAj2kNukfBIOHW37HVhloco14TYmajwuGWomMRrtz521pYAF+c
++g042N7k8Qez2hQOBkaOdYSouz7RNdJUGUocRhcSkh+QZTBwtQxrkuhhHN+zkIri
++Q09hF2hAliHrh6mow8ci0gRsXnZzsdJfTX8CasHWTIll4gfrvWnUY7iYqB6ynRU
+YN+7IgQXMUFLziIlH1qN+DlEYdznsgAPSS3JdTWh0cvjiO8wTFAnOIdsj+BpKoDB
+PK2zzDkCgYEA3TP8h4Ds/y1tDijE3Sarrg0vWuY97sJmAla4qFHH4hscZ84NDzTM
+I/ohLPJgpeR2MaBqZmVk9UFrd3rdt3/lX6kSO7Kffa9rVgfOB4CqJ4joso3j0qY8
+V/iVBcDcD1h4aXCRX2tMJICUTgVU/N8/2wBEElcOUjZHGlcHmbHndlUCgYEAzbFm
+ttPuIHrYHkmOm/DjYB65+WD8gfPMdeUbnx+yIt5xwimIbq1qWzl4++goTAAyaU/7
+qM9IfveRue0B7yjnPa8fjN+CcXMGM6a3BIqeIv1icfgjHxlt7D+64FpENWXHvFE0
+MhRliINfkTHm+U4+1s0045a+bLdTbfVly1gATDcCgYEAyOaoWmFL3k7hl1SLx9eR
+YVj0Q3iNk0XX5BPjTmxIQCEjYVwRHFh1d897Rhk0kja26kepmypH0UADXNaofDqa
+lpE10CZhGIOz1sTr6ICBCbscrN6VpgH5GGTa5AjPVNijNBBa1/DZjOWCzIGnOKuC
+kWLicE3E4gIN/exBKOQdNqkCgYEAjA5PMg38BoGexoCvad8L81b4qqUvSg0HGv91
+X1Plp3hvXRWKoFHUKWlox528UoOPz8V2ReteIZXQ1BhdSMtBKO8lPHa0CyuW/XR3
+CdCY/Jorfg7HW1WlU0fRpxHPf8xdxAxGzhK1T86kM+kWrIpqnzf62zy5TK1HUYfW
+WC8DhOECgYBzU8hIA0PU7aRPUs0o9MO9XcvVPvdX6UOKdNb9CnBMudS/chKHJUYP
+d0fFAiVaRX0JMQ0RSrenxCqfWVtW3T3wFYNHB/IFRIUT3I44wwXJTNOeoi3FDTMx
+EQfc0UFoFHyc3mYEKR4zHheqQG5OFBN89LqG3S+O69vc1qwCvNKL+Q==
+-----END RSA PRIVATE KEY-----
+''')
+
+# openssl genrsa 4096
+PreloadedRSAKey.importKey(4096, '''\
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAzWpYSQt+DrUNI+EJT/ko92wM2POfFnmm3Kc34nmuK6sez0DJ
+r9Vib9R5K46RNgqcUdAodjU6cy3/MZA53SqP7RwR/LQtWmK2a+T4iey2vQZ0iCDA
+2NI4gjgmCAjZnOD/m5yUXjCig/wJ8pGXolg8oHnvdeLg1joIOSF9OudLrI6aJnDg
+OfdegzmCWXmWl7TXrqHVIWZhZZF7qQZRso6ZQ1/8mjpvVD0drASBxMnIzvpe4ynr
+Y2NB807X/D5bbScp292ZKTNf5unPN1SsFy5ymzfLZrfNksYef6xPXcVr6OiObi49
+De8e11aNPj6fgLzzqAu1rjjrDkgvXx5G7gPJXq1aq6uxB2cKMrRS+ivmyC8vQlzP
+lQwW20oYeeOfCg7ddNAJcu3jNTuNJaZdhc9szpVhV8DXZoXe/RzUNjZH7wUqueHy
+fpbLwS+h3McJqrbWFdCQBivZnoI05cF2JIHEeR3S0Gyo2/IheNeFX2Tt8oDnHY4a
+olRHiR5CMdM8UoGSxR9Y12fZ9dcqdCH3d6wDAsBDHTCE8ZIwFwhW6iA+g54YE3X7
+BlsgWr60poCDgH+CJjh0VDVxqL7r+w76sD9WAQMa7Gb+Mp2XCYnIZPXTrsmwVbZ9
+s5vFXUEODYom6qBlbZB8gyZzee5Skc1jx2fnmqxRtflA4W3xVAQFof2rFiUCAwEA
+AQKCAgBxhQXJSFqf0hqy61h0I+Qp6EKpWuleSFiYtKjDti803tql+s37KFfAKZHV
+KnLBhNeitwDFYuEsag0P3P69ZRopFUwzdXdi7g6WTfG0d2b9y6V23XL14Cduf400
+/38TnZxk6QFtlD8b5ZuxvBgqlczbeseFRJ6whV2qBQHqHYzKjfxOpi6kmjpXFt8c
+h39b04smbTUVwjitIttOK7nWjcvRWiiFKyn/Sc8uE0eL81/QUrlBnRcC1AXMapQe
+SG/KQMx3P123UTb8q9XiZB6+qOKZORplZ8pqBKcyM42g6suZ6XtdFJyVKMLIioKA
+FaecQ8/73IzI/ZeZSvcy/85/FwSfGjHD7C7vL9kfg77no+IvHYlBYiIqtTddpQH5
+LGJAJnOGtk047/OjTmL8QyylvDAv8jBeZZdbOX7L+8jk5DbHmfUcDjvBS9g+Fbfk
+jDurphrp1dHn/YgaA27NZs87TPWX1aVPiOlXEhO9SHHiiKCHDpBzV1gW/eiho33s
++uEr57ZoakzonN/zNb7KqHUO/ZGwMg+V9bVIgThqbdgmxNz7JFz14CN79yPmW5QT
+1P1v7a6xWaZTALe2HGvy0B+iRzhLpay1tI4O/omPj9vUzVJwGHztVt0RddcmA9wV
+Y3qglRNl+YvNlm6BUn8KwPIqki8JoioA8J1EQ5mz/K0fbrzcOQKCAQEA8TCqq0pb
+mfxtsf42zhsSUw1VdcCIG0IYcSWxIiCfujryAQX1tmstZeRchlykXmdO+JDcpvMy
+BKBD7188JEWjCX1IRRtHxTJ5WG+pE8sNPLNL8eZVZ+CEbNjVk4dtWGLwyNm+rQkM
+NmOlm+7ZHdezBXljZOeqZbdsTSDQcGYG8JxlvLpAN60pjIGvTdTrdnksMhB4PK+l
+7KtyEVDWXU/VT6kqhP3Ri1doHv/81BplgfjEJM8ZxmasfP4SlJ1olKqsHMFSrclj
+ZCAemKEexVyzg8cHm9ghj6MLQZe3gs94V6h8I2ifrBBNHMrZgYg2Db0GeyYrr+kZ
+GDjT0DZp0jgyfwKCAQEA2gdTclmrfAU/67ziOJbjkMgfhBdteE1BbJDNUca0zB6q
+Ju4BwNgt0cxHMbltgE2/8hWP95HIaQdh1mIgwSK93MxRbaAvAQfF3muJxvMR5Mru
+DejE+IEK9eZetgkNHGWyfiFzBWHda/Z9PQkqYtRfop5qFBVAPZ4YzR5hT0j64eDQ
+N/z9C0ZB6RL9EcXJgEYgGI3wP8Qsrw3JRBQN0SCVRmrEJm4WIXs+CEHOk56/VbPM
+v82uwbHVghS0U9bEZvNoeq7ZQjS2tRXXRJeOgQyCNvYy670T0KvQZoDb59EbEDSz
+eQZS1J7rDEBHW+VwRSJA8noMEgZdEv8AxbEF2CddWwKCAQAMwH71iXvoW1FNbNxm
+70V7wKO5ExHfJxJ1wQFphYIMbZtn9HG2UFpZHcbKj9Fc8GdbewU/inIljnepC0b5
+v/jLwqT0imm0AmQqCdVNp5mukOg+BOiVEmjN/HTmVO2yE6EZbXHIYkcUBRa3dNxj
+2IitjGp15k27DQSb21VJ7AsH46z5WnuUtgIRXLXxDoXYgLWWfApvYvYJ2lKwma6L
+xnHHwXDvESBoFpn5sZ0jdbXSNl3geFarh7gs753534ys940cBBij+ZbYr14Owc4H
+r0wKdpZvZfD4UC2DLUtVjjSVpeHSWXC/vyjkkdEIKTR6a3kRP8ZliZR7FF4Wjxnv
+NGtvAoIBAEu5g6gRsNewUxUjU0boUT115ExSfrjrzC9S05z1cNH8TIic3YsHClL1
+qjyA9KE9X89K4efQgFTKNZbqGgo6cMsBQ77ZhbnL41Nu8jlhLvPR74BxOgg9eXsS
+eg6rchxMzgO0xmg2J1taDwFl74zHyjeG4bz77IX6JQ8I4C9TX5+YH3lyqsiBrF6x
+M6g6k9Ozh24/zhO3pPVfymmUtX/O20nLxzi5v4H9dfwULxVia33upsxvOaUYiNlX
+K5J641gGbmE93UN7X4HhhhTStrHnkEpalDEASKOPKSCQ3M/U9ptYUoVURuyGDYkB
+wkcOl0HLtdcBwLN59lWkr7X519fNREUCggEBAMk39k+shD2DW8ubE/LgoforwfT2
+558FPxpZ+pGwMHL3ZnLuQuiROyPyQZj/ZmmLAa2TPrwS/ssln46Y2KesejWK/0Hq
+8SaFLhOjacF8u5IOOKBZvx+HOT6ctRNBVyzt9A8wu0DE6nzc5HQpm9TMXrOLuZ0L
+u22yFikwoIgYpU6hBdbg1mnirZS/ZyqJV9gWB6ZYyUAUGdgBqL6euSAAqBp93qz8
+sQLesqTufT1mVZd/ndLyvjDJjNKUE0w1g/1xNtg6N5aM+7pc/DwE/s+EtCxc/858
+dQYLBHIPcw6e0FdL3nTs44BpAqcK28N5eWbe/KaZ3EA0lHRmyOQ++WgU6jo=
+-----END RSA PRIVATE KEY-----
+''')
+
+# openssl ecparam -genkey -name prime256v1 | openssl ec
+PreloadedECKey.importKey(HAL_CURVE_P256, '''\
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPBrVhD1iFF2e8wPkPf4N1038iR8xPgku/CVOT8lcSztoAoGCCqGSM49
+AwEHoUQDQgAE3mB5BmN5Fa4fV74LsDWIpBUxktPqYGJ6WOBrjPs1HWkNU7JHO3qY
+9yy+CXFSPb89GWQgb5wLtNPn4QYMj+KRTA==
+-----END EC PRIVATE KEY-----
+''')
+
+# openssl ecparam -genkey -name secp384r1 | openssl ec
+PreloadedECKey.importKey(HAL_CURVE_P384, '''\
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCVGo35Hbrf3Iys7mWRIm5yjg+6vPIgzbp2jCbDyszBo+wTxmQambG4
+g8yocp4wM6+gBwYFK4EEACKhZANiAATYwa+M8T8jsNHKmMZTvPPflUIfrjuZZo1D
+3kkkmN4r6cTNctjaeRdAfD0X40l4yPnGIP9ParuKVVl1y0TdQ7BS3g/Gj/LP33HD
+ESP8gFDIKFCWSDX0uhmy+HsGsPwgNoY=
+-----END EC PRIVATE KEY-----
+''')
+
+# openssl ecparam -genkey -name secp521r1 | openssl ec
+PreloadedECKey.importKey(HAL_CURVE_P521, '''\
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBtf+LKhJNQEJRFQ2cGQPcviwfp9IKSnD5EFTqAPtv7/+t2FtmdHHP
+/fWIlZ7jcC5N9dWy6bKGu3+FqwgZAYLpsqigBwYFK4EEACOhgYkDgYYABADdfcUe
+P0oAZQ5308v5ijcg4hePvhvVi+QKcrwmE9kirXCFoYN1tzPmXZmw8lNJenrbwaNz
+opJR84LBHnomGPogAQGF0aRk0jE8w1j1oMfrrzV6vCWnkh7pyzsDnrLU1HrkWeqw
+ihzwMzYJgFzToDH+fCh7nrBFZZZ9P9gPYMlSM5UMeA==
+-----END EC PRIVATE KEY-----
+''')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/uuid.c b/uuid.c
new file mode 100644
index 0000000..8b82066
--- /dev/null
+++ b/uuid.c
@@ -0,0 +1,111 @@
+/*
+ * uuid.c
+ * ------
+ * UUID support for keystore database.
+ *
+ * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+hal_error_t hal_uuid_gen(hal_uuid_t *uuid)
+{
+ hal_error_t err;
+
+ if (uuid == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Generate a version 4 UUID as specified in RFC 4122.
+ * This is basically a 122-bit random number.
+ */
+
+ if ((err = hal_rpc_get_random(uuid->uuid, sizeof(uuid->uuid))) != HAL_OK)
+ return err;
+
+ /*
+ * Set high order bits of clock_seq_hi_and_reserved and
+ * time_hi_and_version fields to magic values as specified by RFC
+ * 4122 section 4.4.
+ *
+ * Not recommended reading if you've eaten recently.
+ */
+
+ uuid->uuid[6] &= 0x0f;
+ uuid->uuid[6] |= 0x40;
+ uuid->uuid[8] &= 0x3f;
+ uuid->uuid[8] |= 0x80;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_uuid_parse(hal_uuid_t *uuid, const char * const string)
+{
+ static const char fmt[]
+ = "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx";
+
+ if (uuid == NULL || string == NULL ||
+ sscanf(string, fmt,
+ uuid->uuid + 0, uuid->uuid + 1, uuid->uuid + 2, uuid->uuid + 3,
+ uuid->uuid + 4, uuid->uuid + 5, uuid->uuid + 6, uuid->uuid + 7,
+ uuid->uuid + 8, uuid->uuid + 9, uuid->uuid + 10, uuid->uuid + 11,
+ uuid->uuid + 12, uuid->uuid + 13, uuid->uuid + 14, uuid->uuid + 15) != 16)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_uuid_format(const hal_uuid_t * const uuid, char *buffer, const size_t buffer_len)
+{
+ static const char fmt[]
+ = "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx";
+
+ if (uuid == NULL || buffer == NULL || buffer_len < HAL_UUID_TEXT_SIZE)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (snprintf(buffer, buffer_len, fmt,
+ uuid->uuid[ 0], uuid->uuid[ 1], uuid->uuid[ 2], uuid->uuid[ 3],
+ uuid->uuid[ 4], uuid->uuid[ 5], uuid->uuid[ 6], uuid->uuid[ 7],
+ uuid->uuid[ 8], uuid->uuid[ 9], uuid->uuid[10], uuid->uuid[11],
+ uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]) != HAL_UUID_TEXT_SIZE - 1)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ return HAL_OK;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */