aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile57
-rw-r--r--README.md91
-rw-r--r--aes_keywrap.c16
-rw-r--r--asn1.c170
-rw-r--r--asn1_internal.h25
-rw-r--r--core.c89
-rw-r--r--cryptech/libhal.py29
-rwxr-xr-xcryptech_backup187
-rwxr-xr-xcryptech_muxd41
-rw-r--r--ecdsa.c20
-rw-r--r--hal.h90
-rw-r--r--hal_internal.h512
-rw-r--r--hal_io.c114
-rw-r--r--hal_io_eim.c54
-rw-r--r--hal_io_fmc.c56
-rw-r--r--hal_io_i2c.c47
-rw-r--r--hash.c20
-rw-r--r--hashsig.c2058
-rw-r--r--hashsig.h118
-rw-r--r--ks.c1033
-rw-r--r--ks.h437
-rw-r--r--ks_attribute.c4
-rw-r--r--ks_flash.c2213
-rw-r--r--ks_index.c367
-rw-r--r--ks_mmap.c180
-rw-r--r--ks_token.c665
-rw-r--r--ks_volatile.c672
-rw-r--r--mkmif.c52
-rw-r--r--modexp.c300
-rw-r--r--pbkdf2.c3
-rw-r--r--rpc_api.c25
-rw-r--r--rpc_client.c144
-rw-r--r--rpc_hash.c6
-rw-r--r--rpc_misc.c98
-rw-r--r--rpc_pkey.c439
-rw-r--r--rpc_server.c547
-rw-r--r--rsa.c551
-rw-r--r--slip.c2
-rw-r--r--tests/Makefile4
-rwxr-xr-xtests/parallel-signatures.py409
-rw-r--r--tests/test-aes-key-wrap.c2
-rw-r--r--tests/test-ecdsa.c2
-rw-r--r--tests/test-hash.c2
-rw-r--r--tests/test-hashsig.h925
-rw-r--r--tests/test-pbkdf2.c2
-rw-r--r--tests/test-rpc_hashsig.c594
-rw-r--r--tests/test-rsa.c23
-rw-r--r--tests/test-trng.c1
-rw-r--r--tests/test-xdr.c111
-rwxr-xr-xtests/time-keygen.py37
-rw-r--r--unit-tests.py669
-rw-r--r--utils/cores.c2
-rw-r--r--verilog_constants.h37
-rw-r--r--xdr.c227
-rw-r--r--xdr_internal.h44
55 files changed, 9810 insertions, 4813 deletions
diff --git a/Makefile b/Makefile
index 8f2f998..6934f95 100644
--- a/Makefile
+++ b/Makefile
@@ -34,27 +34,24 @@ STATIC_CORE_STATE_BLOCKS = 32
STATIC_HASH_STATE_BLOCKS = 32
STATIC_HMAC_STATE_BLOCKS = 16
STATIC_PKEY_STATE_BLOCKS = 256
-STATIC_KS_VOLATILE_SLOTS = 128
+STATIC_KS_VOLATILE_SLOTS = 1280
-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=mmap|flash] [RPC_TRANSPORT=none|loopback|serial|daemon] [MODEXP_CORE=no|yes] [HASH_CORES=no|yes] [ECDSA_CORES=no|yes]"
+USAGE := "usage: ${MAKE} [IO_BUS=eim|i2c|fmc] [RPC_MODE=none|server|client-simple|client-mixed] [RPC_TRANSPORT=none|loopback|serial|daemon] [MODEXP_CORE=no|yes] [HASH_CORES=no|yes] [ECDSA_CORES=no|yes]"
IO_BUS ?= none
-KS ?= flash
RPC_MODE ?= none
RPC_TRANSPORT ?= none
-MODEXP_CORE ?= no
+MODEXP_CORE ?= yes
HASH_CORES ?= no
ECDSA_CORES ?= yes
ifeq (,$(and \
$(filter none eim i2c fmc ,${IO_BUS}),\
$(filter none server client-simple client-mixed ,${RPC_MODE}),\
- $(filter mmap flash ,${KS}),\
$(filter none loopback serial daemon ,${RPC_TRANSPORT}),\
$(filter no yes ,${MODEXP_CORE}),\
$(filter no yes ,${HASH_CORES}),\
@@ -62,7 +59,7 @@ ifeq (,$(and \
$(error ${USAGE})
endif
-$(info Building libhal with configuration IO_BUS=${IO_BUS} RPC_MODE=${RPC_MODE} KS=${KS} RPC_TRANSPORT=${RPC_TRANSPORT} MODEXP_CORE=${MODEXP_CORE} HASH_CORES=${HASH_CORES} ECDSA_CORES=${ECDSA_CORES})
+$(info Building libhal with configuration IO_BUS=${IO_BUS} RPC_MODE=${RPC_MODE} RPC_TRANSPORT=${RPC_TRANSPORT} MODEXP_CORE=${MODEXP_CORE} HASH_CORES=${HASH_CORES} ECDSA_CORES=${ECDSA_CORES})
# Whether the RSA code should use the ModExp | ModExpS6 | ModExpA7 core.
@@ -96,7 +93,7 @@ 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 xdr.o slip.o
+OBJ += errorstrings.o hash.o asn1.o ecdsa.o rsa.o hashsig.o xdr.o slip.o
OBJ += rpc_api.o rpc_hash.o uuid.o rpc_pkcs1.o crc32.o locks.o logging.o
# Object files to build when we're on a platform with direct access
@@ -112,12 +109,13 @@ CORE_OBJ = core.o csprng.o pbkdf2.o aes_keywrap.o modexp.o mkmif.o ${IO_OBJ}
# i2c: Older I2C bus from Novena
# fmc: FMC bus from dev-bridge and alpha boards
+IO_OBJ = hal_io.o
ifeq "${IO_BUS}" "eim"
- IO_OBJ = hal_io_eim.o novena-eim.o
+ IO_OBJ += hal_io_eim.o novena-eim.o
else ifeq "${IO_BUS}" "i2c"
- IO_OBJ = hal_io_i2c.o
+ IO_OBJ += hal_io_i2c.o
else ifeq "${IO_BUS}" "fmc"
- IO_OBJ = hal_io_fmc.o
+ IO_OBJ += hal_io_fmc.o
endif
# If we're building for STM32, position-independent code leads to some
@@ -138,16 +136,8 @@ endif
# 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_index.o ks_attribute.o ks_volatile.o
-ifeq "${KS}" "mmap"
- KS_OBJ += ks_mmap.o
-else ifeq "${KS}" "flash"
- KS_OBJ += ks_flash.o mkm.o
-endif
+KS_OBJ = ks.o ks_index.o ks_attribute.o ks_volatile.o ks_token.o mkm.o
# RPC_MODE = none | server | client-simple | client-mixed
# none: Build without RPC client, use cores directly.
@@ -186,28 +176,28 @@ endif
ifeq "${RPC_MODE}" "none"
OBJ += ${CORE_OBJ}
- CFLAGS += -DHAL_RSA_USE_MODEXP=${RSA_USE_MODEXP_CORE}
+ CFLAGS += -DHAL_RSA_SIGN_USE_MODEXP=${RSA_USE_MODEXP_CORE}
CFLAGS += -DHAL_ONLY_USE_SOFTWARE_HASH_CORES=${HASH_ONLY_USE_SOFT_CORES}
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER=${ECDSA_USE_ECDSA256_CORE}
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER=${ECDSA_USE_ECDSA384_CORE}
else ifeq "${RPC_MODE}" "server"
OBJ += ${CORE_OBJ} ${RPC_SERVER_OBJ}
CFLAGS += -DRPC_CLIENT=RPC_CLIENT_LOCAL
- CFLAGS += -DHAL_RSA_USE_MODEXP=${RSA_USE_MODEXP_CORE}
+ CFLAGS += -DHAL_RSA_SIGN_USE_MODEXP=${RSA_USE_MODEXP_CORE}
CFLAGS += -DHAL_ONLY_USE_SOFTWARE_HASH_CORES=${HASH_ONLY_USE_SOFT_CORES}
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER=${ECDSA_USE_ECDSA256_CORE}
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER=${ECDSA_USE_ECDSA384_CORE}
else ifeq "${RPC_MODE}" "client-simple"
OBJ += ${RPC_CLIENT_OBJ}
CFLAGS += -DRPC_CLIENT=RPC_CLIENT_REMOTE
- CFLAGS += -DHAL_RSA_USE_MODEXP=0
+ CFLAGS += -DHAL_RSA_SIGN_USE_MODEXP=0
CFLAGS += -DHAL_ONLY_USE_SOFTWARE_HASH_CORES=1
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER=0
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER=0
else ifeq "${RPC_MODE}" "client-mixed"
OBJ += ${RPC_CLIENT_OBJ}
CFLAGS += -DRPC_CLIENT=RPC_CLIENT_MIXED
- CFLAGS += -DHAL_RSA_USE_MODEXP=0
+ CFLAGS += -DHAL_RSA_SIGN_USE_MODEXP=0
CFLAGS += -DHAL_ONLY_USE_SOFTWARE_HASH_CORES=1
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA256_MULTIPLIER=0
CFLAGS += -DHAL_ECDSA_VERILOG_ECDSA384_MULTIPLIER=0
@@ -230,6 +220,7 @@ CFLAGS += -DHAL_STATIC_CORE_STATE_BLOCKS=${STATIC_CORE_STATE_BLOCKS}
CFLAGS += -DHAL_STATIC_HASH_STATE_BLOCKS=${STATIC_HASH_STATE_BLOCKS}
CFLAGS += -DHAL_STATIC_HMAC_STATE_BLOCKS=${STATIC_HMAC_STATE_BLOCKS}
CFLAGS += -DHAL_STATIC_PKEY_STATE_BLOCKS=${STATIC_PKEY_STATE_BLOCKS}
+CFLAGS += -DHAL_STATIC_KS_VOLATILE_SLOTS=${STATIC_KS_VOLATILE_SLOTS}
CFLAGS += -I${CRYPTECH_ROOT}/sw/libhal
CFLAGS += -I${LIBTFM_BLD}
@@ -269,16 +260,20 @@ daemon: mixed
.PHONY: client mixed server serial daemon
-${OBJ}: ${INC}
-
${LIB}: ${OBJ}
${AR} rcs $@ $^
-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_flash.o: last_gasp_pin_internal.h
+asn1.o rsa.o ecdsa.o: asn1_internal.h
+ecdsa.o: ecdsa_curves.h
+${OBJ}: hal.h
+${OBJ}: hal_internal.h
+ks.o ks_token.o ks_volatile.o ks_attribute.o ks_index.o: ks.h
+ks_token.o: last_gasp_pin_internal.h
+novena-eim.o hal_io_eim.o: novena-eim.h
+slip.o rpc_client_serial.o rpc_server_serial.o: slip_internal.h
+${OBJ}: verilog_constants.h
+rpc_client.o rpc_server.o xdr.o: xdr_internal.h
+hashsig.o: hashsig.h
last_gasp_pin_internal.h:
./utils/last_gasp_default_pin >$@
diff --git a/README.md b/README.md
index 39de7b6..ba68f3c 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ math for ECDSA verification; ECDSA math for key generation and signing
on the P-256 and P-384 curves is done in the ECDSA base point
multiplier cores when those are available.
+
## RSA ##
The RSA implementation includes a compile-time option to bypass the
@@ -72,6 +73,7 @@ a tad slow at the moment (others are hard at work fixing this).
The RSA implementation includes optional blinding (enabled by default).
+
## ECDSA ##
The ECDSA implementation is specific to the NIST prime curves P-256,
@@ -112,6 +114,92 @@ point arithmetic is performed in Jacobian projective coordinates, with
the coordinates themselves in Montgomery form; final mapping back to
affine coordinates also handles the final Montgomery reduction.
+
+## Keystore ##
+
+The keystore is basically a light-weight database intended to be run
+directly over some kind of block-access device, with an internal
+low-level driver interface so that we can use the same API for
+multiple keystore devices (eg, flash for "token objects" and RAM for
+"session objects", in the PKCS #11 senses of those terms).
+
+The available storage is divided up into "blocks" of a fixed size; for
+simplicity, the block size is a multiple of the subsector size of the
+flash chip on the Alpha platform, since that's the minimum erasable
+unit. All state stored in the keystore itself follows the conventions
+needed for flash devices, whether the device in question is flash or
+not. The basic rule here is that one can only clear bits, never set
+them: the only way to set a bit is to erase the whole block and start
+over. So blocks progress from an initial state ("erased") where all
+bits are set to one, through several states where the block contains
+useful data, and ending in a state where all bits are set to zero
+("zeroed"), because that's the way that flash hardware works.
+
+The keystore implementation also applies a light-weight form of wear
+leveling to all keystore devices, whether they're flash devices or
+not. The wear-leveling mechanism is not particularly sophisticated,
+but should suffice. The wear-leveling code treats the entirety of a
+particular keystore device as a ring buffer of blocks, and keeps track
+of which blocks have been used recently by zeroing blocks upon freeing
+them rather than erasing them immediately, while also always keeping
+the block at the current head of the free list in the erased state.
+Taken together, this is enough to recover location of the block at the
+head of the free list after a reboot, which is sufficient for a
+round-robin wear leveling strategy.
+
+The block format includes a field for a CRC-32 checksum, which covers
+the entire block except for a few specific fields which need to be
+left out. On reboot, blocks with bad CRC-32 values are considered
+candidates for reuse, but are placed at the end of the free list,
+preserve their contents for as long as possible in case the real
+problem is a buggy firmware update.
+
+At the moment, the decision about whether to use the CRC-32 mechanism
+is up to the individual driver: the flash driver uses it, the RAM
+driver (which never stores anything across reboots anyway) does not.
+
+Since the flash-like semantics do not allow setting bits, updates to a
+block always consist of allocating a new block and copying the
+modified data. The keystore code uses a trivial lock-step protocol
+for this: first:
+
+1. The old block is marked as a "tombstone";
+2. The new block (with modified data) is written;
+3. The old block is erased.
+
+This protocol is deliberately as simple as possible, so that there is
+always a simple recovery path on reboot.
+
+Active blocks within a keystore are named by UUIDs. With one
+exception, these are always type-4 (random) UUIDs, generated directly
+from output of the TRNG. The one exception is the current PIN block,
+which always uses the reserved all-zeros UUID, which cannot possibly
+conflict with a type-4 UUID (by definition).
+
+The core of the keystore mechanism is the `ks->index[]` array, which
+contains nothing but a list of block numbers. This array is divided
+into two parts: the first part is the index of active blocks, which is
+kept sorted (by UUID); the second part is the round-robin free list.
+Everything else in the keystore is indexed by these block numbers,
+which means that the index array is the only data structure which the
+keystore code needs to sort or rotate when adding, removing, or
+updating a block. Because the block numbers themselves are small
+integers, the index array itself is small enough that shuffling data
+within it using `memmove()` is a relatively cheap operation, which in
+turn avoids a lot of complexity that would be involved in managing
+more sophisticated data structures.
+
+The keystore code includes both caching of recently used keystore
+blocks (to avoid unnecessary flash reads) and caching of the location
+of the block corresponding to a particular UUID (to avoid unnecessary
+index searches). Aside from whatever direct performance benefits this
+might bring, this also frees the pkey layer that sits directly on top
+of the keystore code from needing to keep a lot of active state on
+particular keystore objects, which is important given that this whole
+thing sits under an RPC protocol driven by a client program which can
+impose arbitrary delays between any two operations at the pkey layer.
+
+
## Key backup ##
The key backup mechanism is a straightforward three-step process,
@@ -134,6 +222,7 @@ Transfer of the wrapped keys between the two HSMs can be by any
convenient mechanism; for simplicity, `cryptech_backup` script bundles
everything up in a text file using JSON and Base64 encoding.
+
## Multiplexer daemon ##
While the C client library can be built to talk directly to the
@@ -149,6 +238,7 @@ The multiplexer requires two external Python libraries, Tornado
In the long run, the RPC mechanism will need to be wrapped in some
kind of secure channel protocol, but we're not there yet.
+
## API ##
Yeah, we ought to document the API, Real Soon Now, perhaps using
@@ -156,5 +246,6 @@ Yeah, we ought to document the API, Real Soon Now, perhaps using
the Python definitions in cryptech.libhal, and and comments in the
code.
+
[EFD]: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
[Doxygen]: http://www.doxygen.org/
diff --git a/aes_keywrap.c b/aes_keywrap.c
index d7701f0..355cb0b 100644
--- a/aes_keywrap.c
+++ b/aes_keywrap.c
@@ -165,8 +165,7 @@ hal_error_t hal_aes_keywrap(hal_core_t *core,
{
const size_t calculated_C_len = hal_aes_keywrap_ciphertext_length(m);
hal_error_t err;
- uint32_t n;
- long i, j;
+ size_t n;
assert(calculated_C_len % 8 == 0);
@@ -202,8 +201,8 @@ hal_error_t hal_aes_keywrap(hal_core_t *core,
}
else {
- for (j = 0; j <= 5; j++) {
- for (i = 1; i <= n; i++) {
+ for (size_t j = 0; j <= 5; j++) {
+ for (size_t i = 1; i <= n; i++) {
uint32_t t = n * j + i;
if ((err = do_block(core, C, C + i * 8)) != HAL_OK)
goto out;
@@ -235,8 +234,7 @@ hal_error_t hal_aes_keyunwrap(hal_core_t * core,
size_t *Q_len)
{
hal_error_t err;
- uint32_t n;
- long i, j;
+ size_t n;
size_t m;
if (C == NULL || Q == NULL || C_len % 8 != 0 || C_len < 16 || Q_len == NULL || *Q_len < C_len)
@@ -259,8 +257,8 @@ hal_error_t hal_aes_keyunwrap(hal_core_t * core,
}
else {
- for (j = 5; j >= 0; j--) {
- for (i = n; i >= 1; i--) {
+ for (long j = 5; j >= 0; j--) {
+ for (size_t i = n; i >= 1; i--) {
uint32_t t = n * j + i;
Q[7] ^= t & 0xFF; t >>= 8;
Q[6] ^= t & 0xFF; t >>= 8;
@@ -285,7 +283,7 @@ hal_error_t hal_aes_keyunwrap(hal_core_t * core,
}
if (m % 8 != 0)
- for (i = m + 8; i < 8 * (n + 1); i++)
+ for (size_t i = m + 8; i < 8 * (n + 1); i++)
if (Q[i] != 0x00) {
err = HAL_ERROR_KEYWRAP_BAD_PADDING;
goto out;
diff --git a/asn1.c b/asn1.c
index 73e34b6..37318a9 100644
--- a/asn1.c
+++ b/asn1.c
@@ -77,6 +77,10 @@ const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
#endif
+/* from draft-housley-cms-mts-hash-sig-07.txt */
+const uint8_t hal_asn1_oid_mts_hashsig[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x10, 0x03, 0x11 };
+const size_t hal_asn1_oid_mts_hashsig_len = sizeof(hal_asn1_oid_mts_hashsig);
+
/*
* Encode tag and length fields of an ASN.1 object.
*
@@ -175,6 +179,88 @@ hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
}
/*
+ * Encode an unsigned ASN.1 INTEGER from a uint32_t. If der is
+ * NULL, just return the length of what we would have encoded.
+ */
+
+hal_error_t hal_asn1_encode_uint32(const uint32_t n,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ /*
+ * We only handle unsigned INTEGERs, so we need to pad data with a
+ * leading zero if the most significant bit is set, to avoid
+ * flipping the ASN.1 sign bit.
+ */
+
+ size_t vlen;
+ hal_error_t err;
+ size_t hlen;
+
+ /* DER says to use the minimum number of octets */
+ if (n < 0x80) vlen = 1;
+ else if (n < 0x8000) vlen = 2;
+ else if (n < 0x800000) vlen = 3;
+ else if (n < 0x80000000) vlen = 4;
+ else vlen = 5;
+
+ err = hal_asn1_encode_header(ASN1_INTEGER, vlen, der, &hlen, der_max);
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (der == NULL || err != HAL_OK)
+ return err;
+
+ assert(hlen + vlen <= der_max);
+
+ der += hlen;
+
+ uint32_t m = n;
+ for (size_t i = vlen; i > 0; --i) {
+ der[i - 1] = m & 0xff;
+ m >>= 8;
+ }
+
+ return HAL_OK;
+}
+
+/*
+ * Encode an ASN.1 OCTET STRING. If der is NULL, just return the length
+ * of what we would have encoded.
+ */
+
+hal_error_t hal_asn1_encode_octet_string(const uint8_t * const data, const size_t data_len,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (data_len == 0 || (der != NULL && data == NULL))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ size_t hlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, NULL, &hlen, 0)) != HAL_OK)
+ return err;
+
+ if (der_len != NULL)
+ *der_len = hlen + data_len;
+
+ if (der == NULL)
+ return HAL_OK;
+
+ assert(hlen + data_len <= der_max);
+
+ /*
+ * Handle data early, in case it was staged into our output buffer.
+ */
+ memmove(der + hlen, data, data_len);
+
+ if ((err = hal_asn1_encode_header(ASN1_OCTET_STRING, data_len, der, &hlen, der_max)) != HAL_OK)
+ return err;
+
+ return HAL_OK;
+}
+
+/*
* Encode a public key into a X.509 SubjectPublicKeyInfo (RFC 5280).
*/
@@ -484,6 +570,68 @@ hal_error_t hal_asn1_decode_integer(fp_int *bn,
}
/*
+ * Decode an ASN.1 INTEGER into a uint32_t. Since we only
+ * support (or need to support, or expect to see) unsigned integers,
+ * we return failure if the sign bit is set in the ASN.1 INTEGER.
+ */
+
+hal_error_t hal_asn1_decode_uint32(uint32_t *np,
+ const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ if (np == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err;
+ size_t hlen, vlen;
+
+ if ((err = hal_asn1_decode_header(ASN1_INTEGER, der, der_max, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (vlen < 1 || vlen > 5 || (der[hlen] & 0x80) != 0x00 || (vlen == 5 && der[hlen] != 0))
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ uint32_t n = 0;
+ for (size_t i = 0; i < vlen; ++i) {
+ n <<= 8; // slightly inefficient for the first octet
+ n += der[hlen + i];
+ }
+ *np = n;
+
+ return HAL_OK;
+}
+
+/*
+ * Decode an ASN.1 OCTET STRING.
+ */
+
+hal_error_t hal_asn1_decode_octet_string(uint8_t *data, const size_t data_len,
+ const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ if (der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ size_t hlen, vlen;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, der, der_max, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ if (der_len != NULL)
+ *der_len = hlen + vlen;
+
+ if (data != NULL) {
+ if (data_len != vlen)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ memmove(data, der + hlen, vlen);
+ }
+
+ return HAL_OK;
+}
+
+/*
* Decode a public key from a X.509 SubjectPublicKeyInfo (RFC 5280).
*/
@@ -517,7 +665,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -537,7 +685,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (curve_oid != NULL)
*curve_oid = d;
@@ -564,7 +712,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d || vlen == 0 || *d != 0x00)
+ if (vlen >= (size_t)(algid_end - d) || vlen == 0 || *d != 0x00)
return HAL_ERROR_ASN1_PARSE_FAILED;
++d; --vlen;
if (pubkey != NULL)
@@ -620,7 +768,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -640,7 +788,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (curve_oid != NULL)
*curve_oid = d;
@@ -667,7 +815,7 @@ hal_error_t hal_asn1_decode_pkcs8_privatekeyinfo(const uint8_t **alg_oid, size
if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d)
+ if (vlen >= (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (privkey != NULL)
*privkey = d;
@@ -714,7 +862,7 @@ hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oi
if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen > algid_end - d)
+ if (vlen > (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (alg_oid != NULL)
*alg_oid = d;
@@ -736,7 +884,7 @@ hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oi
if ((err = hal_asn1_decode_header(ASN1_OCTET_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK)
return err;
d += hlen;
- if (vlen >= algid_end - d)
+ if (vlen >= (size_t)(algid_end - d))
return HAL_ERROR_ASN1_PARSE_FAILED;
if (data != NULL)
*data = d;
@@ -788,6 +936,12 @@ hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type,
return err;
}
+ if (alg_oid_len == hal_asn1_oid_mts_hashsig_len && memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_HASHSIG_PUBLIC : HAL_KEY_TYPE_HASHSIG_PRIVATE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_OK;
+ }
+
*type = HAL_KEY_TYPE_NONE;
*curve = HAL_CURVE_NONE;
return HAL_ERROR_UNSUPPORTED_KEY;
diff --git a/asn1_internal.h b/asn1_internal.h
index fe2f293..23d8a77 100644
--- a/asn1_internal.h
+++ b/asn1_internal.h
@@ -102,6 +102,9 @@ extern const size_t hal_asn1_oid_ecPublicKey_len;
extern const uint8_t hal_asn1_oid_aesKeyWrap[];
extern const size_t hal_asn1_oid_aesKeyWrap_len;
+extern const uint8_t hal_asn1_oid_mts_hashsig[];
+extern const size_t hal_asn1_oid_mts_hashsig_len;
+
/*
* Transcoding functions.
*/
@@ -117,9 +120,21 @@ extern hal_error_t hal_asn1_decode_header(const uint8_t tag,
extern hal_error_t hal_asn1_encode_integer(const fp_int * const bn,
uint8_t *der, size_t *der_len, const size_t der_max);
+extern hal_error_t hal_asn1_encode_uint32(const uint32_t n,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_encode_octet_string(const uint8_t * const data, const size_t data_len,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
extern hal_error_t hal_asn1_decode_integer(fp_int *bn,
const uint8_t * const der, size_t *der_len, const size_t der_max);
+extern hal_error_t hal_asn1_decode_uint32(uint32_t *np,
+ const uint8_t * const der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_asn1_decode_octet_string(uint8_t *data, const size_t data_len,
+ const uint8_t * const der, size_t *der_len, const size_t der_max);
+
extern hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t alg_oid_len,
const uint8_t * const curve_oid, const size_t curve_oid_len,
const uint8_t * const pubkey, const size_t pubkey_len,
@@ -151,6 +166,16 @@ extern hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t *
extern hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type, hal_curve_name_t *curve,
const uint8_t *const der, const size_t der_len);
+/*
+ * Peek ahead for an OPTIONAL attribute.
+ */
+
+static inline int hal_asn1_peek(const uint8_t tag,
+ const uint8_t * const der, size_t der_max)
+{
+ return der != NULL && der_max > 0 && der[0] == tag;
+}
+
#endif /* _HAL_ASN1_INTERNAL_H_ */
/*
diff --git a/core.c b/core.c
index 1c247f0..c604a15 100644
--- a/core.c
+++ b/core.c
@@ -4,7 +4,7 @@
* This module contains code to probe the FPGA for its installed cores.
*
* Author: Paul Selkirk, Rob Austein
- * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -97,7 +97,7 @@ static int name_matches(const hal_core_t *const core, const char * const name)
static const struct { const char *name; hal_addr_t extra; } gaps[] = {
{ "csprng", 11 * CORE_SIZE }, /* empty slots after csprng */
{ "modexps6", 3 * CORE_SIZE }, /* ModexpS6 uses four slots */
- { "modexpa7", 3 * CORE_SIZE }, /* ModexpA7 uses four slots */
+ { "modexpa7", 7 * CORE_SIZE }, /* ModexpA7 uses eight slots */
};
static hal_core_t *head = NULL;
@@ -135,7 +135,7 @@ static hal_core_t *probe_cores(void)
if (core->info.name[0] == 0x00 || core->info.name[0] == 0xff)
continue;
- for (int i = 0; i < sizeof(gaps)/sizeof(*gaps); i++) {
+ for (size_t i = 0; i < sizeof(gaps)/sizeof(*gaps); i++) {
if (name_matches(core, gaps[i].name)) {
addr += gaps[i].extra;
break;
@@ -201,17 +201,19 @@ hal_core_t *hal_core_find(const char *name, hal_core_t *core)
return NULL;
}
-hal_error_t hal_core_alloc(const char *name, hal_core_t **pcore)
+static hal_error_t hal_core_alloc_no_wait(const char *name, hal_core_t **pcore)
{
- hal_core_t *core;
- hal_error_t err = HAL_ERROR_CORE_NOT_FOUND;
+ /*
+ * This used to allow name == NULL iff *core != NULL, but the
+ * semantics were fragile and in practice we always pass a name
+ * anyway, so simplify by requiring name != NULL, always.
+ */
- if (name == NULL && (pcore == NULL || *pcore == NULL))
+ if (name == NULL || pcore == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- core = *pcore;
- if (name == NULL)
- name = core->info.name;
+ hal_error_t err = HAL_ERROR_CORE_NOT_FOUND;
+ hal_core_t *core = *pcore;
if (core != NULL) {
/* if we can reallocate the same core, do it now */
@@ -221,35 +223,56 @@ hal_error_t hal_core_alloc(const char *name, hal_core_t **pcore)
hal_critical_section_end();
return HAL_OK;
}
- /* else fall through to search */
+ /* else forget that core and fall through to search */
+ *pcore = NULL;
}
- while (1) {
- hal_critical_section_start();
- for (core = hal_core_iterate(NULL); core != NULL; core = core->next) {
- if (name_matches(core, name)) {
- if (core->busy) {
- err = HAL_ERROR_CORE_BUSY;
- continue;
- }
- else {
- err = HAL_OK;
- *pcore = core;
- core->busy = 1;
- break;
- }
- }
+ hal_critical_section_start();
+ for (core = hal_core_find(name, NULL); core != NULL; core = hal_core_find(name, core)) {
+ if (core->busy) {
+ err = HAL_ERROR_CORE_BUSY;
+ continue;
}
- hal_critical_section_end();
- if (err == HAL_ERROR_CORE_BUSY)
- hal_task_yield();
- else
- break;
- }
+ err = HAL_OK;
+ *pcore = core;
+ core->busy = 1;
+ break;
+ }
+ hal_critical_section_end();
return err;
}
+hal_error_t hal_core_alloc(const char *name, hal_core_t **pcore)
+{
+ hal_error_t err;
+
+ while ((err = hal_core_alloc_no_wait(name, pcore)) == HAL_ERROR_CORE_BUSY)
+ hal_task_yield();
+
+ return err;
+}
+
+hal_error_t hal_core_alloc2(const char *name1, hal_core_t **pcore1,
+ const char *name2, hal_core_t **pcore2)
+{
+ hal_error_t err;
+
+ while (1) {
+ if ((err = hal_core_alloc(name1, pcore1)) != HAL_OK)
+ return err;
+
+ if ((err = hal_core_alloc_no_wait(name2, pcore2)) == HAL_OK)
+ return HAL_OK;
+
+ hal_core_free(*pcore1);
+ /* hal_core_free does a yield, so we don't need to do another one */
+
+ if (err != HAL_ERROR_CORE_BUSY)
+ return err;
+ }
+}
+
void hal_core_free(hal_core_t *core)
{
if (core != NULL) {
@@ -270,7 +293,7 @@ const hal_core_info_t *hal_core_info(const hal_core_t *core)
return core == NULL ? NULL : &core->info;
}
-const int hal_core_busy(const hal_core_t *core)
+int hal_core_busy(const hal_core_t *core)
{
return (int)core->busy;
}
diff --git a/cryptech/libhal.py b/cryptech/libhal.py
index 0c6b3f6..273a8a0 100644
--- a/cryptech/libhal.py
+++ b/cryptech/libhal.py
@@ -43,7 +43,6 @@ import uuid
import xdrlib
import socket
import logging
-import contextlib
logger = logging.getLogger(__name__)
@@ -117,10 +116,7 @@ HALError.define(HAL_ERROR_KEYSTORE_LOST_DATA = "Keystore appears to have
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_KS_INDEX_UUID_MISORDERED = "Key index UUID misordered")
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")
@@ -406,11 +402,20 @@ class PKey(Handle):
return result
def export_pkey(self, pkey):
- return self.hsm.pkey_export(pkey = pkey, kekek = self, pkcs8_max = 2560, kek_max = 512)
+ return self.hsm.pkey_export(pkey = pkey, kekek = self, pkcs8_max = 5480, kek_max = 512)
def import_pkey(self, pkcs8, kek, flags = 0):
return self.hsm.pkey_import(kekek = self, pkcs8 = pkcs8, kek = kek, flags = flags)
+class ContextManagedUnpacker(xdrlib.Unpacker):
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.done()
+
+
class HSM(object):
mixed_mode = False
@@ -432,7 +437,7 @@ class HSM(object):
logger.debug("send: %s", ":".join("{:02x}".format(ord(c)) for c in msg))
self.socket.sendall(msg)
- def _recv(self, code): # Returns an xdrlib.Unpacker
+ def _recv(self, code): # Returns a ContextManagedUnpacker
closed = False
while True:
msg = [self.sockfile.read(1)]
@@ -445,7 +450,7 @@ class HSM(object):
msg = slip_decode("".join(msg))
if not msg:
continue
- msg = xdrlib.Unpacker("".join(msg))
+ msg = ContextManagedUnpacker("".join(msg))
if msg.unpack_uint() != code:
continue
return msg
@@ -483,7 +488,6 @@ class HSM(object):
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()
@@ -494,8 +498,7 @@ class HSM(object):
unpacker = self._recv(code)
client = unpacker.unpack_uint()
self._raise_if_error(unpacker.unpack_uint())
- yield unpacker
- unpacker.done()
+ return unpacker
def get_version(self):
with self.rpc(RPC_FUNC_GET_VERSION) as r:
@@ -537,7 +540,9 @@ class HSM(object):
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):
+ def hash_initialize(self, alg, key = None, client = 0, session = 0, mixed_mode = None):
+ if key is None:
+ key = ""
if mixed_mode is None:
mixed_mode = self.mixed_mode
if mixed_mode:
diff --git a/cryptech_backup b/cryptech_backup
index f14f119..76cdfbb 100755
--- a/cryptech_backup
+++ b/cryptech_backup
@@ -17,6 +17,15 @@ sure only to export keys using a KEKEK known to have been generated by
the target HSM. See the unit tests in the source repository for
an example of how to fake this in a few lines of Python.
+We also implement a software-based variant on this backup mechanism,
+for cases where there is no second HSM. The protocol is much the
+same, but the KEKEK is generated in software and encrypted using a
+symmetric key derived from a passphrase using PBKDF2. This requires
+the PyCrypto library, and is only as secure as memory on the machine
+where you're running it (so it's theoretically vulnerable to root or
+anybody with access to /dev/mem). Don't use this mode unless you
+understand the risks, and see the "NOTE WELL" above.
+
YOU HAVE BEEN WARNED. Be careful out there.
"""
@@ -72,6 +81,11 @@ def main():
"-u", "--uuid",
help = "UUID of existing KEKEK to use")
+ setup_mutex_group.add_argument(
+ "-s", "--soft-backup",
+ action = "store_true",
+ help = "software-based backup, see warnings")
+
setup_parser.add_argument(
"-k", "--keylen",
type = int,
@@ -147,9 +161,11 @@ def cmd_setup(args, hsm):
"""
result = {}
+ uuids = []
- uuids = []
- if args.uuid:
+ if args.soft_backup:
+ SoftKEKEK.generate(args, result)
+ elif args.uuid:
uuids.append(args.uuid)
elif not args.new:
uuids.extend(hsm.pkey_match(
@@ -177,7 +193,11 @@ def cmd_setup(args, hsm):
if not result:
sys.exit("Could not find suitable KEKEK")
- result.update(comment = "KEKEK public key")
+ if args.soft_backup:
+ result.update(comment = "KEKEK software keypair")
+ else:
+ result.update(comment = "KEKEK public key")
+
json.dump(result, args.output, indent = 4, sort_keys = True)
args.output.write("\n")
@@ -249,7 +269,14 @@ def cmd_import(args, hsm):
"""
db = json.load(args.input)
- with hsm.pkey_open(uuid.UUID(db["kekek_uuid"]).bytes) as kekek:
+
+ soft_key = SoftKEKEK.is_soft_key(db)
+
+ with (hsm.pkey_load(SoftKEKEK.recover(db), HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)
+ if soft_key else
+ hsm.pkey_open(uuid.UUID(db["kekek_uuid"]).bytes)
+ ) as kekek:
+
for k in db["keys"]:
pkcs8 = b64join(k.get("pkcs8", ""))
spki = b64join(k.get("spki", ""))
@@ -262,6 +289,158 @@ def cmd_import(args, hsm):
with hsm.pkey_load(der = spki, flags = flags) as pkey:
print "Loaded {} as {}".format(k["uuid"], pkey.uuid)
+ if soft_key:
+ kekek.delete()
+
+
+class AESKeyWrapWithPadding(object):
+ """
+ Implementation of AES Key Wrap With Padding from RFC 5649.
+ """
+
+ class UnwrapError(Exception):
+ "Something went wrong during unwrap."
+
+ def __init__(self, key):
+ from Crypto.Cipher import AES
+ self.ctx = AES.new(key, AES.MODE_ECB)
+
+ def _encrypt(self, b1, b2):
+ aes_block = self.ctx.encrypt(b1 + b2)
+ return aes_block[:8], aes_block[8:]
+
+ def _decrypt(self, b1, b2):
+ aes_block = self.ctx.decrypt(b1 + b2)
+ return aes_block[:8], aes_block[8:]
+
+ @staticmethod
+ def _start_stop(start, stop): # Syntactic sugar
+ step = -1 if start > stop else 1
+ return xrange(start, stop + step, step)
+
+ @staticmethod
+ def _xor(R0, t):
+ from struct import pack, unpack
+ return pack(">Q", unpack(">Q", R0)[0] ^ t)
+
+ def wrap(self, Q):
+ "RFC 5649 section 4.1."
+ from struct import pack
+ m = len(Q) # Plaintext length
+ if m % 8 != 0: # Pad Q if needed
+ Q += "\x00" * (8 - (m % 8))
+ R = [pack(">LL", 0xa65959a6, m)] # Magic MSB(32,A), build LSB(32,A)
+ R.extend(Q[i : i + 8] # Append Q
+ for i in xrange(0, len(Q), 8))
+ n = len(R) - 1
+ if n == 1:
+ R[0], R[1] = self._encrypt(R[0], R[1])
+ else:
+ # RFC 3394 section 2.2.1
+ for j in self._start_stop(0, 5):
+ for i in self._start_stop(1, n):
+ R[0], R[i] = self._encrypt(R[0], R[i])
+ R[0] = self._xor(R[0], n * j + i)
+ assert len(R) == (n + 1) and all(len(r) == 8 for r in R)
+ return "".join(R)
+
+ def unwrap(self, C):
+ "RFC 5649 section 4.2."
+ from struct import unpack
+ if len(C) % 8 != 0:
+ raise self.UnwrapError("Ciphertext length {} is not an integral number of blocks"
+ .format(len(C)))
+ n = (len(C) / 8) - 1
+ R = [C[i : i + 8] for i in xrange(0, len(C), 8)]
+ if n == 1:
+ R[0], R[1] = self._decrypt(R[0], R[1])
+ else:
+ # RFC 3394 section 2.2.2 steps (1), (2), and part of (3)
+ for j in self._start_stop(5, 0):
+ for i in self._start_stop(n, 1):
+ R[0] = self._xor(R[0], n * j + i)
+ R[0], R[i] = self._decrypt(R[0], R[i])
+ magic, m = unpack(">LL", R[0])
+ if magic != 0xa65959a6:
+ raise self.UnwrapError("Magic value in AIV should have been 0xa65959a6, was 0x{:02x}"
+ .format(magic))
+ if m <= 8 * (n - 1) or m > 8 * n:
+ raise self.UnwrapError("Length encoded in AIV out of range: m {}, n {}".format(m, n))
+ R = "".join(R[1:])
+ assert len(R) == 8 * n
+ if any(r != "\x00" for r in R[m:]):
+ raise self.UnwrapError("Nonzero trailing bytes {}".format(R[m:].encode("hex")))
+ return R[:m]
+
+
+class SoftKEKEK(object):
+ """
+ Wrapper around all the goo we need to implement soft backups.
+ Requires PyCrypto on about every other line.
+ """
+
+ oid_aesKeyWrap = "\x60\x86\x48\x01\x65\x03\x04\x01\x30"
+
+ def parse_EncryptedPrivateKeyInfo(self, der):
+ from Crypto.Util.asn1 import DerObject, DerSequence, DerOctetString, DerObjectId
+ encryptedPrivateKeyInfo = DerSequence()
+ encryptedPrivateKeyInfo.decode(der)
+ encryptionAlgorithm = DerSequence()
+ algorithm = DerObjectId()
+ encryptedData = DerOctetString()
+ encryptionAlgorithm.decode(encryptedPrivateKeyInfo[0])
+ DerObject.decode(algorithm, encryptionAlgorithm[0])
+ DerObject.decode(encryptedData, encryptedPrivateKeyInfo[1])
+ if algorithm.payload != self.oid_aesKeyWrap:
+ raise ValueError
+ return encryptedData.payload
+
+ def encode_EncryptedPrivateKeyInfo(self, der):
+ from Crypto.Util.asn1 import DerSequence, DerOctetString
+ return DerSequence([
+ DerSequence([
+ chr(0x06) + chr(len(self.oid_aesKeyWrap)) + self.oid_aesKeyWrap
+ ]).encode(),
+ DerOctetString(der).encode()
+ ]).encode()
+
+ def gen_salt(self, bytes = 16):
+ from Crypto import Random
+ return Random.new().read(bytes)
+
+ def wrapper(self, salt, keylen = 256, iterations = 8000):
+ from Crypto.Protocol.KDF import PBKDF2
+ from Crypto.Hash import SHA256, HMAC
+ return AESKeyWrapWithPadding(PBKDF2(
+ password = getpass.getpass("KEKEK Passphrase: "),
+ salt = salt,
+ dkLen = keylen/8,
+ count = iterations,
+ prf = lambda p, s: HMAC.new(p, s, SHA256).digest()))
+
+ @classmethod
+ def is_soft_key(cls, db):
+ return all(k in db for k in ("kekek_pkcs8", "kekek_salt"))
+
+ @classmethod
+ def generate(cls, args, result):
+ from Crypto.PublicKey import RSA
+ self = cls()
+ k = RSA.generate(args.keylen)
+ salt = self.gen_salt()
+ spki = k.publickey().exportKey(format = "DER")
+ pkcs8 = self.encode_EncryptedPrivateKeyInfo(self.wrapper(salt).wrap(
+ k.exportKey(format = "DER", pkcs = 8)))
+ result.update(kekek_salt = b64(salt),
+ kekek_pkcs8 = b64(pkcs8),
+ kekek_pubkey = b64(spki))
+
+ @classmethod
+ def recover(cls, db):
+ self = cls()
+ return self.wrapper(b64join(db["kekek_salt"])).unwrap(
+ self.parse_EncryptedPrivateKeyInfo(b64join(db["kekek_pkcs8"])))
+
if __name__ == "__main__":
main()
diff --git a/cryptech_muxd b/cryptech_muxd
index d5de227..d306eaf 100755
--- a/cryptech_muxd
+++ b/cryptech_muxd
@@ -58,6 +58,8 @@ import tornado.queues
import tornado.locks
import tornado.gen
+from cryptech.libhal import HAL_OK, RPC_FUNC_GET_VERSION, RPC_FUNC_LOGOUT, RPC_FUNC_LOGOUT_ALL
+
logger = logging.getLogger("cryptech_muxd")
@@ -89,6 +91,10 @@ def client_handle_set(msg, handle):
return msg[:4] + struct.pack(">L", handle) + msg[8:]
+logout_msg = struct.pack(">LL", RPC_FUNC_LOGOUT, 0)
+logout_all_msg = struct.pack(">LL", RPC_FUNC_LOGOUT_ALL, 0)
+
+
class SerialIOStream(tornado.iostream.BaseIOStream):
"""
Implementation of a Tornado IOStream over a PySerial device.
@@ -157,10 +163,11 @@ class RPCIOStream(SerialIOStream):
self.rpc_input_lock = tornado.locks.Lock()
@tornado.gen.coroutine
- def rpc_input(self, query, handle, queue):
+ def rpc_input(self, query, handle = 0, queue = None):
"Send a query to the HSM."
logger.debug("RPC send: %s", ":".join("{:02x}".format(ord(c)) for c in query))
- self.queues[handle] = queue
+ if queue is not None:
+ self.queues[handle] = queue
with (yield self.rpc_input_lock.acquire()):
yield self.write(query)
logger.debug("RPC sent")
@@ -182,13 +189,18 @@ class RPCIOStream(SerialIOStream):
continue
try:
handle = client_handle_get(slip_decode(reply))
- queue = self.queues[handle]
except:
logger.debug("RPC skipping bad packet")
continue
- logger.debug("RPC queue put: handle 0x%x, qsize %s, maxsize %s",
- handle, queue.qsize(), queue.maxsize)
- queue.put_nowait(reply)
+ if handle not in self.queues:
+ logger.debug("RPC ignoring response: handle 0x%x", handle)
+ continue
+ logger.debug("RPC queue put: handle 0x%x, qsize %s", handle, self.queues[handle].qsize())
+ self.queues[handle].put_nowait(reply)
+
+ def logout_all(self):
+ "Execute an RPC LOGOUT_ALL operation."
+ return self.rpc_input(slip_encode(logout_all_msg))
class QueuedStreamClosedError(tornado.iostream.StreamClosedError):
@@ -203,7 +215,7 @@ class RPCServer(PFUnixServer):
@tornado.gen.coroutine
def handle_stream(self, stream, address):
"Handle one network connection."
- handle = stream.socket.fileno()
+ handle = self.next_client_handle()
queue = tornado.queues.Queue()
logger.info("RPC connected %r, handle 0x%x", stream, handle)
while True:
@@ -223,8 +235,18 @@ class RPCServer(PFUnixServer):
except tornado.iostream.StreamClosedError:
logger.info("RPC closing %r, handle 0x%x", stream, handle)
stream.close()
+ query = slip_encode(client_handle_set(logout_msg, handle))
+ yield self.serial.rpc_input(query, handle)
return
+ client_handle = int(time.time()) << 4
+
+ @classmethod
+ def next_client_handle(cls):
+ cls.client_handle += 1
+ cls.client_handle &= 0xFFFFFFFF
+ return cls.client_handle
+
class CTYIOStream(SerialIOStream):
"""
@@ -331,8 +353,8 @@ class ProbeIOStream(SerialIOStream):
@tornado.gen.coroutine
def run_probe(self):
- RPC_query = chr(0) * 8 # client_handle = 0, function code = RPC_FUNC_GET_VERSION
- RPC_reply = chr(0) * 12 # opcode = RPC_FUNC_GET_VERSION, client_handle = 0, valret = HAL_OK
+ RPC_query = struct.pack(">LL", RPC_FUNC_GET_VERSION, 0)
+ RPC_reply = struct.pack(">LLL", RPC_FUNC_GET_VERSION, 0, HAL_OK)
probe_string = SLIP_END + Control_U + SLIP_END + RPC_query + SLIP_END + Control_U + Control_M
@@ -434,6 +456,7 @@ def main():
rpc_stream = RPCIOStream(device = args.rpc_device)
rpc_server = RPCServer(rpc_stream, args.rpc_socket)
futures.append(rpc_stream.rpc_output_loop())
+ futures.append(rpc_stream.logout_all())
if args.cty_device is None:
logger.warn("No CTY device found")
diff --git a/ecdsa.c b/ecdsa.c
index b9b14d8..d1b8d0c 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -199,7 +199,7 @@ const size_t hal_ecdsa_key_t_size = sizeof(struct hal_ecdsa_key);
* first time anything asks for any of them.
*/
-static const ecdsa_curve_t * const get_curve(const hal_curve_name_t curve)
+static const ecdsa_curve_t * get_curve(const hal_curve_name_t curve)
{
static ecdsa_curve_t curve_p256, curve_p384, curve_p521;
static int initialized = 0;
@@ -806,18 +806,18 @@ static hal_error_t verilog_point_pick_random(const verilog_ecdsa_driver_t * cons
memset(b, 0, sizeof(b));
fp_to_unsigned_bin(k, b + sizeof(b) - len);
- for (int i = 0; i < sizeof(b); i += 4)
+ for (size_t i = 0; i < sizeof(b); i += 4)
check(hal_io_write(core, driver->k_addr + i/4, &b[sizeof(b) - 4 - i], 4));
check(hal_io_write(core, ADDR_CTRL, zero, sizeof(zero)));
check(hal_io_next(core));
check(hal_io_wait_valid(core));
- for (int i = 0; i < sizeof(b); i += 4)
+ for (size_t i = 0; i < sizeof(b); i += 4)
check(hal_io_read(core, driver->x_addr + i/4, &b[sizeof(b) - 4 - i], 4));
fp_read_unsigned_bin(P->x, b, sizeof(b));
- for (int i = 0; i < sizeof(b); i += 4)
+ for (size_t i = 0; i < sizeof(b); i += 4)
check(hal_io_read(core, driver->y_addr + i/4, &b[sizeof(b) - 4 - i], 4));
fp_read_unsigned_bin(P->y, b, sizeof(b));
@@ -970,7 +970,7 @@ static int point_is_on_curve(const ec_point_t * const P,
* Generate a new ECDSA key.
*/
-hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
+hal_error_t hal_ecdsa_key_gen(hal_core_t *core,
hal_ecdsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const hal_curve_name_t curve_)
@@ -1422,7 +1422,7 @@ hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_,
if ((err = hal_asn1_decode_header(ASN1_EXPLICIT_1, d, der_end - d, &hlen, &vlen)) != HAL_OK)
goto fail;
d += hlen;
- if (vlen > der_end - d)
+ if (vlen > (size_t)(der_end - d))
lose(HAL_ERROR_ASN1_PARSE_FAILED);
if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, vlen, &hlen, &vlen)) != HAL_OK)
goto fail;
@@ -1530,7 +1530,7 @@ hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_key_t **key_,
memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) != 0 ||
hal_ecdsa_oid_to_curve(&key->curve, curve_oid, curve_oid_len) != HAL_OK ||
pubkey_len < 3 || (pubkey_len & 1) == 0 || pubkey[0] != 0x04 ||
- pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(get_curve(key->curve)->q)))
+ pubkey_len / 2 != (size_t)(fp_unsigned_bin_size(unconst_fp_int(get_curve(key->curve)->q))))
return HAL_ERROR_ASN1_PARSE_FAILED;
const uint8_t * const Qx = pubkey + 1;
@@ -1596,7 +1596,7 @@ static hal_error_t decode_signature_pkcs11(const ecdsa_curve_t * const curve,
const size_t n_len = signature_len / 2;
- if (n_len > fp_unsigned_bin_size(unconst_fp_int(curve->n)))
+ if (n_len > (size_t)(fp_unsigned_bin_size(unconst_fp_int(curve->n))))
return HAL_ERROR_BAD_ARGUMENTS;
fp_read_unsigned_bin(r, unconst_uint8_t(signature) + 0 * n_len, n_len);
@@ -1609,7 +1609,7 @@ static hal_error_t decode_signature_pkcs11(const ecdsa_curve_t * const curve,
* Sign a caller-supplied hash.
*/
-hal_error_t hal_ecdsa_sign(const hal_core_t *core,
+hal_error_t hal_ecdsa_sign(hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
uint8_t *signature, size_t *signature_len, const size_t signature_max)
@@ -1690,7 +1690,7 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core,
* Verify a signature using a caller-supplied hash.
*/
-hal_error_t hal_ecdsa_verify(const hal_core_t *core,
+hal_error_t hal_ecdsa_verify(hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
const uint8_t * const signature, const size_t signature_len)
diff --git a/hal.h b/hal.h
index abcaf52..8797a4f 100644
--- a/hal.h
+++ b/hal.h
@@ -157,13 +157,11 @@
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_KS_INDEX_UUID_MISORDERED, "Key index UUID misordered") \
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") \
+ DEFINE_HAL_ERROR(HAL_ERROR_HASHSIG_KEY_EXHAUSTED, "Key exhausted") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -204,11 +202,8 @@ typedef struct hal_core hal_core_t;
extern void hal_io_set_debug(int onoff);
extern hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_t *buf, size_t len);
extern hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf, size_t len);
-extern hal_error_t hal_io_init(const hal_core_t *core);
-extern hal_error_t hal_io_next(const hal_core_t *core);
-extern hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count);
-extern hal_error_t hal_io_wait_ready(const hal_core_t *core);
-extern hal_error_t hal_io_wait_valid(const hal_core_t *core);
+extern hal_error_t hal_io_wait(const hal_core_t *core, const uint8_t status, int *count);
+extern hal_error_t hal_io_wait2(const hal_core_t *core1, const hal_core_t *core2, const uint8_t status, int *count);
/*
* Core management functions.
@@ -235,7 +230,7 @@ extern hal_error_t hal_core_alloc(const char *name, hal_core_t **core);
extern void hal_core_free(hal_core_t *core);
extern void hal_critical_section_start(void);
extern void hal_critical_section_end(void);
-extern const int hal_core_busy(const hal_core_t *core);
+extern int hal_core_busy(const hal_core_t *core);
/*
* Slightly higher level public API, still working directly with cores.
@@ -375,16 +370,25 @@ extern hal_error_t hal_pbkdf2(hal_core_t *core,
unsigned iterations_desired);
/*
- * Modular exponentiation.
+ * Modular exponentiation. This takes a ridiculous number of
+ * arguments of very similar types, making it easy to confuse them,
+ * particularly when performing two modexp operations in parallel, so
+ * we encapsulate the arguments in a structure.
*/
-extern void hal_modexp_set_debug(const int onoff);
+typedef struct {
+ hal_core_t *core;
+ const uint8_t *msg; size_t msg_len; /* Message */
+ const uint8_t *exp; size_t exp_len; /* Exponent */
+ const uint8_t *mod; size_t mod_len; /* Modulus */
+ uint8_t *result; size_t result_len; /* Result of exponentiation */
+ uint8_t *coeff; size_t coeff_len; /* Modulus coefficient (r/w) */
+ uint8_t *mont; size_t mont_len; /* Montgomery factor (r/w)*/
+} hal_modexp_arg_t;
-extern hal_error_t hal_modexp(hal_core_t *core,
- const uint8_t * const msg, const size_t msg_len, /* Message */
- const uint8_t * const exp, const size_t exp_len, /* Exponent */
- const uint8_t * const mod, const size_t mod_len, /* Modulus */
- uint8_t * result, const size_t result_len);
+extern void hal_modexp_set_debug(const int onoff);
+extern hal_error_t hal_modexp( const int precalc, hal_modexp_arg_t *args);
+extern hal_error_t hal_modexp2(const int precalc, hal_modexp_arg_t *args1, hal_modexp_arg_t *args2);
/*
* Master Key Memory Interface
@@ -408,7 +412,11 @@ typedef enum {
HAL_KEY_TYPE_RSA_PRIVATE,
HAL_KEY_TYPE_RSA_PUBLIC,
HAL_KEY_TYPE_EC_PRIVATE,
- HAL_KEY_TYPE_EC_PUBLIC
+ HAL_KEY_TYPE_EC_PUBLIC,
+ HAL_KEY_TYPE_HASHSIG_PRIVATE,
+ HAL_KEY_TYPE_HASHSIG_PUBLIC,
+ HAL_KEY_TYPE_HASHSIG_LMS,
+ HAL_KEY_TYPE_HASHSIG_LMOTS,
} hal_key_type_t;
typedef enum {
@@ -461,17 +469,18 @@ extern hal_error_t hal_rsa_key_get_public_exponent(const hal_rsa_key_t * const k
extern void hal_rsa_key_clear(hal_rsa_key_t *key);
-extern hal_error_t hal_rsa_encrypt(const hal_core_t *core,
- const hal_rsa_key_t * const key,
+extern hal_error_t hal_rsa_encrypt(hal_core_t *core,
+ hal_rsa_key_t *key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len);
-extern hal_error_t hal_rsa_decrypt(const hal_core_t *core,
- const hal_rsa_key_t * const key,
+extern hal_error_t hal_rsa_decrypt(hal_core_t *core1,
+ hal_core_t *core2,
+ hal_rsa_key_t *key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len);
-extern hal_error_t hal_rsa_key_gen(const hal_core_t *core,
+extern hal_error_t hal_rsa_key_gen(hal_core_t *core,
hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const unsigned key_length,
@@ -480,7 +489,8 @@ extern hal_error_t hal_rsa_key_gen(const hal_core_t *core,
extern hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key,
uint8_t *der, size_t *der_len, const size_t der_max);
-extern size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key);
+extern hal_error_t hal_rsa_private_key_to_der_extra(const hal_rsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
extern hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
@@ -495,6 +505,20 @@ extern hal_error_t hal_rsa_public_key_from_der(hal_rsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len);
+extern int hal_rsa_key_needs_saving(const hal_rsa_key_t * const key);
+
+static inline size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key)
+{
+ size_t len = 0;
+ return hal_rsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+static inline size_t hal_rsa_private_key_to_der_extra_len(const hal_rsa_key_t * const key)
+{
+ size_t len = 0;
+ return hal_rsa_private_key_to_der_extra(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
/*
* ECDSA.
*/
@@ -534,7 +558,7 @@ extern hal_error_t hal_ecdsa_key_get_public(const hal_ecdsa_key_t * const key,
extern void hal_ecdsa_key_clear(hal_ecdsa_key_t *key);
-extern hal_error_t hal_ecdsa_key_gen(const hal_core_t *core,
+extern hal_error_t hal_ecdsa_key_gen(hal_core_t *core,
hal_ecdsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const hal_curve_name_t curve);
@@ -567,12 +591,12 @@ extern hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key,
const uint8_t * const der, const size_t der_len,
const hal_curve_name_t curve);
-extern hal_error_t hal_ecdsa_sign(const hal_core_t *core,
+extern hal_error_t hal_ecdsa_sign(hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
uint8_t *signature, size_t *signature_len, const size_t signature_max);
-extern hal_error_t hal_ecdsa_verify(const hal_core_t *core,
+extern hal_error_t hal_ecdsa_verify(hal_core_t *core,
const hal_ecdsa_key_t * const key,
const uint8_t * const hash, const size_t hash_len,
const uint8_t * const signature, const size_t signature_len);
@@ -773,6 +797,18 @@ extern hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
const hal_curve_name_t curve,
const hal_key_flags_t flags);
+typedef enum lmots_algorithm_type lmots_algorithm_t;
+typedef enum lms_algorithm_type lms_algorithm_t;
+
+extern hal_error_t hal_rpc_pkey_generate_hashsig(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const hal_key_flags_t flags);
+
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);
diff --git a/hal_internal.h b/hal_internal.h
index 461feec..b698611 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -48,7 +48,7 @@
*/
/*
- * htonl is not available in arm-none-eabi headers or libc.
+ * htonl and htons are not available in arm-none-eabi headers or libc.
*/
#ifndef STM32F4XX
#include <arpa/inet.h>
@@ -62,25 +62,80 @@ inline uint32_t htonl(uint32_t w)
((w & 0x00ff0000) >> 8) +
((w & 0xff000000) >> 24);
}
+inline uint16_t htons(uint16_t w)
+{
+ return
+ ((w & 0x00ff) << 8) +
+ ((w & 0xff00) >> 8);
+}
#else /* big endian */
#define htonl(x) (x)
+#define htons(x) (x)
#endif
#define ntohl htonl
+#define ntohs htons
#endif
/*
+ * Low-level I/O convenience functions, moved here from hal.h
+ * because they use symbols defined in verilog_constants.h.
+ */
+
+static inline hal_error_t hal_io_zero(const hal_core_t *core)
+{
+ const uint8_t buf[4] = { 0, 0, 0, 0 };
+ return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
+}
+
+static inline hal_error_t hal_io_init(const hal_core_t *core)
+{
+ const uint8_t buf[4] = { 0, 0, 0, CTRL_INIT };
+ return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
+}
+
+static inline hal_error_t hal_io_next(const hal_core_t *core)
+{
+ const uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT };
+ return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
+}
+
+static inline hal_error_t hal_io_wait_ready(const hal_core_t *core)
+{
+ int limit = -1;
+ return hal_io_wait(core, STATUS_READY, &limit);
+}
+
+static inline hal_error_t hal_io_wait_valid(const hal_core_t *core)
+{
+ int limit = -1;
+ return hal_io_wait(core, STATUS_VALID, &limit);
+}
+
+static inline hal_error_t hal_io_wait_ready2(const hal_core_t *core1, const hal_core_t *core2)
+{
+ int limit = -1;
+ return hal_io_wait2(core1, core2, STATUS_READY, &limit);
+}
+
+static inline hal_error_t hal_io_wait_valid2(const hal_core_t *core1, const hal_core_t *core2)
+{
+ int limit = -1;
+ return hal_io_wait2(core1, core2, STATUS_VALID, &limit);
+}
+
+/*
* 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).
+ * really necessary. Intent is just to allow allocation of 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);
+extern hal_error_t hal_free_static_memory(const void * const ptr);
/*
* Longest hash block and digest we support at the moment.
@@ -235,6 +290,15 @@ typedef struct {
const hal_curve_name_t curve,
const hal_key_flags_t flags);
+ hal_error_t (*generate_hashsig)(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const hal_key_flags_t flags);
+
hal_error_t (*close)(const hal_pkey_handle_t pkey);
hal_error_t (*delete)(const hal_pkey_handle_t pkey);
@@ -360,18 +424,17 @@ static inline hal_crc32_t hal_crc32_finalize(hal_crc32_t crc)
* EC P-384: 185 bytes
* EC P-521: 240 bytes
*
+ * Plus extra space for pre-computed speed-up factors specific to our
+ * Verilog implementation, which we store as fixed-length byte strings.
+ *
* Plus we need a bit of AES-keywrap overhead, since we're storing the
* wrapped form (see hal_aes_keywrap_cyphertext_length()).
*
- * 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.
+ * Length check warning moved to ks.h since size of keystore blocks is
+ * internal to the keystore implementation.
*/
-#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 15) & ~7)
+#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7)
/*
* PINs.
@@ -398,8 +461,6 @@ extern hal_error_t hal_get_pin(const hal_user_t user,
extern hal_error_t hal_set_pin(const hal_user_t user,
const hal_ks_pin_t * const pin);
-extern void hal_ks_init_read_only_pins_only(void);
-
/*
* Master key memory (MKM) and key-encryption-key (KEK).
*
@@ -435,6 +496,12 @@ extern hal_error_t hal_mkm_flash_erase(const size_t len);
#endif
/*
+ * Clean up pkey stuff that's tied to a particular client on logout.
+ */
+
+extern hal_error_t hal_pkey_logout(const hal_client_handle_t client);
+
+/*
* Keystore API for use by the pkey implementation.
*
* In an attempt to emulate what current theory says will eventually
@@ -452,9 +519,9 @@ extern hal_error_t hal_mkm_flash_erase(const size_t len);
*/
typedef struct {
- hal_client_handle_t client_handle;
- hal_session_handle_t session_handle;
- hal_pkey_handle_t pkey_handle;
+ hal_client_handle_t client;
+ hal_session_handle_t session;
+ hal_pkey_handle_t pkey;
hal_key_type_t type;
hal_curve_name_t curve;
hal_key_flags_t flags;
@@ -474,377 +541,63 @@ typedef struct {
*/
} hal_pkey_slot_t;
-typedef struct hal_ks_driver hal_ks_driver_t;
+/*
+ * Keystore is an opaque type, we just pass pointers.
+ */
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);
-
- hal_error_t (*shutdown)(const hal_ks_driver_t * const driver);
-
- hal_error_t (*open)(const hal_ks_driver_t * const driver,
- hal_ks_t **ks);
-
- hal_error_t (*close)(hal_ks_t *ks);
-
- hal_error_t (*store)(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- const uint8_t * const der, const size_t der_len);
-
- hal_error_t (*fetch)(hal_ks_t *ks,
- hal_pkey_slot_t *slot,
- uint8_t *der, size_t *der_len, const size_t der_max);
+extern hal_ks_t * const hal_ks_token;
+extern hal_ks_t * const hal_ks_volatile;
- hal_error_t (*delete)(hal_ks_t *ks,
- hal_pkey_slot_t *slot);
+extern hal_error_t hal_ks_init(hal_ks_t *ks,
+ const int alloc);
- 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 mask,
- 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 void hal_ks_init_read_only_pins_only(void);
- hal_error_t (*set_attributes)(hal_ks_t *ks,
+extern hal_error_t hal_ks_store(hal_ks_t *ks,
hal_pkey_slot_t *slot,
- const hal_pkey_attribute_t *attributes,
- const unsigned attributes_len);
+ const uint8_t * const der, const size_t der_len);
- hal_error_t (*get_attributes)(hal_ks_t *ks,
+extern hal_error_t hal_ks_fetch(hal_ks_t *ks,
hal_pkey_slot_t *slot,
- hal_pkey_attribute_t *attributes,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern hal_error_t hal_ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot);
+
+extern 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 mask,
+ const hal_key_flags_t flags,
+ const 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 mask,
- 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, mask, 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 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_uuid_t *result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid);
+
+extern 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);
+
+extern 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,
- 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);
+ uint8_t *attributes_buffer,
+ const size_t attributes_buffer_len);
+
+extern hal_error_t hal_ks_logout(hal_ks_t *ks,
+ const hal_client_handle_t client);
+
+extern hal_error_t hal_ks_rewrite_der(hal_ks_t *ks,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len);
/*
* RPC lowest-level send and receive routines. These are blocking, and
@@ -900,9 +653,10 @@ typedef enum {
RPC_FUNC_PKEY_GET_ATTRIBUTES,
RPC_FUNC_PKEY_EXPORT,
RPC_FUNC_PKEY_IMPORT,
+ RPC_FUNC_PKEY_GENERATE_HASHSIG,
} rpc_func_num_t;
-#define RPC_VERSION 0x01010000 /* 1.1.0.0 */
+#define RPC_VERSION 0x01010100 /* 1.1.1.0 */
/*
* RPC client locality. These have to be defines rather than an enum,
@@ -919,7 +673,7 @@ typedef enum {
*/
#ifndef HAL_RPC_MAX_PKT_SIZE
-#define HAL_RPC_MAX_PKT_SIZE 4096
+#define HAL_RPC_MAX_PKT_SIZE 16384
#endif
/*
diff --git a/hal_io.c b/hal_io.c
new file mode 100644
index 0000000..f885712
--- /dev/null
+++ b/hal_io.c
@@ -0,0 +1,114 @@
+/*
+ * hal_io.c
+ * --------
+ * This module contains common code to talk to the FPGA over the bus du jour.
+ *
+ * Author: Paul Selkirk, Rob Austein
+ * Copyright (c) 2014-2017, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+#ifndef HAL_IO_TIMEOUT
+#define HAL_IO_TIMEOUT 100000000
+#endif
+
+static inline hal_error_t test_status(const hal_core_t *core,
+ const uint8_t status,
+ int *done)
+{
+ if (done == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (*done || core == NULL)
+ return HAL_OK;
+
+ uint8_t buf[4];
+
+ const hal_error_t err = hal_io_read(core, ADDR_STATUS, buf, sizeof(buf));
+
+ if (err == HAL_OK)
+ *done = (buf[3] & status) != 0;
+
+ return err;
+}
+
+hal_error_t hal_io_wait2(const hal_core_t *core1,
+ const hal_core_t *core2,
+ const uint8_t status,
+ int *count)
+{
+ int done1 = 0, done2 = 0;
+ hal_error_t err;
+
+ if (core1 == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (core2 == NULL)
+ done2 = 1;
+
+ if (count && *count == -1)
+ *count = HAL_IO_TIMEOUT;
+
+ for (int i = 1; ; ++i) {
+
+ if (count && (*count > 0) && (i >= *count))
+ return HAL_ERROR_IO_TIMEOUT;
+
+ hal_task_yield();
+
+ if ((err = test_status(core1, status, &done1)) != HAL_OK ||
+ (err = test_status(core2, status, &done2)) != HAL_OK)
+ return err;
+
+ if (done1 && done2) {
+ if (count)
+ *count = i;
+ return HAL_OK;
+ }
+ }
+}
+
+hal_error_t hal_io_wait(const hal_core_t *core,
+ const uint8_t status,
+ int *count)
+{
+ return hal_io_wait2(core, NULL, status, count);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/hal_io_eim.c b/hal_io_eim.c
index 5824f5b..040cb2b 100644
--- a/hal_io_eim.c
+++ b/hal_io_eim.c
@@ -43,11 +43,7 @@
static int debug = 0;
static int inited = 0;
-#ifndef EIM_IO_TIMEOUT
-#define EIM_IO_TIMEOUT 100000000
-#endif
-
-static hal_error_t init(void)
+static inline hal_error_t init(void)
{
if (inited)
return HAL_OK;
@@ -61,7 +57,7 @@ static hal_error_t init(void)
/* translate cryptech register number to EIM address
*/
-static hal_addr_t eim_offset(hal_addr_t offset)
+static inline hal_addr_t eim_offset(hal_addr_t offset)
{
return EIM_BASE_ADDR + (offset << 2);
}
@@ -134,52 +130,6 @@ hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf,
return HAL_OK;
}
-hal_error_t hal_io_init(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_INIT };
- return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
-}
-
-hal_error_t hal_io_next(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT };
- return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
-}
-
-hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count)
-{
- hal_error_t err;
- uint8_t buf[4];
- int i;
-
- for (i = 1; ; ++i) {
-
- if (count && (*count > 0) && (i >= *count))
- return HAL_ERROR_IO_TIMEOUT;
-
- if ((err = hal_io_read(core, ADDR_STATUS, buf, sizeof(buf))) != HAL_OK)
- return err;
-
- if ((buf[3] & status) != 0) {
- if (count)
- *count = i;
- return HAL_OK;
- }
- }
-}
-
-hal_error_t hal_io_wait_ready(const hal_core_t *core)
-{
- int limit = EIM_IO_TIMEOUT;
- return hal_io_wait(core, STATUS_READY, &limit);
-}
-
-hal_error_t hal_io_wait_valid(const hal_core_t *core)
-{
- int limit = EIM_IO_TIMEOUT;
- return hal_io_wait(core, STATUS_VALID, &limit);
-}
-
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/hal_io_fmc.c b/hal_io_fmc.c
index 76d6883..0d49f1e 100644
--- a/hal_io_fmc.c
+++ b/hal_io_fmc.c
@@ -47,11 +47,7 @@
static int debug = 0;
static int inited = 0;
-#ifndef FMC_IO_TIMEOUT
-#define FMC_IO_TIMEOUT 100000000
-#endif
-
-static hal_error_t init(void)
+static inline hal_error_t init(void)
{
if (!inited) {
fmc_init();
@@ -62,7 +58,7 @@ static hal_error_t init(void)
/* Translate cryptech register number to FMC address.
*/
-static hal_addr_t fmc_offset(hal_addr_t offset)
+static inline hal_addr_t fmc_offset(hal_addr_t offset)
{
return offset << 2;
}
@@ -136,54 +132,6 @@ hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf,
return HAL_OK;
}
-hal_error_t hal_io_init(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_INIT };
- return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
-}
-
-hal_error_t hal_io_next(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT };
- return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf));
-}
-
-hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count)
-{
- hal_error_t err;
- uint8_t buf[4];
- int i;
-
- for (i = 1; ; ++i) {
-
- if (count && (*count > 0) && (i >= *count))
- return HAL_ERROR_IO_TIMEOUT;
-
- hal_task_yield();
-
- if ((err = hal_io_read(core, ADDR_STATUS, buf, sizeof(buf))) != HAL_OK)
- return err;
-
- if ((buf[3] & status) != 0) {
- if (count)
- *count = i;
- return HAL_OK;
- }
- }
-}
-
-hal_error_t hal_io_wait_ready(const hal_core_t *core)
-{
- int limit = FMC_IO_TIMEOUT;
- return hal_io_wait(core, STATUS_READY, &limit);
-}
-
-hal_error_t hal_io_wait_valid(const hal_core_t *core)
-{
- int limit = FMC_IO_TIMEOUT;
- return hal_io_wait(core, STATUS_VALID, &limit);
-}
-
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/hal_io_i2c.c b/hal_io_i2c.c
index e7dbbb6..8596174 100644
--- a/hal_io_i2c.c
+++ b/hal_io_i2c.c
@@ -301,53 +301,6 @@ hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf,
return HAL_OK;
}
-hal_error_t hal_io_init(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_INIT };
- return hal_io_write(core, ADDR_CTRL, buf, 4);
-}
-
-hal_error_t hal_io_next(const hal_core_t *core)
-{
- uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT };
- return hal_io_write(core, ADDR_CTRL, buf, 4);
-}
-
-hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count)
-{
- hal_error_t err;
- uint8_t buf[4];
- int i;
-
- for (i = 1; ; ++i) {
-
- if (count && (*count > 0) && (i >= *count))
- return HAL_ERROR_IO_TIMEOUT;
-
- if ((err = hal_io_read(core, ADDR_STATUS, buf, 4)) != HAL_OK)
- return err;
-
- if (buf[3] & status) {
- if (count)
- *count = i;
- return HAL_OK;
-
- }
- }
-}
-
-hal_error_t hal_io_wait_ready(const hal_core_t *core)
-{
- int limit = 10;
- return hal_io_wait(core, STATUS_READY, &limit);
-}
-
-hal_error_t hal_io_wait_valid(const hal_core_t *core)
-{
- int limit = 10;
- return hal_io_wait(core, STATUS_VALID, &limit);
-}
-
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/hash.c b/hash.c
index 2c745a8..d1e55ff 100644
--- a/hash.c
+++ b/hash.c
@@ -302,7 +302,7 @@ static inline hal_hash_state_t *alloc_static_hash_state(void)
#if HAL_STATIC_HASH_STATE_BLOCKS > 0
- for (int i = 0; i < sizeof(static_hash_state)/sizeof(*static_hash_state); i++)
+ for (size_t i = 0; i < sizeof(static_hash_state)/sizeof(*static_hash_state); i++)
if ((static_hash_state[i].flags & STATE_FLAG_STATE_ALLOCATED) == 0)
return &static_hash_state[i];
@@ -316,7 +316,7 @@ static inline hal_hmac_state_t *alloc_static_hmac_state(void)
#if HAL_STATIC_HMAC_STATE_BLOCKS > 0
- for (int i = 0; i < sizeof(static_hmac_state)/sizeof(*static_hmac_state); i++)
+ for (size_t i = 0; i < sizeof(static_hmac_state)/sizeof(*static_hmac_state); i++)
if ((static_hmac_state[i].hash_state.flags & STATE_FLAG_STATE_ALLOCATED) == 0)
return &static_hmac_state[i];
@@ -347,8 +347,8 @@ static inline void swytebop(void *out_, const void * const in_, const size_t n,
return;
case 0x04030201:
- for (int i = 0; i < n; i += w)
- for (int j = 0; j < w && i + j < n; j++)
+ for (size_t i = 0; i < n; i += w)
+ for (size_t j = 0; j < w && i + j < n; j++)
out[i + j] = in[i + w - j - 1];
return;
@@ -443,10 +443,7 @@ hal_error_t hal_hash_initialize(hal_core_t *core,
state->descriptor = descriptor;
state->driver = driver;
state->core = core;
- state->flags = flags;
-
- if (state_buffer == NULL)
- state->flags |= STATE_FLAG_STATE_ALLOCATED;
+ state->flags = flags | STATE_FLAG_STATE_ALLOCATED;
*state_ = state;
@@ -650,7 +647,7 @@ hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaqu
hal_error_t err;
uint8_t *p;
size_t n;
- int i;
+ size_t i;
if (state == NULL || digest_buffer == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -748,7 +745,7 @@ hal_error_t hal_hmac_initialize(hal_core_t *core,
const hal_hash_driver_t * const driver = check_driver(descriptor);
hal_hmac_state_t *state = state_buffer;
hal_error_t err;
- int i;
+ size_t i;
if (descriptor == NULL || driver == NULL || state_ == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -777,9 +774,6 @@ hal_error_t hal_hmac_initialize(hal_core_t *core,
sizeof(state->hash_state))) != HAL_OK)
goto fail;
- if (state_buffer == NULL)
- h->flags |= STATE_FLAG_STATE_ALLOCATED;
-
/*
* If the supplied HMAC key is longer than the hash block length, we
* need to hash the supplied HMAC key to get the real HMAC key.
diff --git a/hashsig.c b/hashsig.c
new file mode 100644
index 0000000..0396ff7
--- /dev/null
+++ b/hashsig.c
@@ -0,0 +1,2058 @@
+/*
+ * hashsig.c
+ * ---------
+ * Implementation of draft-mcgrew-hash-sigs-10.txt
+ *
+ * Copyright (c) 2018, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hal.h"
+#include "hashsig.h"
+#include "ks.h"
+#include "asn1_internal.h"
+#include "xdr_internal.h"
+
+typedef struct { uint8_t bytes[32]; } bytestring32;
+typedef struct { uint8_t bytes[16]; } bytestring16;
+
+#define D_PBLC 0x8080
+#define D_MESG 0x8181
+#define D_LEAF 0x8282
+#define D_INTR 0x8383
+
+#define u32str(X) htonl(X)
+#define u16str(X) htons(X)
+#define u8str(X) (X & 0xff)
+
+#define check(op) do { hal_error_t _err = (op); if (_err != HAL_OK) return _err; } while (0)
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * XDR extensions
+ */
+
+static inline hal_error_t hal_xdr_encode_bytestring32(uint8_t ** const outbuf, const uint8_t * const limit, const bytestring32 * const value)
+{
+ return hal_xdr_encode_fixed_opaque(outbuf, limit, (const uint8_t *)value, sizeof(bytestring32));
+}
+
+static inline hal_error_t hal_xdr_decode_bytestring32_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring32 **value)
+{
+ return hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, (const uint8_t ** const)value, sizeof(bytestring32));
+}
+
+static inline hal_error_t hal_xdr_decode_bytestring32(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring32 * const value)
+{
+ return hal_xdr_decode_fixed_opaque(inbuf, limit, (uint8_t * const)value, sizeof(bytestring32));
+}
+
+static inline hal_error_t hal_xdr_encode_bytestring16(uint8_t ** const outbuf, const uint8_t * const limit, const bytestring16 *value)
+{
+ return hal_xdr_encode_fixed_opaque(outbuf, limit, (const uint8_t *)value, sizeof(bytestring16));
+}
+
+static inline hal_error_t hal_xdr_decode_bytestring16_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring16 **value)
+{
+ return hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, (const uint8_t ** const)value, sizeof(bytestring16));
+}
+
+static inline hal_error_t hal_xdr_decode_bytestring16(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring16 * const value)
+{
+ return hal_xdr_decode_fixed_opaque(inbuf, limit, (uint8_t * const)value, sizeof(bytestring16));
+}
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * ASN.1 extensions
+ */
+
+#define hal_asn1_encode_size_t(n, der, der_len, der_max) \
+ hal_asn1_encode_uint32((const uint32_t)n, der, der_len, der_max)
+
+#define hal_asn1_decode_size_t(np, der, der_len, der_max) \
+ hal_asn1_decode_uint32((uint32_t *)np, der, der_len, der_max)
+
+#define hal_asn1_encode_lms_algorithm(type, der, der_len, der_max) \
+ hal_asn1_encode_uint32((const uint32_t)type, der, der_len, der_max)
+
+#define hal_asn1_decode_lms_algorithm(type, der, der_len, der_max) \
+ hal_asn1_decode_uint32((uint32_t *)type, der, der_len, der_max)
+
+#define hal_asn1_encode_lmots_algorithm(type, der, der_len, der_max) \
+ hal_asn1_encode_uint32((const uint32_t)type, der, der_len, der_max)
+
+#define hal_asn1_decode_lmots_algorithm(type, der, der_len, der_max) \
+ hal_asn1_decode_uint32((uint32_t *)type, der, der_len, der_max)
+
+#define hal_asn1_encode_uuid(data, der, der_len, der_max) \
+ hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(hal_uuid_t), der, der_len, der_max)
+
+#define hal_asn1_decode_uuid(data, der, der_len, der_max) \
+ hal_asn1_decode_octet_string((uint8_t *)data, sizeof(hal_uuid_t), der, der_len, der_max)
+
+#define hal_asn1_encode_bytestring16(data, der, der_len, der_max) \
+ hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(bytestring16), der, der_len, der_max)
+
+#define hal_asn1_decode_bytestring16(data, der, der_len, der_max) \
+ hal_asn1_decode_octet_string((uint8_t *)data, sizeof(bytestring16), der, der_len, der_max)
+
+#define hal_asn1_encode_bytestring32(data, der, der_len, der_max) \
+ hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(bytestring32), der, der_len, der_max)
+
+#define hal_asn1_decode_bytestring32(data, der, der_len, der_max) \
+ hal_asn1_decode_octet_string((uint8_t *)data, sizeof(bytestring32), der, der_len, der_max)
+
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * LM-OTS
+ */
+
+typedef const struct lmots_parameter_set {
+ lmots_algorithm_t type;
+ size_t n, w, p, ls;
+} lmots_parameter_t;
+static lmots_parameter_t lmots_parameters[] = {
+ { lmots_sha256_n32_w1, 32, 1, 265, 7 },
+ { lmots_sha256_n32_w2, 32, 2, 133, 6 },
+ { lmots_sha256_n32_w4, 32, 4, 67, 4 },
+ { lmots_sha256_n32_w8, 32, 8, 34, 0 },
+};
+
+typedef struct lmots_key {
+ hal_key_type_t type;
+ lmots_parameter_t *lmots;
+ bytestring16 I;
+ size_t q;
+ bytestring32 * x;
+ bytestring32 K;
+} lmots_key_t;
+
+static inline lmots_parameter_t *lmots_select_parameter_set(const lmots_algorithm_t lmots_type)
+{
+ if (lmots_type < lmots_sha256_n32_w1 || lmots_type > lmots_sha256_n32_w8)
+ return NULL;
+ else
+ return &lmots_parameters[lmots_type - lmots_sha256_n32_w1];
+}
+
+static inline size_t lmots_private_key_len(lmots_parameter_t * const lmots)
+{
+ /* u32str(type) || I || u32str(q) || x[0] || x[1] || ... || x[p-1] */
+ return 2 * sizeof(uint32_t) + sizeof(bytestring16) + (lmots->p * lmots->n);
+}
+
+static inline size_t lmots_public_key_len(lmots_parameter_t * const lmots)
+{
+ /* u32str(type) || I || u32str(q) || K */
+ return 2 * sizeof(uint32_t) + sizeof(bytestring16) + lmots->n;
+}
+
+static inline size_t lmots_signature_len(lmots_parameter_t * const lmots)
+{
+ /* u32str(type) || C || y[0] || ... || y[p-1] */
+ return sizeof(uint32_t) + (lmots->p + 1) * lmots->n;
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+/* Given a key with most fields filled in, generate the lmots private and
+ * public key components (x and K).
+ * Let the caller worry about storage.
+ */
+static hal_error_t lmots_generate(lmots_key_t * const key)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMOTS || key->lmots == NULL || key->x == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+// Algorithm 0: Generating a Private Key
+
+// 3. set n and p according to the typecode and Table 1
+
+ size_t n = key->lmots->n;
+ size_t p = key->lmots->p;
+ size_t w = key->lmots->w;
+
+// 4. compute the array x as follows:
+// for ( i = 0; i < p; i = i + 1 ) {
+// set x[i] to a uniformly random n-byte string
+// }
+
+ for (size_t i = 0; i < p; ++i)
+ check(hal_rpc_get_random(&key->x[i], n));
+
+// Algorithm 1: Generating a One Time Signature Public Key From a
+// Private Key
+
+// 4. compute the string K as follows:
+
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ bytestring32 y[p];
+ uint32_t l;
+ uint16_t s;
+ uint8_t b;
+
+// for ( i = 0; i < p; i = i + 1 ) {
+ for (size_t i = 0; i < p; ++i) {
+
+// tmp = x[i]
+ bytestring32 tmp;
+ memcpy(&tmp, &key->x[i], sizeof(tmp));
+
+// for ( j = 0; j < 2^w - 1; j = j + 1 ) {
+ for (size_t j = 0; j < (1U << w) - 1; ++j) {
+
+// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp)
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(i); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ b = u8str(j); check(hal_hash_update(state, (const uint8_t *)&b, sizeof(b)));
+ check(hal_hash_update(state, (const uint8_t *)&tmp, sizeof(tmp)));
+ check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp)));
+ }
+
+// y[i] = tmp
+ memcpy(&y[i], &tmp, sizeof(tmp));
+// }
+ }
+
+// K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1])
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_PBLC); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ for (size_t i = 0; i < p; ++i)
+ check(hal_hash_update(state, (const uint8_t *)&y[i], sizeof(y[i])));
+ check(hal_hash_finalize(state, (uint8_t *)&key->K, sizeof(key->K)));
+
+ return HAL_OK;
+}
+#endif
+
+/* strings of w-bit elements */
+static uint8_t coef(const uint8_t * const S, const size_t i, size_t w)
+{
+ switch (w) {
+ case 1:
+ return (S[i/8] >> (7 - (i % 8))) & 0x01;
+ case 2:
+ return (S[i/4] >> (6 - (2 * (i % 4)))) & 0x03;
+ case 4:
+ return (S[i/2] >> (4 - (4 * (i % 2)))) & 0x0f;
+ case 8:
+ return S[i];
+ default:
+ return 0;
+ }
+}
+
+/* checksum */
+static uint16_t Cksm(const uint8_t * const S, lmots_parameter_t *lmots)
+{
+ uint16_t sum = 0;
+
+ for (size_t i = 0; i < (lmots->n * 8 / lmots->w); ++i)
+ sum += ((1 << lmots->w) - 1) - coef(S, i, lmots->w);
+
+ return (sum << lmots->ls);
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+static hal_error_t lmots_sign(lmots_key_t *key,
+ const uint8_t * const msg, const size_t msg_len,
+ uint8_t * sig, size_t *sig_len, const size_t sig_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMOTS || msg == NULL || sig == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+// Algorithm 3: Generating a One Time Signature From a Private Key and a
+// Message
+
+// 1. set type to the typecode of the algorithm
+//
+// 2. set n, p, and w according to the typecode and Table 1
+
+ size_t n = key->lmots->n;
+ size_t p = key->lmots->p;
+ size_t w = key->lmots->w;
+
+ if (sig_max < lmots_signature_len(key->lmots))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+// 3. determine x, I and q from the private key
+//
+// 4. set C to a uniformly random n-byte string
+
+ bytestring32 C;
+ check(hal_rpc_get_random(&C, n));
+
+// 5. compute the array y as follows:
+
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ uint8_t Q[n + 2]; /* hash || 16-bit checksum */
+ uint32_t l;
+ uint16_t s;
+ uint8_t b;
+
+// Q = H(I || u32str(q) || u16str(D_MESG) || C || message)
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_MESG); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ check(hal_hash_update(state, (const uint8_t *)&C, sizeof(C)));
+ check(hal_hash_update(state, msg, msg_len));
+ check(hal_hash_finalize(state, Q, n));
+
+ /* append checksum */
+ *(uint16_t *)&Q[n] = u16str(Cksm((uint8_t *)Q, key->lmots));
+
+ bytestring32 y[p];
+
+// for ( i = 0; i < p; i = i + 1 ) {
+ for (size_t i = 0; i < p; ++i) {
+
+// a = coef(Q || Cksm(Q), i, w)
+ uint8_t a = coef(Q, i, w);
+
+// tmp = x[i]
+ bytestring32 tmp;
+ memcpy(&tmp, &key->x[i], sizeof(tmp));
+
+// for ( j = 0; j < a; j = j + 1 ) {
+ for (size_t j = 0; j < (size_t)a; ++j) {
+
+// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp)
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(i); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ b = u8str(j); check(hal_hash_update(state, (const uint8_t *)&b, sizeof(b)));
+ check(hal_hash_update(state, (const uint8_t *)&tmp, sizeof(tmp)));
+ check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp)));
+// }
+ }
+
+// y[i] = tmp
+ memcpy(&y[i], &tmp, sizeof(tmp));
+ }
+
+// 6. return u32str(type) || C || y[0] || ... || y[p-1]
+ uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_max;
+ check(hal_xdr_encode_int(&sigptr, siglim, key->lmots->type));
+ check(hal_xdr_encode_bytestring32(&sigptr, siglim, &C));
+ for (size_t i = 0; i < p; ++i)
+ check(hal_xdr_encode_bytestring32(&sigptr, siglim, &y[i]));
+
+ if (sig_len != NULL)
+ *sig_len = sigptr - sig;
+
+ return HAL_OK;
+}
+#endif
+
+static hal_error_t lmots_public_key_candidate(const lmots_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ const uint8_t * const sig, const size_t sig_len)
+{
+ if (key == NULL || msg == NULL || sig == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /* Skip the length checks here, because we did a unitary length check
+ * at the start of lms_verify.
+ */
+
+// 1. if the signature is not at least four bytes long, return INVALID
+//
+// 2. parse sigtype, C, and y from the signature as follows:
+// a. sigtype = strTou32(first 4 bytes of signature)
+
+ const uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_len;
+
+ uint32_t sigtype;
+ check(hal_xdr_decode_int(&sigptr, siglim, &sigtype));
+
+// b. if sigtype is not equal to pubtype, return INVALID
+
+ if ((lmots_algorithm_t)sigtype != key->lmots->type)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// c. set n and p according to the pubtype and Table 1; if the
+// signature is not exactly 4 + n * (p+1) bytes long, return INVALID
+
+ size_t n = key->lmots->n;
+ size_t p = key->lmots->p;
+ size_t w = key->lmots->w;
+
+// d. C = next n bytes of signature
+
+ bytestring32 C;
+ check(hal_xdr_decode_bytestring32(&sigptr, siglim, &C));
+
+// e. y[0] = next n bytes of signature
+// y[1] = next n bytes of signature
+// ...
+// y[p-1] = next n bytes of signature
+
+ bytestring32 y[p];
+ for (size_t i = 0; i < p; ++i)
+ check(hal_xdr_decode_bytestring32(&sigptr, siglim, &y[i]));
+
+// 3. compute the string Kc as follows
+
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ uint8_t Q[n + 2]; /* hash || 16-bit checksum */
+ uint32_t l;
+ uint16_t s;
+ uint8_t b;
+
+// Q = H(I || u32str(q) || u16str(D_MESG) || C || message)
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_MESG); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ check(hal_hash_update(state, (const uint8_t *)&C, sizeof(C)));
+ check(hal_hash_update(state, msg, msg_len));
+ check(hal_hash_finalize(state, Q, n));
+
+ /* append checksum */
+ *(uint16_t *)&Q[n] = u16str(Cksm((uint8_t *)Q, key->lmots));
+
+ bytestring32 z[p];
+
+// for ( i = 0; i < p; i = i + 1 ) {
+ for (size_t i = 0; i < p; ++i) {
+
+// a = coef(Q || Cksm(Q), i, w)
+ uint8_t a = coef(Q, i, w);
+
+// tmp = y[i]
+ bytestring32 tmp;
+ memcpy(&tmp, &y[i], sizeof(tmp));
+
+// for ( j = a; j < 2^w - 1; j = j + 1 ) {
+ for (size_t j = (size_t)a; j < (1U << w) - 1; ++j) {
+
+// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp)
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(i); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ b = u8str(j); check(hal_hash_update(state, (const uint8_t *)&b, sizeof(b)));
+ check(hal_hash_update(state, (const uint8_t *)&tmp, sizeof(tmp)));
+ check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp)));
+// }
+ }
+
+// z[i] = tmp
+ memcpy(&z[i], &tmp, sizeof(tmp));
+// }
+ }
+
+// Kc = H(I || u32str(q) || u16str(D_PBLC) || z[0] || z[1] || ... || z[p-1])
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(key->q); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_PBLC); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ for (size_t i = 0; i < p; ++i)
+ check(hal_hash_update(state, (const uint8_t *)&z[i], sizeof(z[i])));
+ check(hal_hash_finalize(state, (uint8_t *)&key->K, sizeof(key->K)));
+
+// 4. return Kc
+ return HAL_OK;
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+static hal_error_t lmots_private_key_to_der(const lmots_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMOTS)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ // u32str(lmots_type) || I || u32str(q) || K || x[0] || x[1] || ... || x[p-1]
+ /* K is not an integral part of the private key, but we store it to speed up restart */
+
+ /*
+ * Calculate data length.
+ */
+
+ size_t len, vlen = 0, hlen;
+
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring16(&key->I, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_size_t(key->q, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring32(&key->K, NULL, &len, 0)); vlen += len;
+ for (size_t i = 0; i < key->lmots->p; ++i) {
+ check(hal_asn1_encode_bytestring32(&key->x[i], NULL, &len, 0)); vlen += len;
+ }
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0));
+
+ check(hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, NULL, hlen + vlen, NULL, der_len, der_max));
+
+ if (der == NULL)
+ return HAL_OK;
+
+ /*
+ * Encode data.
+ */
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max));
+
+ uint8_t *d = der + hlen;
+ memset(d, 0, vlen);
+
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_bytestring16(&key->I, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_size_t(key->q, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_bytestring32(&key->K, d, &len, vlen)); d += len; vlen -= len;
+ for (size_t i = 0; i < key->lmots->p; ++i) {
+ check(hal_asn1_encode_bytestring32(&key->x[i], d, &len, vlen)); d += len; vlen -= len;
+ }
+
+ return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, der, d - der, der, der_len, der_max);
+}
+
+static size_t lmots_private_key_to_der_len(const lmots_key_t * const key)
+{
+ size_t len = 0;
+ return (lmots_private_key_to_der(key, NULL, &len, 0) == HAL_OK) ? len : 0;
+}
+
+static hal_error_t lmots_private_key_from_der(lmots_key_t *key,
+ const uint8_t *der, const size_t der_len)
+{
+ if (key == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ key->type = HAL_KEY_TYPE_HASHSIG_LMOTS;
+
+ size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len;
+ const uint8_t *alg_oid, *curve_oid, *privkey;
+
+ check(hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len,
+ &curve_oid, &curve_oid_len,
+ &privkey, &privkey_len,
+ der, der_len));
+
+ if (alg_oid_len != hal_asn1_oid_mts_hashsig_len ||
+ memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) != 0 ||
+ curve_oid_len != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ check(hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen));
+
+ const uint8_t *d = privkey + hlen;
+ size_t len;
+
+ // u32str(lmots_type) || I || u32str(q) || K || x[0] || x[1] || ... || x[p-1]
+
+ lmots_algorithm_t lmots_type;
+ check(hal_asn1_decode_lmots_algorithm(&lmots_type, d, &len, vlen)); d += len; vlen -= len;
+ key->lmots = lmots_select_parameter_set(lmots_type);
+ check(hal_asn1_decode_bytestring16(&key->I, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_decode_size_t(&key->q, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_decode_bytestring32(&key->K, d, &len, vlen)); d += len; vlen -= len;
+ if (key->x != NULL) {
+ for (size_t i = 0; i < key->lmots->p; ++i) {
+ check(hal_asn1_decode_bytestring32(&key->x[i], d, &len, vlen)); d += len; vlen -= len;
+ }
+
+ if (d != privkey + privkey_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ }
+
+ return HAL_OK;
+}
+#endif
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * LMS
+ */
+
+typedef const struct lms_parameter_set {
+ lms_algorithm_t type;
+ size_t m, h;
+} lms_parameter_t;
+static lms_parameter_t lms_parameters[] = {
+ { lms_sha256_n32_h5, 32, 5 },
+ { lms_sha256_n32_h10, 32, 10 },
+ { lms_sha256_n32_h15, 32, 15 },
+ { lms_sha256_n32_h20, 32, 20 },
+ { lms_sha256_n32_h25, 32, 25 },
+};
+
+typedef struct lms_key {
+ hal_key_type_t type;
+ size_t level;
+ lms_parameter_t *lms;
+ lmots_parameter_t *lmots;
+ bytestring16 I;
+ size_t q; /* index of next lmots signing key */
+ hal_uuid_t *lmots_keys; /* private key components */
+ bytestring32 *T; /* public key components */
+ bytestring32 T1; /* copy of T[1] */
+ uint8_t *pubkey; /* in XDR format */
+ size_t pubkey_len;
+ uint8_t *signature; /* of public key by parent lms key */
+ size_t signature_len;
+} lms_key_t;
+
+static inline lms_parameter_t *lms_select_parameter_set(const lms_algorithm_t lms_type)
+{
+ if (lms_type < lms_sha256_n32_h5 || lms_type > lms_sha256_n32_h25)
+ return NULL;
+ else
+ return &lms_parameters[lms_type - lms_sha256_n32_h5];
+}
+
+static inline size_t lms_public_key_len(lms_parameter_t * const lms)
+{
+ /* u32str(type) || u32str(otstype) || I || T[1] */
+ return 2 * sizeof(uint32_t) + 16 + lms->m;
+}
+
+static inline size_t lms_signature_len(lms_parameter_t * const lms, lmots_parameter_t * const lmots)
+{
+ /* u32str(q) || ots_signature || u32str(type) || path[0] || path[1] || ... || path[h-1] */
+ return 2 * sizeof(uint32_t) + lmots_signature_len(lmots) + lms->h * lms->m;
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+/* Given a key with most fields filled in, generate the lms private and
+ * public key components.
+ * Let the caller worry about storage.
+ */
+static hal_error_t lms_generate(lms_key_t *key)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMS || key->lms == NULL || key->lmots == NULL || key->lmots_keys == NULL || key->T == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ check(hal_uuid_gen((hal_uuid_t *)&key->I));
+ key->q = 0;
+
+ bytestring32 x[key->lmots->p];
+ lmots_key_t lmots_key = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMOTS,
+ .lmots = key->lmots,
+ .x = x
+ };
+ memcpy(&lmots_key.I, &key->I, sizeof(key->I));
+
+ hal_pkey_slot_t slot = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMOTS,
+ .curve = HAL_CURVE_NONE,
+ .flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | ((key->level == 0) ? HAL_KEY_FLAG_TOKEN: 0)
+ };
+ hal_ks_t *ks = (key->level == 0) ? hal_ks_token : hal_ks_volatile;
+
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ uint32_t l;
+ uint16_t s;
+ size_t h2 = (1 << key->lms->h);
+
+ /* private key - array of lmots key names */
+ for (size_t q = 0; q < h2; ++q) {
+ /* generate the lmots private and public key components */
+ lmots_key.q = q;
+ check(lmots_generate(&lmots_key));
+
+ /* store the lmots key */
+ uint8_t der[lmots_private_key_to_der_len(&lmots_key)];
+ size_t der_len;
+ check(lmots_private_key_to_der(&lmots_key, der, &der_len, sizeof(der)));
+ check(hal_uuid_gen(&slot.name));
+ hal_error_t err = hal_ks_store(ks, &slot, der, der_len);
+ memset(&x, 0, sizeof(x));
+ memset(der, 0, sizeof(der));
+ if (err != HAL_OK) return err;
+
+ /* record the lmots keystore name */
+ memcpy(&key->lmots_keys[q], &slot.name, sizeof(slot.name));
+
+ /* compute T[r] = H(I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[r-2^h]) */
+ size_t r = h2 + q;
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(r); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_LEAF); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ check(hal_hash_update(state, (const uint8_t *)&lmots_key.K, sizeof(lmots_key.K)));
+ check(hal_hash_finalize(state, (uint8_t *)&key->T[r], sizeof(key->T[r])));
+ }
+
+ /* generate the rest of T[r] = H(I || u32str(r) || u16str(D_INTR) || T[2*r] || T[2*r+1]) */
+ for (size_t r = h2 - 1; r > 0; --r) {
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(r); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_INTR); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ check(hal_hash_update(state, (const uint8_t *)&key->T[2*r], sizeof(key->T[r])));
+ check(hal_hash_update(state, (const uint8_t *)&key->T[2*r+1], sizeof(key->T[r])));
+ check(hal_hash_finalize(state, (uint8_t *)&key->T[r], sizeof(key->T[r])));
+ }
+
+ memcpy(&key->T1, &key->T[1], sizeof(key->T1));
+
+ /* generate the XDR encoding of the public key, which will be signed
+ * by the previous lms key
+ */
+ uint8_t *pubkey = key->pubkey;
+ const uint8_t * const publim = key->pubkey + key->pubkey_len;
+ // u32str(lms_type) || u32str(lmots_type) || I || T[1]
+ check(hal_xdr_encode_int(&pubkey, publim, key->lms->type));
+ check(hal_xdr_encode_int(&pubkey, publim, key->lmots->type));
+ check(hal_xdr_encode_bytestring16(&pubkey, publim, &key->I));
+ check(hal_xdr_encode_bytestring32(&pubkey, publim, &key->T1));
+
+ return HAL_OK;
+}
+
+static hal_error_t lms_delete(const lms_key_t * const key)
+{
+ hal_pkey_slot_t slot = {0};
+ hal_ks_t *ks = (key->level == 0) ? hal_ks_token : hal_ks_volatile;
+
+ /* delete the lmots keys */
+ for (size_t i = 0; i < (1U << key->lms->h); ++i) {
+ memcpy(&slot.name, &key->lmots_keys[i], sizeof(slot.name));
+ check(hal_ks_delete(ks, &slot));
+ }
+
+ /* delete the lms key */
+ memcpy(&slot.name, &key->I, sizeof(slot.name));
+ return hal_ks_delete(ks, &slot);
+}
+
+static hal_error_t lms_private_key_to_der(const lms_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+static hal_error_t lms_sign(lms_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ uint8_t *sig, size_t *sig_len, const size_t sig_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMS || msg == NULL || sig == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (key->q >= (1U << key->lms->h))
+ return HAL_ERROR_HASHSIG_KEY_EXHAUSTED;
+
+ if (sig_max < lms_signature_len(key->lms, key->lmots))
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ /* u32str(q) || ots_signature || u32str(lms_type) || path[0] || path[1] || ... || path[h-1] */
+
+ uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_max;
+ check(hal_xdr_encode_int(&sigptr, siglim, key->q));
+
+ /* fetch and decode the lmots signing key from the keystore */
+ hal_pkey_slot_t slot;
+ memset(&slot, 0, sizeof(slot));
+ memcpy(&slot.name, &key->lmots_keys[key->q], sizeof(slot.name));
+
+ lmots_key_t lmots_key;
+ memset(&lmots_key, 0, sizeof(lmots_key));
+ bytestring32 x[key->lmots->p];
+ memset(&x, 0, sizeof(x));
+ lmots_key.x = x;
+
+ uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
+ size_t der_len;
+ hal_ks_t *ks = (key->level == 0) ? hal_ks_token : hal_ks_volatile;
+ check(hal_ks_fetch(ks, &slot, der, &der_len, sizeof(der)));
+ check(lmots_private_key_from_der(&lmots_key, der, der_len));
+ memset(&der, 0, sizeof(der));
+
+ //? check lmots_type and I vs. lms key?
+
+ /* generate the lmots signature */
+ size_t lmots_sig_len;
+ check(lmots_sign(&lmots_key, msg, msg_len, sigptr, &lmots_sig_len, sig_max - (sigptr - sig)));
+ memset(&x, 0, sizeof(x));
+ sigptr += lmots_sig_len;
+
+ check(hal_xdr_encode_int(&sigptr, siglim, key->lms->type));
+
+ /* generate the path array */
+ for (size_t r = (1 << key->lms->h) + key->q; r > 1; r /= 2)
+ check(hal_xdr_encode_bytestring32(&sigptr, siglim, ((r & 1) ? &key->T[r-1] : &key->T[r+1])));
+
+ if (sig_len != NULL)
+ *sig_len = sigptr - sig;
+
+ /* update and store q before returning the signature */
+ ++key->q;
+ check(lms_private_key_to_der(key, der, &der_len, sizeof(der)));
+ slot.type = HAL_KEY_TYPE_HASHSIG_LMS;
+ slot.flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | ((key->level == 0) ? HAL_KEY_FLAG_TOKEN : 0);
+ memcpy(&slot.name, &key->I, sizeof(slot.name));
+ check(hal_ks_rewrite_der(ks, &slot, der, der_len));
+
+ return HAL_OK;
+}
+#endif
+
+static hal_error_t lms_public_key_candidate(const lms_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ const uint8_t * const sig, const size_t sig_len,
+ bytestring32 * Tc);
+
+static hal_error_t lms_verify(const lms_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ const uint8_t * const sig, const size_t sig_len)
+{
+ if (key == NULL || msg == NULL || sig == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /* We can do one length check right now, rather than the 3 in
+ * Algorithm 6b and 2 in Algorithm 4b, because the lms and lmots types
+ * in the signature have to match the key.
+ */
+ if (sig_len != lms_signature_len(key->lms, key->lmots))
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// Algorithm 6: LMS Signature Verification
+//
+// 1. if the public key is not at least eight bytes long, return
+// INVALID
+//
+// 2. parse pubtype, I, and T[1] from the public key as follows:
+//
+// a. pubtype = strTou32(first 4 bytes of public key)
+//
+// b. ots_typecode = strTou32(next 4 bytes of public key)
+//
+// c. set m according to pubtype, based on Table 2
+//
+// d. if the public key is not exactly 24 + m bytes
+// long, return INVALID
+//
+// e. I = next 16 bytes of the public key
+//
+// f. T[1] = next m bytes of the public key
+//
+// 3. compute the candidate LMS root value Tc from the signature,
+// message, identifier and pubtype using Algorithm 6b.
+
+ bytestring32 Tc;
+ check(lms_public_key_candidate(key, msg, msg_len, sig, sig_len, &Tc));
+
+// 4. if Tc is equal to T[1], return VALID; otherwise, return INVALID
+
+ return (memcmp(&Tc, &key->T1, sizeof(Tc)) ? HAL_ERROR_INVALID_SIGNATURE : HAL_OK);
+}
+
+static hal_error_t lms_public_key_candidate(const lms_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ const uint8_t * const sig, const size_t sig_len,
+ bytestring32 * Tc)
+{
+// Algorithm 6b: Computing an LMS Public Key Candidate from a Signature,
+// Message, Identifier, and algorithm typecode
+ /* XXX and pubotstype */
+
+// 1. if the signature is not at least eight bytes long, return INVALID
+//
+// 2. parse sigtype, q, ots_signature, and path from the signature as
+// follows:
+//
+// a. q = strTou32(first 4 bytes of signature)
+
+ const uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_len;
+
+ uint32_t q;
+ check(hal_xdr_decode_int(&sigptr, siglim, &q));
+
+// b. otssigtype = strTou32(next 4 bytes of signature)
+
+ uint32_t otssigtype;
+ check(hal_xdr_decode_int_peek(&sigptr, siglim, &otssigtype));
+
+// c. if otssigtype is not the OTS typecode from the public key, return INVALID
+
+ if ((lmots_algorithm_t)otssigtype != key->lmots->type)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// d. set n, p according to otssigtype and Table 1; if the
+// signature is not at least 12 + n * (p + 1) bytes long, return INVALID
+//
+// e. ots_signature = bytes 8 through 8 + n * (p + 1) - 1 of signature
+
+ /* XXX Technically, this is also wrong - this is the remainder of
+ * ots_signature after otssigtype. The full ots_signature would be
+ * bytes 4 through 8 + n * (p + 1) - 1.
+ */
+
+ const uint8_t * const ots_signature = sigptr;
+ sigptr += lmots_signature_len(key->lmots);
+
+// f. sigtype = strTou32(4 bytes of signature at location 8 + n * (p + 1))
+
+ uint32_t sigtype;
+ check(hal_xdr_decode_int(&sigptr, siglim, &sigtype));
+
+// f. if sigtype is not the LM typecode from the public key, return INVALID
+
+ if ((lms_algorithm_t)sigtype != key->lms->type)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// g. set m, h according to sigtype and Table 2
+
+ size_t m = key->lms->m;
+ size_t h = key->lms->h;
+ size_t h2 = (1 << key->lms->h);
+
+// h. if q >= 2^h or the signature is not exactly 12 + n * (p + 1) + m * h bytes long, return INVALID
+
+ if (q >= h2)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// i. set path as follows:
+// path[0] = next m bytes of signature
+// path[1] = next m bytes of signature
+// ...
+// path[h-1] = next m bytes of signature
+
+ bytestring32 path[h];
+ for (size_t i = 0; i < h; ++i)
+ check(hal_xdr_decode_bytestring32(&sigptr, siglim, &path[i]));
+
+// 3. Kc = candidate public key computed by applying Algorithm 4b
+// to the signature ots_signature, the message, and the
+// identifiers I, q
+
+ lmots_key_t lmots_key = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMOTS,
+ .lmots = key->lmots,
+ .q = q
+ };
+ memcpy(&lmots_key.I, &key->I, sizeof(lmots_key.I));
+ check(lmots_public_key_candidate(&lmots_key, msg, msg_len, ots_signature, lmots_signature_len(key->lmots)));
+
+// 4. compute the candidate LMS root value Tc as follows:
+
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ uint32_t l;
+ uint16_t s;
+
+// node_num = 2^h + q
+ size_t r = h2 + q;
+
+// tmp = H(I || u32str(node_num) || u16str(D_LEAF) || Kc)
+ bytestring32 tmp;
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&lmots_key.I, sizeof(lmots_key.I)));
+ l = u32str(r); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_LEAF); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ check(hal_hash_update(state, (const uint8_t *)&lmots_key.K, sizeof(lmots_key.K)));
+ check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp)));
+
+// i = 0
+// while (node_num > 1) {
+// if (node_num is odd):
+// tmp = H(I || u32str(node_num/2) || u16str(D_INTR) || path[i] || tmp)
+// else:
+// tmp = H(I || u32str(node_num/2) || u16str(D_INTR) || tmp || path[i])
+// node_num = node_num/2
+// i = i + 1
+// }
+ for (size_t i = 0; r > 1; r /= 2, ++i) {
+ check(hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf)));
+ check(hal_hash_update(state, (const uint8_t *)&key->I, sizeof(key->I)));
+ l = u32str(r/2); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l)));
+ s = u16str(D_INTR); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ if (r & 1) {
+ check(hal_hash_update(state, (const uint8_t *)&path[i], m));
+ check(hal_hash_update(state, (const uint8_t *)&tmp, sizeof(tmp)));
+ }
+ else {
+ check(hal_hash_update(state, (const uint8_t *)&tmp, sizeof(tmp)));
+ check(hal_hash_update(state, (const uint8_t *)&path[i], m));
+ }
+ check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp)));
+ }
+
+// Tc = tmp
+ memcpy(Tc, &tmp, sizeof(*Tc));
+
+ return HAL_OK;
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+static hal_error_t lms_private_key_to_der(const lms_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_LMS)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Calculate data length.
+ */
+
+ // u32str(lms_type) || u32str(lmots_type) || I || q
+
+ size_t len, vlen = 0, hlen;
+
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring16(&key->I, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_size_t(key->q, NULL, &len, 0)); vlen += len;
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0));
+
+ check(hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, NULL, hlen + vlen, NULL, der_len, der_max));
+
+ if (der == NULL)
+ return HAL_OK;
+
+ /*
+ * Encode data.
+ */
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max));
+
+ uint8_t *d = der + hlen;
+ memset(d, 0, vlen);
+
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_bytestring16(&key->I, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_size_t(key->q, d, &len, vlen)); d += len; vlen -= len;
+
+ return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, der, d - der, der, der_len, der_max);
+}
+
+static size_t lms_private_key_to_der_len(const lms_key_t * const key)
+{
+ size_t len = 0;
+ return lms_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+static hal_error_t lms_private_key_from_der(lms_key_t *key,
+ const uint8_t *der, const size_t der_len)
+{
+ if (key == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ key->type = HAL_KEY_TYPE_HASHSIG_LMS;
+
+ size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len;
+ const uint8_t *alg_oid, *curve_oid, *privkey;
+
+ check(hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len,
+ &curve_oid, &curve_oid_len,
+ &privkey, &privkey_len,
+ der, der_len));
+
+ if (alg_oid_len != hal_asn1_oid_mts_hashsig_len ||
+ memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) != 0 ||
+ curve_oid_len != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ check(hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen));
+
+ const uint8_t *d = privkey + hlen;
+ size_t n;
+
+ // u32str(lms_type) || u32str(lmots_type) || I || q
+
+ lms_algorithm_t lms_type;
+ check(hal_asn1_decode_lms_algorithm(&lms_type, d, &n, vlen)); d += n; vlen -= n;
+ key->lms = lms_select_parameter_set(lms_type);
+ lmots_algorithm_t lmots_type;
+ check(hal_asn1_decode_lmots_algorithm(&lmots_type, d, &n, vlen)); d += n; vlen -= n;
+ key->lmots = lmots_select_parameter_set(lmots_type);
+ check(hal_asn1_decode_bytestring16(&key->I, d, &n, vlen)); d += n; vlen -= n;
+ check(hal_asn1_decode_size_t(&key->q, d, &n, vlen)); d += n; vlen -= n;
+
+ if (d != privkey + privkey_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ return HAL_OK;
+}
+#endif
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * HSS
+ */
+
+/* For purposes of the external API, the key type is "hal_hashsig_key_t".
+ * Internally, we refer to it as "hss_key_t".
+ */
+
+typedef struct hal_hashsig_key hss_key_t;
+
+struct hal_hashsig_key {
+ hal_key_type_t type;
+ hss_key_t *next;
+ hal_uuid_t name;
+ size_t L;
+ lms_parameter_t *lms;
+ lmots_parameter_t *lmots;
+ bytestring16 I;
+ bytestring32 T1;
+ lms_key_t *lms_keys;
+};
+
+const size_t hal_hashsig_key_t_size = sizeof(hss_key_t);
+
+static hss_key_t *hss_keys = NULL;
+
+static inline size_t hss_public_key_len(lms_parameter_t * const lms)
+{
+ /* L || pub[0] */
+ return sizeof(uint32_t) + lms_public_key_len(lms);
+}
+
+static inline size_t hss_signature_len(const size_t L, lms_parameter_t * const lms, lmots_parameter_t * const lmots)
+{
+ /* u32str(Nspk) || sig[0] || pub[1] || ... || sig[Nspk-1] || pub[Nspk] || sig[Nspk] */
+ return sizeof(uint32_t) + L * lms_signature_len(lms, lmots) + (L - 1) * lms_public_key_len(lms);
+}
+
+size_t hal_hashsig_signature_len(const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type)
+{
+ lms_parameter_t * const lms = lms_select_parameter_set(lms_type);
+ if (lms == NULL)
+ return 0;
+
+ lmots_parameter_t * const lmots = lmots_select_parameter_set(lmots_type);
+ if (lmots == NULL)
+ return 0;
+
+ return hss_signature_len(L, lms, lmots);
+}
+
+size_t hal_hashsig_lmots_private_key_len(const lmots_algorithm_t lmots_type)
+{
+ lmots_parameter_t * const lmots = lmots_select_parameter_set(lmots_type);
+ if (lmots == NULL)
+ return 0;
+
+ return lmots_private_key_len(lmots);
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+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 hss_alloc(hal_hashsig_key_t **key_,
+ const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type)
+{
+ if (key_ == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (L == 0 || L > 8)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ lms_parameter_t *lms = lms_select_parameter_set(lms_type);
+ if (lms == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ size_t h2 = (1 << lms->h);
+
+ lmots_parameter_t *lmots = lmots_select_parameter_set(lmots_type);
+ if (lmots == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /* w=1 fails on the Alpha, because the key exceeds the keystore block
+ * size. The XDR encoding of the key is going to differ from the DER
+ * encoding, but it's at least in the ballpark to tell us whether the key
+ * will fit.
+ */
+ if (lmots_private_key_len(lmots) > HAL_KS_BLOCK_SIZE)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ if (hss_signature_len(L, lms, lmots) > HAL_RPC_MAX_PKT_SIZE)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ /* check volatile keystore for space to store the lower-level trees */
+ size_t available;
+ check(hal_ks_available(hal_ks_volatile, &available));
+ if (available < (L - 1) * (h2 + 1))
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ size_t lms_sig_len = lms_signature_len(lms, lmots);
+ size_t lms_pub_len = lms_public_key_len(lms);
+
+ /* allocate lms tree nodes and lmots key names, atomically */
+ size_t len = (sizeof(hss_key_t) +
+ L * sizeof(lms_key_t) +
+ L * lms_sig_len +
+ L * lms_pub_len +
+ L * h2 * sizeof(hal_uuid_t) +
+ L * (2 * h2) * sizeof(bytestring32));
+ uint8_t *mem = hal_allocate_static_memory(len);
+ if (mem == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+ memset(mem, 0, len);
+
+ /* allocate the key that will stay in working memory */
+ hss_key_t *key = gnaw(&mem, &len, sizeof(hss_key_t));
+ *key_ = key;
+ key->type = HAL_KEY_TYPE_HASHSIG_PRIVATE;
+ key->L = L;
+ key->lms = lms;
+ key->lmots = lmots;
+
+ /* add to the list of active keys */
+ key->next = hss_keys;
+ hss_keys = key;
+
+ /* allocate the list of lms trees */
+ key->lms_keys = gnaw(&mem, &len, L * sizeof(lms_key_t));
+ for (size_t i = 0; i < L; ++i) {
+ /* XXX some of this is redundant to lms_private_key_from_der */
+ lms_key_t * lms_key = &key->lms_keys[i];
+ lms_key->type = HAL_KEY_TYPE_HASHSIG_LMS;
+ lms_key->lms = lms;
+ lms_key->lmots = lmots;
+ lms_key->level = i;
+ lms_key->lmots_keys = (hal_uuid_t *)gnaw(&mem, &len, h2 * sizeof(hal_uuid_t));
+ lms_key->T = gnaw(&mem, &len, (2 * h2) * sizeof(bytestring32));
+ lms_key->signature = gnaw(&mem, &len, lms_sig_len);
+ lms_key->signature_len = lms_sig_len;
+ lms_key->pubkey = gnaw(&mem, &len, lms_pub_len);
+ lms_key->pubkey_len = lms_pub_len;
+ }
+
+ return HAL_OK;
+}
+
+/* called from pkey_local_generate_hashsig */
+hal_error_t hal_hashsig_key_gen(hal_core_t *core,
+ hal_hashsig_key_t **key_,
+ const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type)
+{
+ /* hss_alloc does most of the checks */
+
+ /* check flash keystore for space to store the root tree */
+ lms_parameter_t *lms = lms_select_parameter_set(lms_type);
+ if (lms == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ size_t available;
+ check(hal_ks_available(hal_ks_token, &available));
+ if (available < (1U << lms->h) + 2)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ check(hss_alloc(key_, L, lms_type, lmots_type));
+ hss_key_t *key = *key_;
+
+ /* generate the lms trees */
+ for (size_t i = 0; i < L; ++i) {
+ lms_key_t * lms_key = &key->lms_keys[i];
+
+ check(lms_generate(lms_key));
+
+ if (i > 0)
+ /* sign this tree with the previous */
+ check(lms_sign(&key->lms_keys[i-1],
+ (const uint8_t * const)lms_key->pubkey, lms_public_key_len(key->lms),
+ lms_key->signature, NULL, lms_signature_len(key->lms, key->lmots)));
+
+ /* store the lms key */
+ hal_pkey_slot_t slot = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMS,
+ .curve = HAL_CURVE_NONE,
+ .flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | ((i == 0) ? HAL_KEY_FLAG_TOKEN: 0)
+ };
+ hal_ks_t *ks = (i == 0) ? hal_ks_token : hal_ks_volatile;
+ uint8_t der[lms_private_key_to_der_len(lms_key)];
+ size_t der_len;
+
+ memcpy(&slot.name, &lms_key->I, sizeof(slot.name));
+ check(lms_private_key_to_der(lms_key, der, &der_len, sizeof(der)));
+ check(hal_ks_store(ks, &slot, der, der_len));
+ }
+
+ memcpy(&key->I, &key->lms_keys[0].I, sizeof(key->I));
+ memcpy(&key->T1, &key->lms_keys[0].T1, sizeof(key->T1));
+
+ /* pkey_local_generate_hashsig stores the key */
+
+ return HAL_OK;
+}
+
+/* caller will delete the hss key from the keystore */
+hal_error_t hal_hashsig_key_delete(const hal_hashsig_key_t * const key)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /* delete the lms trees and their lmots keys */
+ for (size_t level = 0; level < key->L; ++level)
+ check(lms_delete(&key->lms_keys[level]));
+
+ /* XXX free memory, if supported */
+ (void)hal_free_static_memory(key);
+
+ /* remove from global hss_keys linked list */
+ /* XXX or mark it unused, for possible re-use */
+ if (hss_keys == key) {
+ hss_keys = key->next;
+ }
+ else {
+ for (hss_key_t *prev = hss_keys; prev != NULL; prev = prev->next) {
+ if (prev->next == key) {
+ prev->next = key->next;
+ break;
+ }
+ }
+ }
+
+ return HAL_OK;
+}
+
+hal_error_t hal_hashsig_sign(hal_core_t *core,
+ const hal_hashsig_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ uint8_t *sig, size_t *sig_len, const size_t sig_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE || msg == NULL || sig == NULL || sig_len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (sig_max < hss_signature_len(key->L, key->lms, key->lmots))
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+// To sign a message using the private key prv, the following steps are
+// performed:
+//
+// If prv[L-1] is exhausted, then determine the smallest integer d
+// such that all of the private keys prv[d], prv[d+1], ... , prv[L-1]
+// are exhausted. If d is equal to zero, then the HSS key pair is
+// exhausted, and it MUST NOT generate any more signatures.
+// Otherwise, the key pairs for levels d through L-1 must be
+// regenerated during the signature generation process, as follows.
+// For i from d to L-1, a new LMS public and private key pair with a
+// new identifier is generated, pub[i] and prv[i] are set to those
+// values, then the public key pub[i] is signed with prv[i-1], and
+// sig[i-1] is set to the resulting value.
+
+ size_t h2 = (1 << key->lms->h);
+ if (key->lms_keys[key->L-1].q >= h2) {
+ size_t d;
+ for (d = key->L-1; d > 0 && key->lms_keys[d-1].q >= h2; --d) {
+ }
+ if (d == 0)
+ return HAL_ERROR_HASHSIG_KEY_EXHAUSTED;
+ for ( ; d < key->L; ++d) {
+ lms_key_t *lms_key = &key->lms_keys[d];
+ /* Delete then regenerate the LMS key. We don't worry about
+ * power-cycling in the middle, because the lower-level trees are
+ * all stored in the volatile keystore, so we'd have to regenerate
+ * them anyway on restart; and this way we don't have to allocate
+ * any additional memory.
+ */
+ check(lms_delete(lms_key));
+ check(lms_generate(lms_key));
+ check(lms_sign(&key->lms_keys[d-1],
+ (const uint8_t * const)lms_key->pubkey, lms_key->pubkey_len,
+ lms_key->signature, NULL, lms_key->signature_len));
+
+ hal_pkey_slot_t slot = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMS,
+ .curve = HAL_CURVE_NONE,
+ .flags = (lms_key->level == 0) ? HAL_KEY_FLAG_TOKEN: 0
+ };
+ hal_ks_t *ks = (lms_key->level == 0) ? hal_ks_token : hal_ks_volatile;
+ uint8_t der[lms_private_key_to_der_len(lms_key)];
+ size_t der_len;
+
+ memcpy(&slot.name, &lms_key->I, sizeof(slot.name));
+ check(lms_private_key_to_der(lms_key, der, &der_len, sizeof(der)));
+ check(hal_ks_store(ks, &slot, der, der_len));
+ }
+ }
+
+// The message is signed with prv[L-1], and the value sig[L-1] is set
+// to that result.
+//
+// The value of the HSS signature is set as follows. We let
+// signed_pub_key denote an array of octet strings, where
+// signed_pub_key[i] = sig[i] || pub[i+1], for i between 0 and Nspk-
+// 1, inclusive, where Nspk = L-1 denotes the number of signed public
+// keys. Then the HSS signature is u32str(Nspk) ||
+// signed_pub_key[0] || ... || signed_pub_key[Nspk-1] || sig[Nspk].
+
+ uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_max;
+ check(hal_xdr_encode_int(&sigptr, siglim, key->L - 1));
+
+ /* copy the lms signed public keys into the signature */
+ for (size_t i = 1; i < key->L; ++i) {
+ lms_key_t *lms_key = &key->lms_keys[i];
+ check(hal_xdr_encode_fixed_opaque(&sigptr, siglim, lms_key->signature, lms_key->signature_len));
+ check(hal_xdr_encode_fixed_opaque(&sigptr, siglim, lms_key->pubkey, lms_key->pubkey_len));
+ }
+
+ /* sign the message with the last lms private key */
+ size_t len;
+ check(lms_sign(&key->lms_keys[key->L-1], msg, msg_len, sigptr, &len, sig_max - (sigptr - sig)));
+ sigptr += len;
+ *sig_len = sigptr - sig;
+
+ return HAL_OK;
+}
+#endif
+
+hal_error_t hal_hashsig_verify(hal_core_t *core,
+ const hal_hashsig_key_t * const key,
+ const uint8_t * const msg, const size_t msg_len,
+ const uint8_t * const sig, const size_t sig_len)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_PUBLIC || msg == NULL || sig == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ core = core;
+
+// To verify a signature sig and message using the public key pub, the
+// following steps are performed:
+//
+// The signature S is parsed into its components as follows:
+//
+// Nspk = strTou32(first four bytes of S)
+// if Nspk+1 is not equal to the number of levels L in pub:
+// return INVALID
+
+ const uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + sig_len;
+
+ uint32_t Nspk;
+ check(hal_xdr_decode_int(&sigptr, siglim, &Nspk));
+ if (Nspk + 1 != key->L)
+ return HAL_ERROR_INVALID_SIGNATURE;
+
+// key = pub
+// for (i = 0; i < Nspk; i = i + 1) {
+// sig = next LMS signature parsed from S
+// msg = next LMS public key parsed from S
+// if (lms_verify(msg, key, sig) != VALID):
+// return INVALID
+// key = msg
+// }
+
+ lms_key_t pub = {
+ .type = HAL_KEY_TYPE_HASHSIG_LMS,
+ .lms = key->lms,
+ .lmots = key->lmots
+ };
+ memcpy(&pub.I, &key->I, sizeof(pub.I));
+ memcpy(&pub.T1, &key->T1, sizeof(pub.T1));
+
+ for (size_t i = 0; i < Nspk; ++i) {
+ const uint8_t * const lms_sig = sigptr;
+ /* peek into the signature for the lmots and lms types */
+ /* XXX The structure of the LMS signature makes this a bigger pain
+ * in the ass than necessary.
+ */
+ /* skip over q */
+ sigptr += 4;
+ /* read lmots_type out of the ots_signature */
+ uint32_t lmots_type;
+ check(hal_xdr_decode_int_peek(&sigptr, siglim, &lmots_type));
+ lmots_parameter_t *lmots = lmots_select_parameter_set((lmots_algorithm_t)lmots_type);
+ if (lmots == NULL)
+ return HAL_ERROR_INVALID_SIGNATURE;
+ /* skip over ots_signature */
+ sigptr += lmots_signature_len(lmots);
+ /* read lms_type after ots_signature */
+ uint32_t lms_type;
+ check(hal_xdr_decode_int(&sigptr, siglim, &lms_type));
+ lms_parameter_t *lms = lms_select_parameter_set((lms_algorithm_t)lms_type);
+ if (lms == NULL)
+ return HAL_ERROR_INVALID_SIGNATURE;
+ /* skip over the path elements of the lms signature */
+ sigptr += lms->h * lms->m;
+ /*XXX sigptr = lms_sig + lms_signature_len(lms, lmots); */
+
+ /* verify the signature over the bytestring version of the signed public key */
+ check(lms_verify(&pub, sigptr, lms_public_key_len(lms), lms_sig, sigptr - lms_sig));
+
+ /* parse the signed public key */
+ check(hal_xdr_decode_int(&sigptr, siglim, &lms_type));
+ pub.lms = lms_select_parameter_set((lmots_algorithm_t)lms_type);
+ if (pub.lms == NULL)
+ return HAL_ERROR_INVALID_SIGNATURE;
+ check(hal_xdr_decode_int(&sigptr, siglim, &lmots_type));
+ pub.lmots = lmots_select_parameter_set((lmots_algorithm_t)lmots_type);
+ if (pub.lmots == NULL)
+ return HAL_ERROR_INVALID_SIGNATURE;
+ check(hal_xdr_decode_bytestring16(&sigptr, siglim, &pub.I));
+ check(hal_xdr_decode_bytestring32(&sigptr, siglim, &pub.T1));
+ }
+
+ /* verify the final signature over the message */
+ return lms_verify(&pub, msg, msg_len, sigptr, sig_len - (sigptr - sig));
+}
+
+hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /*
+ * Calculate data length.
+ */
+
+ size_t len, vlen = 0, hlen;
+
+ check(hal_asn1_encode_size_t(key->L, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring16(&key->I, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring32(&key->T1, NULL, &len, 0)); vlen += len;
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0));
+
+ check(hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, NULL, hlen + vlen, NULL, der_len, der_max));
+
+ if (der == NULL)
+ return HAL_OK;
+
+ /*
+ * Encode data.
+ */
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max));
+
+ uint8_t *d = der + hlen;
+ memset(d, 0, vlen);
+
+ check(hal_asn1_encode_size_t(key->L, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_bytestring16(&key->I, d, &len, vlen)); d += len; vlen -= len;
+ check(hal_asn1_encode_bytestring32(&key->T1, d, &len, vlen)); d += len; vlen -= len;
+
+ return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, der, d - der, der, der_len, der_max);
+}
+
+size_t hal_hashsig_private_key_to_der_len(const hal_hashsig_key_t * const key)
+{
+ size_t len = 0;
+ return hal_hashsig_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+hal_error_t hal_hashsig_private_key_from_der(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t *der, const size_t der_len)
+{
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_hashsig_key_t) || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+
+ hss_key_t *key = *key_ = keybuf;
+
+ key->type = HAL_KEY_TYPE_HASHSIG_PRIVATE;
+
+ size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len;
+ const uint8_t *alg_oid, *curve_oid, *privkey;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len,
+ &curve_oid, &curve_oid_len,
+ &privkey, &privkey_len,
+ der, der_len)) != HAL_OK)
+ return err;
+
+ if (alg_oid_len != hal_asn1_oid_mts_hashsig_len ||
+ memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) != 0 ||
+ curve_oid_len != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen)) != HAL_OK)
+ return err;
+
+ const uint8_t *d = privkey + hlen;
+ size_t n;
+
+ check(hal_asn1_decode_size_t(&key->L, d, &n, vlen)); d += n; vlen -= n;
+ lms_algorithm_t lms_type;
+ check(hal_asn1_decode_lms_algorithm(&lms_type, d, &n, vlen)); d += n; vlen -= n;
+ key->lms = lms_select_parameter_set(lms_type);
+ lmots_algorithm_t lmots_type;
+ check(hal_asn1_decode_lmots_algorithm(&lmots_type, d, &n, vlen)); d += n; vlen -= n;
+ key->lmots = lmots_select_parameter_set(lmots_type);
+ check(hal_asn1_decode_bytestring16(&key->I, d, &n, vlen)); d += n; vlen -= n;
+ check(hal_asn1_decode_bytestring32(&key->T1, d, &n, vlen)); d += n; vlen -= n;
+
+ if (d != privkey + privkey_len)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ /* Find this key in the list of active hashsig keys, and return a
+ * pointer to that key structure, rather than the caller-provided key
+ * structure. (The caller will wipe his own key structure when done,
+ * and not molest ours.)
+ */
+ for (hss_key_t *hss_key = hss_keys; hss_key != NULL; hss_key = hss_key->next) {
+ if (memcmp(&key->I, &hss_key->lms_keys[0].I, sizeof(key->I)) == 0) {
+ *key_ = hss_key;
+ }
+ }
+
+ return HAL_OK;
+}
+
+hal_error_t hal_hashsig_public_key_to_der(const hal_hashsig_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ if (key == NULL || (key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE &&
+ key->type != HAL_KEY_TYPE_HASHSIG_PUBLIC))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ // L || u32str(lms_type) || u32str(lmots_type) || I || T[1]
+
+ size_t len, vlen = 0, hlen;
+
+ check(hal_asn1_encode_size_t(key->L, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring16(&key->I, NULL, &len, 0)); vlen += len;
+ check(hal_asn1_encode_bytestring32(&key->T1, NULL, &len, 0)); vlen += len;
+
+ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max));
+
+ if (der != NULL) {
+ uint8_t *d = der + hlen;
+ size_t dlen = vlen;
+ memset(d, 0, vlen);
+
+ check(hal_asn1_encode_size_t(key->L, d, &len, dlen)); d += len; dlen -= len;
+ check(hal_asn1_encode_lms_algorithm(key->lms->type, d, &len, dlen)); d += len; dlen -= len;
+ check(hal_asn1_encode_lmots_algorithm(key->lmots->type, d, &len, dlen)); d += len; dlen -= len;
+ check(hal_asn1_encode_bytestring16(&key->I, d, &len, dlen)); d += len; dlen -= len;
+ check(hal_asn1_encode_bytestring32(&key->T1, d, &len, dlen)); d += len; dlen -= len;
+ }
+
+ return hal_asn1_encode_spki(hal_asn1_oid_mts_hashsig, hal_asn1_oid_mts_hashsig_len,
+ NULL, 0, der, hlen + vlen,
+ der, der_len, der_max);
+
+}
+
+size_t hal_hashsig_public_key_to_der_len(const hal_hashsig_key_t * const key)
+{
+ size_t len = 0;
+ return hal_hashsig_public_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+}
+
+hal_error_t hal_hashsig_public_key_from_der(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hss_key_t) || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hss_key_t *key = keybuf;
+
+ memset(keybuf, 0, keybuf_len);
+ *key_ = key;
+
+ key->type = HAL_KEY_TYPE_HASHSIG_PUBLIC;
+
+ const uint8_t *alg_oid = NULL, *null = NULL, *pubkey = NULL;
+ size_t alg_oid_len, null_len, pubkey_len;
+
+ check(hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &null, &null_len, &pubkey, &pubkey_len, der, der_len));
+
+ if (null != NULL || null_len != 0 || alg_oid == NULL ||
+ alg_oid_len != hal_asn1_oid_mts_hashsig_len || memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ size_t len, hlen, vlen;
+
+ check(hal_asn1_decode_header(ASN1_SEQUENCE, pubkey, pubkey_len, &hlen, &vlen));
+
+ const uint8_t * const pubkey_end = pubkey + hlen + vlen;
+ const uint8_t *d = pubkey + hlen;
+
+ // L || u32str(lms_type) || u32str(lmots_type) || I || T[1]
+
+ lms_algorithm_t lms_type;
+ lmots_algorithm_t lmots_type;
+
+ check(hal_asn1_decode_size_t(&key->L, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_lms_algorithm(&lms_type, d, &len, pubkey_end - d)); d += len;
+ key->lms = lms_select_parameter_set(lms_type);
+ check(hal_asn1_decode_lmots_algorithm(&lmots_type, d, &len, pubkey_end - d)); d += len;
+ key->lmots = lmots_select_parameter_set(lmots_type);
+ check(hal_asn1_decode_bytestring16(&key->I, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_bytestring32(&key->T1, d, &len, pubkey_end - d)); d += len;
+
+ if (d != pubkey_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+
+ return HAL_OK;
+}
+
+hal_error_t hal_hashsig_key_load_public(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const uint8_t * const I, const size_t I_len,
+ const uint8_t * const T1, const size_t T1_len)
+{
+ if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_hashsig_key_t) ||
+ I == NULL || I_len != sizeof(bytestring16) ||
+ T1 == NULL || T1_len != sizeof(bytestring32))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memset(keybuf, 0, keybuf_len);
+
+ hal_hashsig_key_t *key = keybuf;
+
+ key->type = HAL_KEY_TYPE_HASHSIG_PUBLIC;
+
+ key->L = L;
+ key->lms = lms_select_parameter_set(lms_type);
+ key->lmots = lmots_select_parameter_set(lmots_type);
+ if (key->lms == NULL || key->lmots == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ memcpy(&key->I, I, I_len);
+ memcpy(&key->T1, T1, T1_len);
+
+ *key_ = key;
+
+ return HAL_OK;
+}
+
+
+hal_error_t hal_hashsig_key_load_public_xdr(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const xdr, const size_t xdr_len)
+{
+ const uint8_t *xdrptr = xdr;
+ const uint8_t * const xdrlim = xdr + xdr_len;
+
+ /* L || u32str(lms_type) || u32str(lmots_type) || I || T[1] */
+
+ uint32_t L, lms_type, lmots_type;
+ bytestring16 *I;
+ bytestring32 *T1;
+
+ check(hal_xdr_decode_int(&xdrptr, xdrlim, &L));
+ check(hal_xdr_decode_int(&xdrptr, xdrlim, &lms_type));
+ check(hal_xdr_decode_int(&xdrptr, xdrlim, &lmots_type));
+ check(hal_xdr_decode_bytestring16_ptr(&xdrptr, xdrlim, &I));
+ check(hal_xdr_decode_bytestring32_ptr(&xdrptr, xdrlim, &T1));
+
+ return hal_hashsig_key_load_public(key_, keybuf, keybuf_len, L, lms_type, lmots_type,
+ (const uint8_t * const)I, sizeof(bytestring16),
+ (const uint8_t * const)T1, sizeof(bytestring32));
+}
+
+hal_error_t hal_hashsig_public_key_der_to_xdr(const uint8_t * const der, const size_t der_len,
+ uint8_t * const xdr, size_t * const xdr_len , const size_t xdr_max)
+{
+ if (der == NULL || xdr == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t *alg_oid = NULL, *null = NULL, *pubkey = NULL;
+ size_t alg_oid_len, null_len, pubkey_len;
+
+ check(hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &null, &null_len, &pubkey, &pubkey_len, der, der_len));
+
+ if (null != NULL || null_len != 0 || alg_oid == NULL ||
+ alg_oid_len != hal_asn1_oid_mts_hashsig_len || memcmp(alg_oid, hal_asn1_oid_mts_hashsig, alg_oid_len) != 0)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ size_t len, hlen, vlen;
+
+ check(hal_asn1_decode_header(ASN1_SEQUENCE, pubkey, pubkey_len, &hlen, &vlen));
+
+ const uint8_t * const pubkey_end = pubkey + hlen + vlen;
+ const uint8_t *d = pubkey + hlen;
+
+ // L || u32str(lms_type) || u32str(lmots_type) || I || T[1]
+
+ size_t L;
+ lms_algorithm_t lms_type;
+ lmots_algorithm_t lmots_type;
+ bytestring16 I;
+ bytestring32 T1;
+
+ check(hal_asn1_decode_size_t(&L, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_lms_algorithm(&lms_type, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_lmots_algorithm(&lmots_type, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_bytestring16(&I, d, &len, pubkey_end - d)); d += len;
+ check(hal_asn1_decode_bytestring32(&T1, d, &len, pubkey_end - d)); d += len;
+
+ if (d != pubkey_end)
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+
+ uint8_t * xdrptr = xdr;
+ const uint8_t * const xdrlim = xdr + xdr_max;
+
+ check(hal_xdr_encode_int(&xdrptr, xdrlim, L));
+ check(hal_xdr_encode_int(&xdrptr, xdrlim, lms_type));
+ check(hal_xdr_encode_int(&xdrptr, xdrlim, lmots_type));
+ check(hal_xdr_encode_bytestring16(&xdrptr, xdrlim, &I));
+ check(hal_xdr_encode_bytestring32(&xdrptr, xdrlim, &T1));
+
+ if (xdr_len != NULL)
+ *xdr_len = xdrptr - xdr;
+
+ return HAL_OK;
+}
+
+#if RPC_CLIENT == RPC_CLIENT_LOCAL
+/* Reinitialize the hashsig key structures after a device restart */
+hal_error_t hal_hashsig_ks_init(void)
+{
+ const hal_client_handle_t client = { -1 };
+ const hal_session_handle_t session = { HAL_HANDLE_NONE };
+ hal_uuid_t prev_name = {{0}};
+ unsigned len;
+ hal_pkey_slot_t slot = {0};
+ uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
+ size_t der_len;
+
+ /* Find all hss private keys */
+ while ((hal_ks_match(hal_ks_token, client, session,
+ HAL_KEY_TYPE_HASHSIG_PRIVATE, HAL_CURVE_NONE, 0, 0, NULL, 0,
+ &slot.name, &len, 1, &prev_name) == HAL_OK) && (len > 0)) {
+ hal_hashsig_key_t keybuf, *key;
+ if (hal_ks_fetch(hal_ks_token, &slot, der, &der_len, sizeof(der)) != HAL_OK ||
+ hal_hashsig_private_key_from_der(&key, (void *)&keybuf, sizeof(keybuf), der, der_len) != HAL_OK) {
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ continue;
+ }
+
+ /* Make sure we have the lms key */
+ hal_pkey_slot_t lms_slot = {0};
+ lms_key_t lms_key;
+ memcpy(&lms_slot.name, &key->I, sizeof(lms_slot.name));
+ if (hal_ks_fetch(hal_ks_token, &lms_slot, der, &der_len, sizeof(der)) != HAL_OK ||
+ lms_private_key_from_der(&lms_key, der, der_len) != HAL_OK ||
+ /* check keys for consistency */
+ lms_key.lms != key->lms ||
+ lms_key.lmots != key->lmots ||
+ memcmp(&lms_key.I, &key->I, sizeof(lms_key.I)) != 0 ||
+ /* optimistically allocate the full hss key structure */
+ hss_alloc(&key, key->L, key->lms->type, key->lmots->type) != HAL_OK) {
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ (void)hal_ks_delete(hal_ks_token, &lms_slot);
+ continue;
+ }
+
+ /* hss_alloc redefines key, so copy fields from the old version of the key */
+ memcpy(&key->I, &keybuf.I, sizeof(key->I));
+ memcpy(&key->T1, &keybuf.T1, sizeof(key->T1));
+ key->name = slot.name;
+
+ /* initialize top-level lms key (beyond what hss_alloc did) */
+ memcpy(&key->lms_keys[0].I, &lms_key.I, sizeof(lms_key.I));
+ key->lms_keys[0].q = lms_key.q;
+
+ prev_name = slot.name;
+ }
+
+ /* Delete orphaned lms keys */
+ memset(&prev_name, 0, sizeof(prev_name));
+ while ((hal_ks_match(hal_ks_token, client, session,
+ HAL_KEY_TYPE_HASHSIG_LMS, HAL_CURVE_NONE, 0, 0, NULL, 0,
+ &slot.name, &len, 1, &prev_name) == HAL_OK) && (len > 0)) {
+ hss_key_t *hss_key;
+ for (hss_key = hss_keys; hss_key != NULL; hss_key = hss_key->next) {
+ if (memcmp(&slot.name, &hss_key->I, sizeof(slot.name)) == 0)
+ break;
+ }
+ if (hss_key == NULL) {
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ continue;
+ }
+
+ prev_name = slot.name;
+ }
+
+ /* Find all lmots keys */
+ memset(&prev_name, 0, sizeof(prev_name));
+ while ((hal_ks_match(hal_ks_token, client, session,
+ HAL_KEY_TYPE_HASHSIG_LMOTS, HAL_CURVE_NONE, 0, 0, NULL, 0,
+ &slot.name, &len, 1, &prev_name) == HAL_OK) && (len > 0)) {
+ if (hss_keys == NULL) {
+ /* if no hss keys were recovered, all lmots keys are orphaned */
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ continue;
+ }
+
+ lmots_key_t lmots_key = {0};
+ if (hal_ks_fetch(hal_ks_token, &slot, der, &der_len, sizeof(der)) != HAL_OK ||
+ lmots_private_key_from_der(&lmots_key, der, der_len) != HAL_OK) {
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ continue;
+ }
+
+ hss_key_t *hss_key;
+ for (hss_key = hss_keys; hss_key != NULL; hss_key = hss_key->next) {
+ if (memcmp(&hss_key->I, &lmots_key.I, sizeof(lmots_key.I)) == 0)
+ break;
+ }
+ if (hss_key == NULL) {
+ /* delete orphaned key */
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ continue;
+ }
+
+ /* record this lmots key in the top-level lms key */
+ memcpy(&hss_key->lms_keys[0].lmots_keys[lmots_key.q], &slot.name, sizeof(slot.name));
+
+ /* compute T[r] = H(I || u32str(r) || u16str(D_LEAF) || K) */
+ size_t r = (1U << hss_key->lms->h) + lmots_key.q;
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf));
+ hal_hash_update(state, (const uint8_t *)&hss_key->I, sizeof(hss_key->I));
+ uint32_t l = u32str(r); hal_hash_update(state, (const uint8_t *)&l, sizeof(l));
+ uint16_t s = u16str(D_LEAF); hal_hash_update(state, (const uint8_t *)&s, sizeof(s));
+ hal_hash_update(state, (const uint8_t *)&lmots_key.K, sizeof(lmots_key.K));
+ hal_hash_finalize(state, (uint8_t *)&hss_key->lms_keys[0].T[r], sizeof(hss_key->lms_keys[0].T[r]));
+
+ prev_name = slot.name;
+ }
+
+ /* After all keys have been read, scan for completeness. */
+ hal_uuid_t uuid_0 = {{0}};
+ hss_key_t *hss_key, *hss_next = NULL;
+ for (hss_key = hss_keys; hss_key != NULL; hss_key = hss_next) {
+ hss_next = hss_key->next;
+ int fail = 0;
+ for (size_t i = 0; i < (1U << hss_key->lms->h); ++i) {
+ if (hal_uuid_cmp(&hss_key->lms_keys[0].lmots_keys[i], &uuid_0) == 0) {
+ fail = 1;
+ break;
+ }
+ }
+ if (fail) {
+ fail:
+ /* lms key is incomplete, give up on it */
+ /* delete lmots keys */
+ for (size_t i = 0; i < (1U << hss_key->lms->h); ++i) {
+ if (hal_uuid_cmp(&hss_key->lms_keys[0].lmots_keys[i], &uuid_0) != 0) {
+ memcpy(&slot.name, &hss_key->lms_keys[0].lmots_keys[i], sizeof(slot.name));
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ }
+ }
+ /* delete lms key */
+ memcpy(&slot.name, &hss_key->I, sizeof(slot.name));
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ /* delete hss key */
+ slot.name = hss_key->name;
+ (void)hal_ks_delete(hal_ks_token, &slot);
+ /* remove the hss key from the key list */
+ if (hss_keys == hss_key) {
+ hss_keys = hss_key->next;
+ }
+ else {
+ for (hss_key_t *prev = hss_keys; prev != NULL; prev = prev->next) {
+ if (prev->next == hss_key) {
+ prev->next = hss_key->next;
+ break;
+ }
+ }
+ }
+ (void)hal_free_static_memory(hss_key);
+ continue;
+ }
+
+ /* generate the rest of T[] */
+ for (size_t r = (1U << hss_key->lms->h) - 1; r > 0; --r) {
+ uint8_t statebuf[512];
+ hal_hash_state_t *state = NULL;
+ hal_hash_initialize(NULL, hal_hash_sha256, &state, statebuf, sizeof(statebuf));
+ hal_hash_update(state, (const uint8_t *)&hss_key->I, sizeof(hss_key->I));
+ uint32_t l = u32str(r); hal_hash_update(state, (const uint8_t *)&l, sizeof(l));
+ uint16_t s = u16str(D_INTR); check(hal_hash_update(state, (const uint8_t *)&s, sizeof(s)));
+ hal_hash_update(state, (const uint8_t *)&hss_key->lms_keys[0].T[2*r], sizeof(hss_key->lms_keys[0].T[r]));
+ hal_hash_update(state, (const uint8_t *)&hss_key->lms_keys[0].T[2*r+1], sizeof(hss_key->lms_keys[0].T[r]));
+ hal_hash_finalize(state, (uint8_t *)&hss_key->lms_keys[0].T[r], sizeof(hss_key->lms_keys[0].T[r]));
+ }
+ if (memcmp(&hss_key->lms_keys[0].T[1], &hss_key->T1, sizeof(hss_key->lms_keys[0].T[1])) != 0)
+ goto fail;
+
+ /* generate the lower-level lms keys */
+ for (size_t i = 1; i < hss_key->L; ++i) {
+ lms_key_t * lms_key = &hss_key->lms_keys[i];
+ if (lms_generate(lms_key) != HAL_OK)
+ goto fail;
+
+ /* store the lms key */
+ slot.type = HAL_KEY_TYPE_HASHSIG_LMS;
+ slot.flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
+ memcpy(&slot.name, &lms_key->I, sizeof(slot.name));
+ if (lms_private_key_to_der(lms_key, der, &der_len, sizeof(der)) != HAL_OK ||
+ hal_ks_store(hal_ks_volatile, &slot, der, der_len) != HAL_OK ||
+ /* sign this lms key with the previous */
+ lms_sign(&hss_key->lms_keys[i-1],
+ (const uint8_t * const)lms_key->pubkey, lms_key->pubkey_len,
+ lms_key->signature, NULL, lms_key->signature_len) != HAL_OK)
+ goto fail;
+ }
+ }
+
+ return HAL_OK;
+}
+#endif
diff --git a/hashsig.h b/hashsig.h
new file mode 100644
index 0000000..3753496
--- /dev/null
+++ b/hashsig.h
@@ -0,0 +1,118 @@
+/*
+ * hashsig.h
+ * ---------
+ * Implementation of draft-mcgrew-hash-sigs-08.txt
+ *
+ * Copyright (c) 2018, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _HAL_HASHSIG_H_
+#define _HAL_HASHSIG_H_
+
+typedef enum lmots_algorithm_type {
+ lmots_reserved = 0,
+ lmots_sha256_n32_w1 = 1,
+ lmots_sha256_n32_w2 = 2,
+ lmots_sha256_n32_w4 = 3,
+ lmots_sha256_n32_w8 = 4
+} lmots_algorithm_t;
+
+typedef enum lms_algorithm_type {
+ lms_reserved = 0,
+ lms_sha256_n32_h5 = 5,
+ lms_sha256_n32_h10 = 6,
+ lms_sha256_n32_h15 = 7,
+ lms_sha256_n32_h20 = 8,
+ lms_sha256_n32_h25 = 9
+} lms_algorithm_t;
+
+typedef struct hal_hashsig_key hal_hashsig_key_t;
+
+extern const size_t hal_hashsig_key_t_size;
+
+extern hal_error_t hal_hashsig_key_gen(hal_core_t *core,
+ hal_hashsig_key_t **key_,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type);
+
+extern hal_error_t hal_hashsig_key_delete(const hal_hashsig_key_t * const key);
+
+extern hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern size_t hal_hashsig_private_key_to_der_len(const hal_hashsig_key_t * const key);
+
+extern hal_error_t hal_hashsig_private_key_from_der(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t *der, const size_t der_len);
+
+extern hal_error_t hal_hashsig_public_key_to_der(const hal_hashsig_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max);
+
+extern size_t hal_hashsig_public_key_to_der_len(const hal_hashsig_key_t * const key);
+
+extern hal_error_t hal_hashsig_public_key_from_der(hal_hashsig_key_t **key,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len);
+
+extern hal_error_t hal_hashsig_sign(hal_core_t *core,
+ const hal_hashsig_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ uint8_t *signature, size_t *signature_len, const size_t signature_max);
+
+extern hal_error_t hal_hashsig_verify(hal_core_t *core,
+ const hal_hashsig_key_t * const key,
+ const uint8_t * const hash, const size_t hash_len,
+ const uint8_t * const signature, const size_t signature_len);
+
+extern hal_error_t hal_hashsig_key_load_public(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const uint8_t * const I, const size_t I_len,
+ const uint8_t * const T1, const size_t T1_len);
+
+extern hal_error_t hal_hashsig_key_load_public_xdr(hal_hashsig_key_t **key_,
+ void *keybuf, const size_t keybuf_len,
+ const uint8_t * const xdr, const size_t xdr_len);
+
+extern size_t hal_hashsig_signature_len(const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type);
+
+extern size_t hal_hashsig_lmots_private_key_len(const lmots_algorithm_t lmots_type);
+
+extern hal_error_t hal_hashsig_public_key_der_to_xdr(const uint8_t * const der, const size_t der_len,
+ uint8_t * const xdr, size_t * const xdr_len , const size_t xdr_max);
+
+extern hal_error_t hal_hashsig_ks_init(void);
+
+#endif /* _HAL_HASHSIG_H_ */
diff --git a/ks.c b/ks.c
new file mode 100644
index 0000000..c848056
--- /dev/null
+++ b/ks.c
@@ -0,0 +1,1033 @@
+/*
+ * ks.c
+ * ----
+ * Keystore, generic parts anyway. This is internal within libhal.
+ *
+ * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+#include "ks.h"
+
+/*
+ * PIN block gets the all-zeros UUID, which will never be returned by
+ * the UUID generation code (by definition -- it's not a version 4 UUID).
+ */
+
+const hal_uuid_t hal_ks_pin_uuid = {{0}};
+
+/*
+ * 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.
+ */
+
+#define BLOCK_UNUSED (~0U)
+
+hal_ks_block_t *hal_ks_cache_pick_lru(hal_ks_t *ks)
+{
+ uint32_t best_delta = 0;
+ int best_index = 0;
+
+ for (unsigned i = 0; i < ks->cache_size; i++) {
+
+ if (ks->cache[i].blockno == BLOCK_UNUSED)
+ return &ks->cache[i].block;
+
+ const unsigned delta = ks->cache_lru - ks->cache[i].lru;
+ if (delta > best_delta) {
+ best_delta = delta;
+ best_index = i;
+ }
+
+ }
+
+ ks->cache[best_index].blockno = BLOCK_UNUSED;
+ return &ks->cache[best_index].block;
+}
+
+/*
+ * Find a block in our in-memory cache; return block or NULL if not present.
+ */
+
+hal_ks_block_t *hal_ks_cache_find_block(const hal_ks_t * const ks, const unsigned blockno)
+{
+ for (unsigned i = 0; i < ks->cache_size; i++)
+ if (ks->cache[i].blockno == blockno)
+ return &ks->cache[i].block;
+ return NULL;
+}
+
+/*
+ * Mark a block in our in-memory cache as being in current use.
+ */
+
+void hal_ks_cache_mark_used(hal_ks_t *ks, const hal_ks_block_t * const block, const unsigned blockno)
+{
+ for (unsigned i = 0; i < ks->cache_size; i++) {
+ if (&ks->cache[i].block == block) {
+ ks->cache[i].blockno = blockno;
+ ks->cache[i].lru = ++ks->cache_lru;
+ return;
+ }
+ }
+}
+
+/*
+ * Release a block from the in-memory cache.
+ */
+
+void hal_ks_cache_release(hal_ks_t *ks, const hal_ks_block_t * const block)
+{
+ if (block != NULL)
+ hal_ks_cache_mark_used(ks, block, BLOCK_UNUSED);
+}
+
+/*
+ * Generate CRC-32 for a block.
+ *
+ * This function needs to understand the structure of the
+ * hal_ks_block_header_t, so that it can skip over fields that
+ * shouldn't be included in the CRC.
+ */
+
+hal_crc32_t hal_ks_block_calculate_crc(const hal_ks_block_t * const block)
+{
+ hal_crc32_t crc = hal_crc32_init();
+
+ if (block != NULL) {
+
+ crc = hal_crc32_update(crc, &block->header.block_type,
+ sizeof(block->header.block_type));
+
+ crc = hal_crc32_update(crc, &block->header.legacy_1,
+ sizeof(block->header.legacy_1));
+
+ crc = hal_crc32_update(crc, &block->header.legacy_2,
+ sizeof(block->header.legacy_2));
+
+ crc = hal_crc32_update(crc,
+ block->bytes + sizeof(hal_ks_block_header_t),
+ sizeof(*block) - sizeof(hal_ks_block_header_t));
+ }
+
+ return hal_crc32_finalize(crc);
+}
+
+/*
+ * 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 hal_ks_match() operation.
+ */
+
+hal_error_t hal_ks_block_read_cached(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t **block)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((*block = hal_ks_cache_find_block(ks, blockno)) != NULL)
+ return HAL_OK;
+
+ if ((*block = hal_ks_cache_pick_lru(ks)) == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ return hal_ks_block_read(ks, blockno, *block);
+}
+
+/*
+ * Update one block, including zombie jamboree.
+ */
+
+hal_error_t hal_ks_block_update(hal_ks_t *ks,
+ const unsigned b1,
+ hal_ks_block_t *block,
+ const hal_uuid_t * const uuid,
+ int *hint)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (ks->used == ks->size)
+ return HAL_ERROR_NO_KEY_INDEX_SLOTS;
+
+ hal_ks_cache_release(ks, block);
+
+ hal_error_t err;
+ unsigned b2;
+
+ if ((err = hal_ks_block_deprecate(ks, b1)) != HAL_OK ||
+ (err = hal_ks_index_replace(ks, uuid, &b2, hint)) != HAL_OK ||
+ (err = hal_ks_block_write(ks, b2, block)) != HAL_OK ||
+ (err = hal_ks_block_copy_owner(ks, b1, b2)) != HAL_OK ||
+ (err = hal_ks_block_zero(ks, b1)) != HAL_OK)
+ return err;
+
+ hal_ks_cache_mark_used(ks, block, b2);
+
+ /*
+ * Erase the first block in the free list. In case of restart, this
+ * puts the block back at the head of the free list.
+ */
+
+ return hal_ks_block_erase_maybe(ks, ks->index[ks->used]);
+}
+
+/*
+ * 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.
+ */
+
+hal_error_t hal_ks_init(hal_ks_t *ks, const int alloc)
+{
+ if (ks == NULL || ks->driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->init == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ hal_ks_lock();
+
+ const hal_error_t err = ks->driver->init(ks, alloc);
+
+ hal_ks_unlock();
+
+ return err;
+}
+
+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;
+}
+
+hal_error_t hal_ks_alloc_common(hal_ks_t *ks,
+ const unsigned ks_blocks,
+ const unsigned cache_blocks,
+ void **extra,
+ const size_t extra_len)
+{
+ /*
+ * We allocate a single big chunk of memory to make it atomic. We
+ * need all three of our blocks, so this way either all succeed or
+ * all fail; we allow our caller to piggyback its own memory needs
+ * (if any) on ours for the same reason.
+ */
+
+ size_t len = (sizeof(*ks->index) * ks_blocks +
+ sizeof(*ks->names) * ks_blocks +
+ sizeof(*ks->cache) * cache_blocks +
+ extra_len);
+
+ uint8_t *mem = hal_allocate_static_memory(len);
+
+ if (mem == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+
+ memset(((uint8_t *) ks) + sizeof(ks->driver), 0,
+ sizeof(hal_ks_t) - sizeof(ks->driver));
+ memset(mem, 0, len);
+
+ ks->index = gnaw(&mem, &len, sizeof(*ks->index) * ks_blocks);
+ ks->names = gnaw(&mem, &len, sizeof(*ks->names) * ks_blocks);
+ ks->cache = gnaw(&mem, &len, sizeof(*ks->cache) * cache_blocks);
+
+ ks->size = ks_blocks;
+ ks->cache_size = cache_blocks;
+
+ if (extra != NULL)
+ *extra = mem;
+
+ return HAL_OK;
+}
+
+hal_error_t hal_ks_init_common(hal_ks_t *ks)
+{
+ if (ks->index == NULL || ks->names == NULL || ks->cache == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ ks->used = 0;
+
+ for (unsigned i = 0; i < ks->cache_size; i++)
+ ks->cache[i].blockno = BLOCK_UNUSED;
+
+ /*
+ * Scan existing content of keystore 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.
+ */
+
+ hal_ks_block_type_t block_types[ks->size];
+ hal_ks_block_status_t block_status[ks->size];
+ hal_ks_block_t *block = hal_ks_cache_pick_lru(ks);
+ unsigned first_erased = BLOCK_UNUSED;
+ hal_error_t err;
+ uint16_t n = 0;
+
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ for (unsigned i = 0; i < ks->size; 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 end up near the end of the free list.
+ */
+
+ err = hal_ks_block_read(ks, i, block);
+
+ if (err == HAL_ERROR_KEYSTORE_BAD_CRC || err == HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE)
+ block_types[i] = HAL_KS_BLOCK_TYPE_UNKNOWN;
+
+ else if (err != HAL_OK)
+ return err;
+
+ else if ((block->header.legacy_1 != 0xFF || block->header.legacy_2 != 0xFF) &&
+ (block->header.legacy_1 != 0x01 || block->header.legacy_2 != 0x00))
+ block_types[i] = HAL_KS_BLOCK_TYPE_UNKNOWN;
+
+ else
+ block_types[i] = hal_ks_block_get_type(block);
+
+
+ switch (block_types[i]) {
+ case HAL_KS_BLOCK_TYPE_KEY:
+ case HAL_KS_BLOCK_TYPE_PIN:
+ block_status[i] = hal_ks_block_get_status(block);
+ break;
+ default:
+ block_status[i] = HAL_KS_BLOCK_STATUS_UNKNOWN;
+ }
+
+ /*
+ * First erased block we see is head of the free list.
+ */
+
+ if (block_types[i] == HAL_KS_BLOCK_TYPE_ERASED && first_erased == BLOCK_UNUSED)
+ 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 HAL_KS_BLOCK_TYPE_KEY: uuid = &block->key.name; break;
+ case HAL_KS_BLOCK_TYPE_PIN: uuid = &hal_ks_pin_uuid; break;
+ default: /* Keep GCC happy */ break;
+ }
+
+ if (uuid != NULL) {
+ ks->names[i] = *uuid;
+ ks->index[n++] = i;
+ }
+ }
+
+ ks->used = n;
+
+ if (ks->used > ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /*
+ * 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 < ks->size)
+ for (unsigned i = 0; i < ks->size; i++)
+ if (block_types[i] == HAL_KS_BLOCK_TYPE_ERASED)
+ ks->index[n++] = i;
+
+ if (n < ks->size && first_erased != BLOCK_UNUSED)
+ for (unsigned i = first_erased; i < ks->size; i++)
+ if (block_types[i] == HAL_KS_BLOCK_TYPE_ZEROED)
+ ks->index[n++] = i;
+
+ if (n < ks->size && first_erased != BLOCK_UNUSED)
+ for (unsigned i = 0; i < first_erased; i++)
+ if (block_types[i] == HAL_KS_BLOCK_TYPE_ZEROED)
+ ks->index[n++] = i;
+
+ if (n < ks->size)
+ for (unsigned i = 0; i < ks->size; i++)
+ if (block_types[i] == HAL_KS_BLOCK_TYPE_UNKNOWN)
+ ks->index[n++] = i;
+
+ if (ks->used > ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ /*
+ * Sort the index, then deal with tombstones. Tombstones are blocks
+ * left behind when something bad (like a power failure) happened
+ * while we updating. There can be at most one tombstone and one
+ * live block for a given UUID. If we find no live block, we need
+ * to restore it from the tombstone, after which we need to zero the
+ * tombstone in either case. The sequence of operations while
+ * updating is designed so that, barring a bug or a hardware
+ * failure, we should never lose data.
+ */
+
+ if ((err = hal_ks_index_heapsort(ks)) != HAL_OK)
+ return err;
+
+ for (unsigned b_tomb = 0; b_tomb < ks->size; b_tomb++) {
+
+ if (block_status[b_tomb] != HAL_KS_BLOCK_STATUS_TOMBSTONE)
+ continue;
+
+ hal_uuid_t name = ks->names[b_tomb];
+
+ int where = -1;
+
+ if ((err = hal_ks_index_find(ks, &name, NULL, &where)) != HAL_OK)
+ return err;
+
+ if (b_tomb != ks->index[where]) {
+ if ((int)ks->used > where + 1 && b_tomb == ks->index[where + 1])
+ where = where + 1;
+ else if (0 <= where - 1 && b_tomb == ks->index[where - 1])
+ where = where - 1;
+ else
+ return HAL_ERROR_IMPOSSIBLE;
+ }
+
+ const int matches_next = where + 1 < (int)ks->used && !hal_uuid_cmp(&name, &ks->names[ks->index[where + 1]]);
+ const int matches_prev = where - 1 >= 0 && !hal_uuid_cmp(&name, &ks->names[ks->index[where - 1]]);
+
+ if ((matches_prev && matches_next) ||
+ (matches_prev && block_status[ks->index[b_tomb - 1]] != HAL_KS_BLOCK_STATUS_LIVE) ||
+ (matches_next && block_status[ks->index[b_tomb + 1]] != HAL_KS_BLOCK_STATUS_LIVE))
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (matches_prev || matches_next) {
+ memmove(&ks->index[where], &ks->index[where + 1], (ks->size - where - 1) * sizeof(*ks->index));
+ ks->index[ks->size - 1] = b_tomb;
+ }
+
+ else {
+ unsigned b_live;
+ if ((err = hal_ks_block_read(ks, b_tomb, block)) != HAL_OK)
+ return err;
+ block->header.block_status = HAL_KS_BLOCK_STATUS_LIVE;
+ if ((err = hal_ks_index_replace(ks, &name, &b_live, &where)) != HAL_OK ||
+ (err = hal_ks_block_write(ks, b_live, block)) != HAL_OK)
+ return err;
+ block_status[b_live] = HAL_KS_BLOCK_STATUS_LIVE;
+ }
+
+ if ((err = hal_ks_block_zero(ks, b_tomb)) != HAL_OK)
+ return err;
+ block_types[ b_tomb] = HAL_KS_BLOCK_TYPE_ZEROED;
+ block_status[b_tomb] = HAL_KS_BLOCK_STATUS_UNKNOWN;
+ }
+
+ /*
+ * Erase first block on free list if it's not already erased.
+ */
+
+ if (ks->used < ks->size &&
+ (err = hal_ks_block_erase_maybe(ks, ks->index[ks->used])) != HAL_OK)
+ return err;
+
+ /*
+ * And we're finally done.
+ */
+
+ return HAL_OK;
+}
+
+/*
+ * Log a client out of a keystore.
+ */
+
+hal_error_t hal_ks_logout(hal_ks_t *ks, const hal_client_handle_t client)
+{
+ if (ks == NULL || ks->driver == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ if (ks->driver->logout == NULL)
+ return HAL_ERROR_NOT_IMPLEMENTED;
+
+ hal_ks_lock();
+
+ const hal_error_t err = ks->driver->logout(ks, client);
+
+ hal_ks_unlock();
+
+ return err;
+}
+
+/*
+ * Test whether we like a particular key type.
+ */
+
+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:
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_LMS:
+ case HAL_KEY_TYPE_HASHSIG_LMOTS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Internal bits of constructing a new key block.
+ */
+
+static hal_error_t construct_key_block(hal_ks_block_t *block,
+ hal_pkey_slot_t *slot,
+ const uint8_t * const der, const size_t der_len)
+{
+ if (block == NULL || slot == NULL || der == NULL || der_len == 0)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_ks_key_block_t *k = &block->key;
+ hal_error_t err = HAL_OK;
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+
+ memset(block, 0xFF, sizeof(*block));
+
+ block->header.block_type = HAL_KS_BLOCK_TYPE_KEY;
+ block->header.block_status = HAL_KS_BLOCK_STATUS_LIVE;
+
+ k->name = slot->name;
+ k->type = slot->type;
+ k->curve = slot->curve;
+ k->flags = slot->flags;
+ k->der_len = SIZEOF_KS_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));
+
+ return err;
+}
+
+/*
+ * Store a key block.
+ */
+
+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 || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err = HAL_OK;
+ hal_ks_block_t *block;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((block = hal_ks_cache_pick_lru(ks)) == NULL) {
+ err = HAL_ERROR_IMPOSSIBLE;
+ goto done;
+ }
+
+ if ((err = hal_ks_index_add(ks, &slot->name, &b, &slot->hint)) != HAL_OK)
+ goto done;
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ if (ks->used < ks->size)
+ err = hal_ks_block_erase_maybe(ks, ks->index[ks->used]);
+
+ if (err == HAL_OK)
+ err = construct_key_block(block, slot, der, der_len);
+
+ if (err == HAL_OK)
+ err = hal_ks_block_write(ks, b, block);
+
+ if (err == HAL_OK)
+ err = hal_ks_block_set_owner(ks, b, slot->client, slot->session);
+
+ if (err == HAL_OK)
+ goto done;
+
+ memset(block, 0, sizeof(*block));
+ hal_ks_cache_release(ks, block);
+ (void) hal_ks_index_delete(ks, &slot->name, NULL, &slot->hint);
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+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 || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err = HAL_OK;
+ hal_ks_block_t *block;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((err = hal_ks_index_find(ks, &slot->name, &b, &slot->hint)) != HAL_OK ||
+ (err = hal_ks_block_test_owner(ks, b, slot->client, slot->session)) != HAL_OK ||
+ (err = hal_ks_block_read_cached(ks, b, &block)) != HAL_OK)
+ goto done;
+
+ if (hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_KEY) {
+ err = HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE; /* HAL_ERROR_KEY_NOT_FOUND */
+ goto done;
+ }
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ hal_ks_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));
+ }
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+hal_error_t hal_ks_delete(hal_ks_t *ks,
+ hal_pkey_slot_t *slot)
+{
+ if (ks == NULL || slot == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err = HAL_OK;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((err = hal_ks_index_delete(ks, &slot->name, &b, &slot->hint)) != HAL_OK ||
+ (err = hal_ks_block_test_owner(ks, b, slot->client, slot->session)) != HAL_OK)
+ goto done;
+
+ hal_ks_cache_release(ks, hal_ks_cache_find_block(ks, b));
+
+ if ((err = hal_ks_block_zero(ks, b)) != HAL_OK)
+ goto done;
+
+ err = hal_ks_block_erase_maybe(ks, ks->index[ks->used]);
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+static inline hal_error_t locate_attributes(hal_ks_block_t *block,
+ 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 (hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_KEY)
+ return HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE;
+ *attrs_len = &block->key.attributes_len;
+ *bytes = block->key.der + block->key.der_len;
+ *bytes_len = SIZEOF_KS_KEY_BLOCK_DER - block->key.der_len;
+
+ return HAL_OK;
+}
+
+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 mask,
+ 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;
+
+ hal_error_t err = HAL_OK;
+ hal_ks_block_t *block;
+ int i = -1;
+
+ hal_ks_lock();
+
+ *result_len = 0;
+
+ err = hal_ks_index_find(ks, previous_uuid, NULL, &i);
+
+ if (err == HAL_ERROR_KEY_NOT_FOUND)
+ i--;
+ else if (err != HAL_OK)
+ goto done;
+
+ while (*result_len < result_max && ++i < (int)ks->used) {
+
+ unsigned b = ks->index[i];
+
+ if ((err = hal_ks_block_read_cached(ks, b, &block)) != HAL_OK)
+ goto done;
+
+ if ((err = hal_ks_block_test_owner(ks, b, client, session)) == HAL_ERROR_KEY_NOT_FOUND)
+ continue;
+
+ if (err != HAL_OK)
+ goto done;
+
+ if ((type != HAL_KEY_TYPE_NONE && type != block->key.type) ||
+ (curve != HAL_CURVE_NONE && curve != block->key.curve) ||
+ ((flags ^ block->key.flags) & mask) != 0)
+ continue;
+
+ if (attributes_len > 0) {
+ uint8_t need_attr[attributes_len];
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+ int possible = 1;
+
+ memset(need_attr, 1, sizeof(need_attr));
+
+ if ((err = locate_attributes(block, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ goto done;
+
+ 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)
+ goto done;
+
+ for (unsigned 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;
+ }
+ }
+ }
+
+ if (!possible || memchr(need_attr, 1, sizeof(need_attr)) != NULL)
+ continue;
+ }
+
+ result[*result_len] = ks->names[b];
+ ++*result_len;
+ }
+
+ err = HAL_OK;
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+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 || slot == NULL || attributes == NULL || attributes_len == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_error_t err = HAL_OK;
+ hal_ks_block_t *block;
+ unsigned b;
+
+ hal_ks_lock();
+
+ {
+ if ((err = hal_ks_index_find(ks, &slot->name, &b, &slot->hint)) != HAL_OK ||
+ (err = hal_ks_block_test_owner(ks, b, slot->client, slot->session)) != HAL_OK ||
+ (err = hal_ks_block_read_cached(ks, b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ goto done;
+
+ 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)
+ goto done;
+
+ for (unsigned 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)
+ err = hal_ks_block_update(ks, b, block, &slot->name, &slot->hint);
+ else
+ hal_ks_cache_release(ks, block);
+ }
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+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 || slot == NULL || attributes == NULL || attributes_len == 0 ||
+ attributes_buffer == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ for (unsigned i = 0; i < attributes_len; i++) {
+ attributes[i].length = 0;
+ attributes[i].value = NULL;
+ }
+
+ uint8_t *abuf = attributes_buffer;
+ hal_ks_block_t *block = NULL;
+ hal_error_t err = HAL_OK;
+ unsigned found = 0;
+ unsigned b;
+
+ hal_ks_lock();
+
+ {
+ if ((err = hal_ks_index_find(ks, &slot->name, &b, &slot->hint)) != HAL_OK ||
+ (err = hal_ks_block_test_owner(ks, b, slot->client, slot->session)) != HAL_OK ||
+ (err = hal_ks_block_read_cached(ks, b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ uint8_t *bytes = NULL;
+ size_t bytes_len = 0;
+ unsigned *attrs_len;
+
+ if ((err = locate_attributes(block, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
+ goto done;
+
+ if (*attrs_len == 0) {
+ err = HAL_ERROR_ATTRIBUTE_NOT_FOUND;
+ goto done;
+ }
+
+ hal_pkey_attribute_t attrs[*attrs_len];
+
+ if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
+ goto done;
+
+ for (unsigned i = 0; i < attributes_len; i++) {
+
+ if (attributes[i].length > 0)
+ continue;
+
+ unsigned 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 > (size_t)(attributes_buffer + attributes_buffer_len - abuf)) {
+ err = HAL_ERROR_RESULT_TOO_LONG;
+ goto done;
+ }
+
+ memcpy(abuf, attrs[j].value, attrs[j].length);
+ attributes[i].value = abuf;
+ abuf += attrs[j].length;
+ }
+
+ };
+
+ if (found < attributes_len && attributes_buffer_len > 0)
+ err = HAL_ERROR_ATTRIBUTE_NOT_FOUND;
+ else
+ err = HAL_OK;
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+hal_error_t hal_ks_rewrite_der(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;
+
+ hal_ks_block_t *block = NULL;
+ hal_error_t err = HAL_OK;
+ unsigned b;
+
+ hal_ks_lock();
+
+ {
+ if ((err = hal_ks_index_find(ks, &slot->name, &b, &slot->hint)) != HAL_OK ||
+ (err = hal_ks_block_test_owner(ks, b, slot->client, slot->session)) != HAL_OK ||
+ (err = hal_ks_block_read_cached(ks, b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ size_t bytes_len = 0, attributes_len = 0;
+ unsigned *count = NULL;
+ uint8_t *bytes = NULL;
+
+ if ((err = locate_attributes(block, &bytes, &bytes_len, &count)) != HAL_OK ||
+ (err = hal_ks_attribute_scan(bytes, bytes_len, NULL, *count, &attributes_len)) != HAL_OK)
+ goto done;
+
+ if (der_len + attributes_len > SIZEOF_KS_KEY_BLOCK_DER) {
+ err = HAL_ERROR_RESULT_TOO_LONG;
+ goto done;
+ }
+
+ uint8_t attributes[attributes_len > 0 ? attributes_len : 1];
+ hal_ks_key_block_t *k = &block->key;
+ unsigned attributes_count = *count;
+
+ memcpy(attributes, bytes, attributes_len);
+
+ if ((err = construct_key_block(block, slot, der, der_len)) != HAL_OK)
+ goto done;
+
+ if (k->der_len + attributes_len > SIZEOF_KS_KEY_BLOCK_DER) {
+ err = HAL_ERROR_IMPOSSIBLE;
+ goto done;
+ }
+
+ memcpy(k->der + k->der_len, attributes, attributes_len);
+ k->attributes_len = attributes_count;
+
+ err = hal_ks_block_update(ks, b, block, &slot->name, &slot->hint);
+ }
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+hal_error_t hal_ks_available(hal_ks_t *ks, size_t *count)
+{
+ if (ks == NULL || count == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ hal_ks_lock();
+ *count = ks->size - ks->used;
+ hal_ks_unlock();
+
+ return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks.h b/ks.h
new file mode 100644
index 0000000..e1f865c
--- /dev/null
+++ b/ks.h
@@ -0,0 +1,437 @@
+/*
+ * ks.h
+ * ----
+ * Keystore, generic parts anyway. This is internal within libhal.
+ *
+ * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KS_H_
+#define _KS_H_
+
+#include "hal.h"
+#include "hal_internal.h"
+
+/*
+ * Size of a keystore "block".
+ *
+ * This must be an integer multiple of the flash subsector size, among
+ * other reasons because that's the minimum erasable unit.
+ */
+
+#ifndef HAL_KS_BLOCK_SIZE
+#define HAL_KS_BLOCK_SIZE (4096 * 2)
+#endif
+
+#if HAL_KS_WRAPPED_KEYSIZE + 8 > HAL_KS_BLOCK_SIZE
+#warning HAL_KS_WRAPPED_KEYSIZE is too big for to fit in a keystore block
+#endif
+
+/*
+ * PIN block gets the all-zeros UUID, which will never be returned by
+ * the UUID generation code (by definition -- it's not a version 4 UUID).
+ */
+
+const hal_uuid_t hal_ks_pin_uuid;
+
+/*
+ * Known block states.
+ *
+ * C does not guarantee any particular representation for enums, so
+ * including enums directly in the block header isn't safe. Instead,
+ * we use an access method which casts when reading from the header.
+ * Writing to the header isn't a problem, because C does guarantee
+ * that enum is compatible with *some* integer type, it just doesn't
+ * specify which one.
+ */
+
+typedef enum {
+ HAL_KS_BLOCK_TYPE_ERASED = 0xFF, /* Pristine erased block (candidate for reuse) */
+ HAL_KS_BLOCK_TYPE_ZEROED = 0x00, /* Zeroed block (recently used) */
+ HAL_KS_BLOCK_TYPE_KEY = 0x55, /* Block contains key material */
+ HAL_KS_BLOCK_TYPE_PIN = 0xAA, /* Block contains PINs */
+ HAL_KS_BLOCK_TYPE_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} hal_ks_block_type_t;
+
+/*
+ * Block status.
+ */
+
+typedef enum {
+ HAL_KS_BLOCK_STATUS_LIVE = 0x66, /* This is a live block */
+ HAL_KS_BLOCK_STATUS_TOMBSTONE = 0x44, /* This is a tombstone left behind during an update */
+ HAL_KS_BLOCK_STATUS_UNKNOWN = -1, /* Internal code for "I have no clue what this is" */
+} hal_ks_block_status_t;
+
+/*
+ * Common header for all keystore block types. A few of these fields
+ * are deliberately omitted from the CRC.
+ *
+ * The legacy_1 and legacy_2 fields were used in the more complex
+ * "chunked" layout used in an earlier iteration of this keystore
+ * design, which proved more complex than it was worth. At the
+ * moment, the only thing we do with these fields is include them in
+ * the CRC and check them for allowed values, to avoid gratuitously
+ * breaking backwards compatability with the earlier design.
+ */
+
+typedef struct {
+ uint8_t block_type;
+ uint8_t block_status;
+ uint8_t legacy_1;
+ uint8_t legacy_2;
+ hal_crc32_t crc;
+} hal_ks_block_header_t;
+
+/*
+ * Key block. Tail end of "der" field (after der_len) used for attributes.
+ */
+
+typedef struct {
+ hal_ks_block_header_t header;
+ hal_uuid_t name;
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ hal_key_flags_t flags;
+ size_t der_len;
+ unsigned attributes_len;
+ uint8_t der[]; /* Must be last field -- C99 "flexible array member" */
+} hal_ks_key_block_t;
+
+#define SIZEOF_KS_KEY_BLOCK_DER \
+ (HAL_KS_BLOCK_SIZE - offsetof(hal_ks_key_block_t, der))
+
+/*
+ * PIN block. Also includes space for backing up the KEK when
+ * HAL_MKM_FLASH_BACKUP_KLUDGE is enabled.
+ */
+
+typedef struct {
+ hal_ks_block_header_t header;
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+#if HAL_MKM_FLASH_BACKUP_KLUDGE
+ uint32_t kek_set;
+ uint8_t kek[KEK_LENGTH];
+#endif
+} hal_ks_pin_block_t;
+
+#define FLASH_KEK_NOT_SET 0
+#define FLASH_KEK_SET 0x33333333
+
+/*
+ * One keystore block.
+ */
+
+typedef union {
+ uint8_t bytes[HAL_KS_BLOCK_SIZE];
+ hal_ks_block_header_t header;
+ hal_ks_key_block_t key;
+ hal_ks_pin_block_t pin;
+} hal_ks_block_t;
+
+/*
+ * In-memory cache.
+ */
+
+typedef struct {
+ unsigned blockno;
+ unsigned lru;
+ hal_ks_block_t block;
+} hal_ks_cache_block_t;
+
+/*
+ * Keystore object. hal_internal.h typedefs this to hal_ks_t.
+ *
+ * We expect this to be a static variable, but we expect the arrays in
+ * it to be allocated at runtime using hal_allocate_static_memory()
+ * because they can get kind of large.
+ *
+ * Driver-specific stuff is handled by a form of subclassing: the
+ * driver embeds the hal_ks_t structure at the head of whatever else
+ * it needs, and performs (controlled, type-safe) casts as needed.
+ *
+ * Core of this is the keystore index. This is intended to be usable
+ * by both memory-based and flash-based keystores. Some of the
+ * features aren't necessary for memory-based keystores, but should be
+ * harmless, and let us keep the drivers simple.
+ *
+ * General approach is multiple arrays, all but one of which are
+ * indexed by "block" numbers, where a block number might be a slot in
+ * yet another static array, the number of a flash sub-sector, or
+ * whatever is the appropriate unit for holding one keystore record.
+ *
+ * The index array only contains block numbers. This is a small data
+ * structure so that moving data within it is relatively cheap.
+ *
+ * The index array is divided into two portions: the index proper, and
+ * the free queue. The index proper is ordered according to the names
+ * (UUIDs) of the corresponding blocks; the free queue is a FIFO, to
+ * support a simplistic form of wear leveling in flash-based keystores.
+ *
+ * Key names are kept in a separate array, indexed by block number.
+ *
+ * The all-zeros UUID, which (by definition) cannot be a valid key
+ * UUID, is reserved for the (non-key) block used to stash PINs and
+ * other small data which aren't really part of the keystore proper
+ * but are kept with it because the keystore is the flash we have.
+ *
+ * Note that this API deliberately says nothing about how the keys
+ * themselves are stored, that's up to the keystore driver.
+ */
+
+typedef struct hal_ks_driver hal_ks_driver_t;
+
+struct hal_ks {
+ const hal_ks_driver_t *driver;/* Must be first */
+ unsigned size; /* Blocks in keystore */
+ unsigned used; /* How many blocks are in use */
+ uint16_t *index; /* Index/freelist array */
+ hal_uuid_t *names; /* Keyname array */
+ unsigned cache_lru; /* Cache LRU counter */
+ unsigned cache_size; /* Size (how many blocks) in cache */
+ hal_ks_cache_block_t *cache; /* Cache */
+};
+
+/*
+ * Keystore driver.
+ */
+
+struct hal_ks_driver {
+ hal_error_t (*init) (hal_ks_t *ks, const int alloc);
+ hal_error_t (*read) (hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block);
+ hal_error_t (*write) (hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block);
+ hal_error_t (*deprecate) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*zero) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*erase) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*erase_maybe) (hal_ks_t *ks, const unsigned blockno);
+ hal_error_t (*set_owner) (hal_ks_t *ks, const unsigned blockno,
+ const hal_client_handle_t client, const hal_session_handle_t session);
+ hal_error_t (*test_owner) (hal_ks_t *ks, const unsigned blockno,
+ const hal_client_handle_t client, const hal_session_handle_t session);
+ hal_error_t (*copy_owner) (hal_ks_t *ks, const unsigned source, const unsigned target);
+ hal_error_t (*logout) (hal_ks_t *ks, const hal_client_handle_t client);
+};
+
+/*
+ * Wrappers around keystore driver methods.
+ *
+ * hal_ks_init() and hal_ks_logout() are missing here because we
+ * expose them to the rest of libhal.
+ */
+
+static inline hal_error_t hal_ks_block_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->read == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->read(ks, blockno, block);
+}
+
+static inline hal_error_t hal_ks_block_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->write == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->write(ks, blockno, block);
+}
+
+static inline hal_error_t hal_ks_block_deprecate(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->deprecate == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->deprecate(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_zero(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->zero == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->zero(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_erase(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->erase == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->erase(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_erase_maybe(hal_ks_t *ks, const unsigned blockno)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->erase_maybe == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->erase_maybe(ks, blockno);
+}
+
+static inline hal_error_t hal_ks_block_set_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->set_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->set_owner(ks, blockno, client, session);
+}
+
+static inline hal_error_t hal_ks_block_test_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->test_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->test_owner(ks, blockno, client, session);
+}
+
+static inline hal_error_t hal_ks_block_copy_owner(hal_ks_t *ks,
+ const unsigned source,
+ const unsigned target)
+{
+ return
+ ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS :
+ ks->driver->copy_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED :
+ ks->driver->copy_owner(ks, source, target);
+}
+
+/*
+ * Type safe casts.
+ */
+
+static inline hal_ks_block_type_t hal_ks_block_get_type(const hal_ks_block_t * const block)
+{
+ return block == NULL ? HAL_KS_BLOCK_TYPE_UNKNOWN :
+ (hal_ks_block_type_t) block->header.block_type;
+}
+
+static inline hal_ks_block_status_t hal_ks_block_get_status(const hal_ks_block_t * const block)
+{
+ return block == NULL ? HAL_KS_BLOCK_STATUS_UNKNOWN :
+ (hal_ks_block_status_t) block->header.block_status;
+}
+
+/*
+ * Keystore utilities. Some or all of these may end up static within ks.c.
+ */
+
+extern hal_error_t hal_ks_alloc_common(hal_ks_t *ks,
+ const unsigned ks_blocks,
+ const unsigned cache_blocks,
+ void **extra,
+ const size_t extra_len);
+
+extern hal_error_t hal_ks_init_common(hal_ks_t *ks);
+
+extern hal_crc32_t hal_ks_block_calculate_crc(const hal_ks_block_t * const block);
+
+extern hal_error_t hal_ks_index_heapsort(hal_ks_t *ks);
+
+extern hal_error_t hal_ks_index_find(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_add(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_delete(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_replace(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
+ int *hint);
+
+extern hal_error_t hal_ks_index_fsck(hal_ks_t *ks);
+
+extern const size_t hal_ks_attribute_header_size;
+
+extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ size_t *total_len);
+
+extern hal_error_t hal_ks_attribute_delete(uint8_t *bytes,
+ const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type);
+
+extern hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
+ hal_pkey_attribute_t *attributes,
+ unsigned *attributes_len,
+ size_t *total_len,
+ const uint32_t type,
+ const uint8_t * const value,
+ const size_t value_len);
+
+extern hal_ks_block_t *hal_ks_cache_pick_lru(hal_ks_t *ks);
+
+extern hal_ks_block_t *hal_ks_cache_find_block(const hal_ks_t * const ks,
+ const unsigned blockno);
+
+extern void hal_ks_cache_mark_used(hal_ks_t *ks,
+ const hal_ks_block_t * const block,
+ const unsigned blockno);
+
+extern void hal_ks_cache_release(hal_ks_t *ks,
+ const hal_ks_block_t * const block);
+
+extern hal_error_t hal_ks_block_read_cached(hal_ks_t *ks,
+ const unsigned blockno,
+ hal_ks_block_t **block);
+
+extern hal_error_t hal_ks_block_update(hal_ks_t *ks,
+ const unsigned b1,
+ hal_ks_block_t *block,
+ const hal_uuid_t * const uuid,
+ int *hint);
+
+extern hal_error_t hal_ks_available(hal_ks_t *ks, size_t *count);
+
+#endif /* _KS_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_attribute.c b/ks_attribute.c
index ec674f5..1eefefb 100644
--- a/ks_attribute.c
+++ b/ks_attribute.c
@@ -89,7 +89,7 @@ hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, const size_t byte
const uint8_t *b = bytes;
const uint8_t * const end = bytes + bytes_len;
- for (int i = 0; i < attributes_len; i++) {
+ for (unsigned i = 0; i < attributes_len; i++) {
uint32_t type;
size_t length;
hal_error_t err = read_header(b, end - b, &type, &length);
@@ -125,7 +125,7 @@ hal_error_t hal_ks_attribute_delete(uint8_t *bytes, const size_t bytes_len,
* attribute of any given type.
*/
- int i = 0;
+ unsigned i = 0;
while (i < *attributes_len && attributes[i].type != type)
i++;
diff --git a/ks_flash.c b/ks_flash.c
deleted file mode 100644
index 8aadc37..0000000
--- a/ks_flash.c
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * ks_flash.c
- * ----------
- * Keystore implementation in flash memory.
- *
- * Authors: Rob Austein, Fredrik Thulin
- * 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
- * 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 keystore driver operates over bare flash, versus over a flash file
- * system or flash translation layer. The block size is large enough to
- * hold an AES-keywrapped 4096-bit RSA key. Any remaining space in the key
- * block may be used to store attributes (opaque TLV blobs). If the
- * attributes overflow the key block, additional blocks may be added, but
- * no attribute may exceed the block size.
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-
-#include "hal.h"
-#include "hal_internal.h"
-
-#include "last_gasp_pin_internal.h"
-
-#define HAL_OK CMIS_HAL_OK
-#include "stm-keystore.h"
-#undef HAL_OK
-
-/*
- * 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;
-
-/*
- * 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;
-
-/*
- * PIN block gets the all-zeros UUID, which will never be returned by
- * the UUID generation code (by definition -- it's not a version 4 UUID).
- */
-
-const static hal_uuid_t pin_uuid = {{0}};
-
-/*
- * 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.
- */
-
-static db_t db;
-
-/*
- * Type safe casts.
- */
-
-static inline flash_block_type_t block_get_type(const flash_block_t * const block)
-{
- assert(block != NULL);
- return (flash_block_type_t) block->header.block_type;
-}
-
-static inline flash_block_status_t block_get_status(const flash_block_t * const block)
-{
- assert(block != NULL);
- return (flash_block_status_t) block->header.block_status;
-}
-
-/*
- * 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 best_delta = 0;
- int best_index = 0;
-
- for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
-
- if (db.cache[i].blockno == ~0)
- return &db.cache[i].block;
-
- const uint32_t delta = db.cache_lru - db.cache[i].lru;
- if (delta > best_delta) {
- best_delta = delta;
- best_index = i;
- }
-
- }
-
- db.cache[best_index].blockno = ~0;
- return &db.cache[best_index].block;
-}
-
-/*
- * Find a block in our in-memory cache; return block or NULL if not present.
- */
-
-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;
-}
-
-/*
- * Mark a block in our in-memory cache as being in current use.
- */
-
-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;
- }
- }
-}
-
-/*
- * 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);
-}
-
-/*
- * 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)
-{
- assert(block != NULL);
-
- 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 offset of the block in the flash address space.
- */
-
-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_subsector(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);
-
- 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);
-
- /*
- * Erase the first block in the free list. In case of restart, this
- * puts the block back at the head of the free list.
- */
-
- return block_erase_maybe(db.ksi.index[db.ksi.used]);
-}
-
-/*
- * Forward reference.
- */
-
-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 err = HAL_OK;
-
- hal_ks_lock();
-
- /*
- * 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);
-
- /*
- * This is done as a single large allocation, rather than 3 smaller
- * allocations, to make it atomic - we need all 3, so either all
- * succeed or all fail.
- */
-
- uint8_t *mem = hal_allocate_static_memory(len);
-
- if (mem == NULL) {
- err = HAL_ERROR_ALLOCATION_FAILURE;
- goto done;
- }
-
- 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) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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;
- uint16_t n = 0;
-
- if (block == NULL) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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 end 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
- goto done;
-
- 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;
- }
-
- /*
- * 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;
- }
-
- 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)
- goto done;
-
- /*
- * 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. This basically works in reverse of
- * the update sequence in ks_set_attributes().
- *
- * If we can construct a valid sequence of live blocks, the complete
- * update was written out, and we just need to finish zeroing 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
- * 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 none of the new data was 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)
- goto done;
-
- /*
- * hal_ks_index_find_range does a binary search, not a linear search,
- * so it may not return the first instance of a block with the given
- * name and chunk=0. Search backwards to make sure we have all chunks.
- */
-
- while (where > 0 && !hal_uuid_cmp(&name, &db.ksi.names[db.ksi.index[where - 1]].name)) {
- where--;
- n_blocks++;
- }
-
- /*
- * Rather than calling hal_ks_index_find_range with an array pointer
- * to get the list of matching blocks (because of the binary search
- * issue), we're going to fondle the index directly. This is really
- * not something to do in regular code, but this is error-recovery
- * code.
- */
-
- 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: err = HAL_ERROR_IMPOSSIBLE; goto done;
- }
- }
-
- 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];
-
- if ((err = block_read(b, block)) != HAL_OK)
- goto done;
-
- 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:
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
- }
-
- if (!live_ok && !tomb_ok && !join_ok) {
- err = HAL_ERROR_KEYSTORE_LOST_DATA;
- goto done;
- }
-
- /*
- * If live_ok or tomb_ok, we have to zero out some blocks, and adjust
- * the index. Again, don't fondle the index directly, outside of error
- * recovery.
- */
-
- if (live_ok) {
- for (int j = 0; j < n_tomb; j++) {
- const unsigned b = tomb_blocks[j];
- if ((err = block_zero(b)) != HAL_OK)
- goto done;
- 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)
- goto done;
- 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;
- }
-
- /*
- * Restore tombstone blocks (tomb_ok or join_ok).
- */
-
- 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)
- goto done;
- 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)
- goto done;
- block_types[b1] = BLOCK_TYPE_ZEROED;
- block_status[b1] = BLOCK_STATUS_UNKNOWN;
- block_status[b2] = BLOCK_STATUS_LIVE;
- }
- }
-
- /*
- * Fetch or create the PIN block.
- */
-
- 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)
- goto done;
-
- 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)
- goto done;
-
- cache_mark_used(block, b);
-
- err = block_write(b, block);
-
- cache_release(block);
-
- if (err != HAL_OK)
- goto done;
- }
-
- /*
- * 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)
- goto done;
-
- /*
- * And we're finally done.
- */
-
- db.ks.driver = driver;
-
- err = HAL_OK;
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-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;
-
- hal_error_t err = HAL_OK;
- flash_block_t *block;
- flash_key_block_t *k;
- uint8_t kek[KEK_LENGTH];
- size_t kek_len;
- unsigned b;
-
- hal_ks_lock();
-
- if ((block = cache_pick_lru()) == NULL) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- k = &block->key;
-
- if ((err = hal_ks_index_add(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- 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 (db.ksi.used < db.ksi.size)
- err = block_erase_maybe(db.ksi.index[db.ksi.used]);
-
- if (err == HAL_OK)
- err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek));
-
- if (err == 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);
-
- if (err == HAL_OK)
- goto done;
-
- memset(block, 0, sizeof(*block));
- cache_release(block);
- (void) hal_ks_index_delete(&db.ksi, &slot->name, 0, NULL, &slot->hint);
-
- done:
- hal_ks_unlock();
- 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;
-
- hal_error_t err = HAL_OK;
- flash_block_t *block;
- unsigned b;
-
- hal_ks_lock();
-
- if ((err = hal_ks_index_find(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK ||
- (err = block_read_cached(b, &block)) != HAL_OK)
- goto done;
-
- if (block_get_type(block) != BLOCK_TYPE_KEY) {
- err = HAL_ERROR_KEYSTORE_WRONG_BLOCK_TYPE; /* HAL_ERROR_KEY_NOT_FOUND */
- goto done;
- }
-
- 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));
- }
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-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 = HAL_OK;
- unsigned n;
-
- hal_ks_lock();
-
- {
- /*
- * Get the count of blocks to delete.
- */
-
- if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, 0, &n, NULL, &slot->hint)) != HAL_OK)
- goto done;
-
- /*
- * Then delete them.
- */
-
- unsigned b[n];
-
- if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, n, NULL, b, &slot->hint)) != HAL_OK)
- goto done;
-
- for (int i = 0; i < n; i++)
- cache_release(cache_find_block(b[i]));
-
- /*
- * Zero the blocks, to mark them as recently used.
- */
-
- for (int i = 0; i < n; i++)
- if ((err = block_zero(b[i])) != HAL_OK)
- goto done;
-
- /*
- * Erase the first block in the free list. In case of restart, this
- * puts the block back at the head of the free list.
- */
-
- err = block_erase_maybe(db.ksi.index[db.ksi.used]);
- }
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-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 mask,
- 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];
- hal_error_t err = HAL_OK;
- flash_block_t *block;
- int possible = 0;
- int i = -1;
-
- hal_ks_lock();
-
- *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)
- goto done;
-
- 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)
- goto done;
-
- 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) &&
- ((flags ^ block->key.flags) & mask) == 0);
- }
-
- 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)
- goto done;
-
- 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)
- goto done;
-
- 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;
- }
- }
- }
- }
-
- 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;
- }
-
- err = HAL_OK;
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-/*
- * 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)
-{
- if (ks != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0)
- 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.
- */
-
- unsigned updated_attributes_len = attributes_len;
- hal_error_t err = HAL_OK;
- flash_block_t *block;
- unsigned chunk = 0;
- unsigned b;
-
- hal_ks_lock();
-
- {
-
- 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)
- goto done;
-
- if (block->header.this_chunk != chunk) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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)
- goto done;
-
- 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)
- goto done;
-
- 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)
- err = block_update(b, block, &slot->name, chunk, &hint);
-
- goto done;
-
-#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;
-
- updated_attributes_len = 0;
-
- /*
- * 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.
- */
-
- 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_read_cached(b, &block)) != HAL_OK)
- goto done;
-
- if (block->header.this_chunk != chunk) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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)
- goto done;
-
- 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)
- goto done;
-
- 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)) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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++;
- }
- }
-
- /*
- * Phase 0.2: Merge new attributes into updated_attributes[].
- * For each new attribute type, mark any existing attributes of that
- * type for deletion. Append new attributes to 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)) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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++) {
-
- if (updated_attributes[i].length == HAL_PKEY_ATTRIBUTE_NIL)
- continue;
-
- 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) {
- err = HAL_ERROR_RESULT_TOO_LONG;
- goto done;
- }
-
- 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) {
- err = HAL_ERROR_NO_KEY_INDEX_SLOTS;
- goto done;
- }
-
- /*
- * 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)
- goto done;
- 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) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- /*
- * 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)
- goto done;
-
- if (old_block->header.this_chunk != old_chunk) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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)
- goto done;
-
- old_attrs_i = 0;
- }
-
- if (old_attrs_i >= *old_attrs_len) {
- old_chunk++;
- old_block = NULL;
- continue;
- }
-
- 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) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- 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) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- /*
- * 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)
- goto done;
- if (tmp_block->header.this_chunk != 0) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
- 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);
- }
- 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)
- goto done;
-
- 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)
- goto done;
- break;
- default:
- goto done;
- }
-
- /*
- * 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)
- goto done;
-
- cache_mark_used(new_block, b);
-
- new_block = NULL;
- new_chunk++;
- }
-
- /*
- * 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)
- goto done;
- }
-
- }
-
- /*
- * 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)
- goto done;
-
- err = HAL_OK;
-
- }
-
- done:
- hal_ks_unlock();
- return err;
-
-#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?).
-}
-
-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 (ks != &db.ks || slot == NULL || attributes == NULL || attributes_len == 0 ||
- attributes_buffer == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- for (int i = 0; i < attributes_len; i++) {
- attributes[i].length = 0;
- attributes[i].value = NULL;
- }
-
- uint8_t *abuf = attributes_buffer;
- flash_block_t *block = NULL;
- unsigned chunk = 0;
- unsigned found = 0;
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- 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)
- goto done;
-
- if (block->header.this_chunk != chunk) {
- err = HAL_ERROR_IMPOSSIBLE;
- goto done;
- }
-
- if (chunk == 0)
- slot->hint = hint;
-
- 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)
- goto done;
-
- 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)
- goto done;
-
- 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) {
- err = HAL_ERROR_RESULT_TOO_LONG;
- goto done;
- }
-
- 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)
- err = HAL_ERROR_ATTRIBUTE_NOT_FOUND;
- else
- err = HAL_OK;
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-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.
- */
-
-/*
- * Special bonus init routine used only by the bootloader, so that it
- * can read PINs set by the main firmware. Yes, this is a kludge. We
- * could of course call the real ks_init() routine instead, but it's
- * slow, and we don't want to allow anything that would modify the
- * flash here, so having a special entry point for this kludge is
- * simplest, overall. Sigh.
- */
-
-void hal_ks_init_read_only_pins_only(void)
-{
- unsigned b, best_seen = ~0;
- flash_block_t block[1];
-
- hal_ks_lock();
-
- for (b = 0; b < NUM_FLASH_BLOCKS; b++) {
- if (block_read(b, block) != HAL_OK || block_get_type(block) != BLOCK_TYPE_PIN)
- continue;
- best_seen = b;
- if (block_get_status(block) == BLOCK_STATUS_LIVE)
- break;
- }
-
- if (b != best_seen && best_seen != ~0 && block_read(best_seen, block) != HAL_OK)
- best_seen = ~0;
-
- if (best_seen == ~0) {
- memset(block, 0xFF, sizeof(*block));
- block->pin.wheel_pin = hal_last_gasp_pin;
- }
-
- db.wheel_pin = block->pin.wheel_pin;
- db.so_pin = block->pin.so_pin;
- db.user_pin = block->pin.user_pin;
-
- hal_ks_unlock();
-}
-
-/*
- * 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_error_t err = HAL_OK;
-
- hal_ks_lock();
-
- 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: err = HAL_ERROR_BAD_ARGUMENTS;
- }
-
- hal_ks_unlock();
-
- return err;
-}
-
-/*
- * 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;
-
- hal_error_t err;
- int hint = 0;
- unsigned b_;
-
- if (b == NULL)
- b = &b_;
-
- 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.
- */
-
-static hal_error_t update_pin_block(const unsigned b,
- flash_block_t *block,
- const flash_pin_block_t * const new_data)
-{
- 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;
-
- flash_block_t *block;
- hal_error_t err;
- unsigned b;
-
- hal_ks_lock();
-
- if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
- goto done;
-
- 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: err = HAL_ERROR_BAD_ARGUMENTS; goto done;
- }
-
- 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;
-
- done:
- hal_ks_unlock();
- 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_no_lock(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_read(uint8_t *buf, const size_t len)
-{
- hal_ks_lock();
- const hal_error_t err = hal_mkm_flash_read_no_lock(buf, len);
- hal_ks_unlock();
- return err;
-}
-
-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;
-
- hal_ks_lock();
-
- if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
- goto done;
-
- flash_pin_block_t new_data = block->pin;
-
- new_data.kek_set = FLASH_KEK_SET;
- memcpy(new_data.kek, buf, len);
-
- err = update_pin_block(b, block, &new_data);
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-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;
-
- hal_ks_lock();
-
- if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
- goto done;
-
- flash_pin_block_t new_data = block->pin;
-
- new_data.kek_set = FLASH_KEK_SET;
- memset(new_data.kek, 0, len);
-
- err = update_pin_block(b, block, &new_data);
-
- done:
- hal_ks_unlock();
- return err;
-}
-
-#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */
-
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/ks_index.c b/ks_index.c
index c47451c..dcc0fe0 100644
--- a/ks_index.c
+++ b/ks_index.c
@@ -3,7 +3,7 @@
* ----------
* Keystore index API. This is internal within libhal.
*
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -32,54 +32,37 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stddef.h>
#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;
-}
+#include "ks.h"
/*
* Find a block in the index, return true (found) or false (not found).
* "where" indicates the name's position, or the position of the first free block.
*
* NB: This does NOT return a block number, it returns an index into
- * ksi->index[].
+ * ks->index[].
*/
-static int ks_find(const hal_ks_index_t * const ksi,
- const hal_uuid_t * const uuid,
- const uint8_t chunk,
+static int ks_find(const hal_ks_t * const ks,
+ const hal_uuid_t * const uuid,
const int * const hint,
- int *where)
+ int *where)
{
- assert(ksi != NULL && ksi->index != NULL && ksi->names != NULL && uuid != NULL && where != NULL);
+ if (ks == NULL || ks->index == NULL || ks->names == NULL || uuid == NULL || where == NULL)
+ return 0;
- 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) {
+ if (hint != NULL && *hint >= 0 && *hint < (int)ks->used &&
+ hal_uuid_cmp(uuid, &ks->names[ks->index[*hint]]) == 0) {
*where = *hint;
return 1;
}
int lo = -1;
- int hi = ksi->used;
+ int hi = ks->used;
for (;;) {
int m = (lo + hi) / 2;
@@ -87,7 +70,7 @@ static int ks_find(const hal_ks_index_t * const ksi,
*where = hi;
return 0;
}
- const int cmp = ks_name_cmp(&name, &ksi->names[ksi->index[m]]);
+ const int cmp = hal_uuid_cmp(uuid, &ks->names[ks->index[m]]);
if (cmp < 0)
hi = m;
else if (cmp > 0)
@@ -107,125 +90,97 @@ static int ks_find(const hal_ks_index_t * const ksi,
* 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)
+static inline hal_error_t ks_heapsift(hal_ks_t *ks, int parent, const int end)
{
- assert(ksi != NULL && ksi->index != NULL && ksi->names != NULL &&
- parent >= 0 && end >= parent);
+ if (ks == NULL || ks->index == NULL || ks->names == NULL || parent < 0 || end < parent)
+ return HAL_ERROR_IMPOSSIBLE;
+
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)
+ if (left_child <= end && hal_uuid_cmp(&ks->names[ks->index[biggest]],
+ &ks->names[ks->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)
+ if (right_child <= end && hal_uuid_cmp(&ks->names[ks->index[biggest]],
+ &ks->names[ks->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;
+ return HAL_OK;
+ const uint16_t tmp = ks->index[biggest];
+ ks->index[biggest] = ks->index[parent];
+ ks->index[parent] = tmp;
parent = biggest;
}
}
-static inline void ks_heapsort(hal_ks_index_t *ksi)
+hal_error_t hal_ks_index_heapsort(hal_ks_t *ks)
{
- 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);
- }
-}
-
-/*
- * Perform a consistency check on the index.
- */
-
-#define fsck(_ksi) \
- do { hal_error_t _err = hal_ks_index_fsck(_ksi); if (_err != HAL_OK) return _err; } while (0)
-
+ if (ks == NULL || ks->index == NULL || ks->names == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
-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;
+ if (ks->used < 2)
+ return HAL_OK;
- for (int i = 0; i < ksi->used; i++) {
+ hal_error_t err;
- const int cmp = i == 0 ? -1 : hal_uuid_cmp(&ksi->names[ksi->index[i - 1]].name,
- &ksi->names[ksi->index[i ]].name);
+ for (int i = (ks->used - 2) / 2; i >= 0; i--)
+ if ((err = ks_heapsift(ks, i, ks->used - 1)) != HAL_OK)
+ return err;
- 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;
+ for (int i = ks->used - 1; i > 0; i--) {
+ const uint16_t tmp = ks->index[i];
+ ks->index[i] = ks->index[0];
+ ks->index[0] = tmp;
+ if ((err = ks_heapsift(ks, 0, i - 1)) != HAL_OK)
+ return err;
}
return HAL_OK;
}
/*
- * Set up the index. Only setup task we have at the moment is sorting the index.
+ * Perform a consistency check on the index.
*/
-hal_error_t hal_ks_index_setup(hal_ks_index_t *ksi)
+#define fsck(_ks) \
+ do { hal_error_t _err = hal_ks_index_fsck(_ks); if (_err != HAL_OK) return _err; } while (0)
+
+
+hal_error_t hal_ks_index_fsck(hal_ks_t *ks)
{
- if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
- ksi->size == 0 || ksi->used > ksi->size)
+ if (ks == NULL || ks->index == NULL || ks->names == NULL ||
+ ks->size == 0 || ks->used > ks->size)
return HAL_ERROR_BAD_ARGUMENTS;
- 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.
- */
+ for (unsigned i = 1; i < ks->used; i++)
+ if (hal_uuid_cmp(&ks->names[ks->index[i - 1]], &ks->names[ks->index[i]]) >= 0)
+ return HAL_ERROR_KS_INDEX_UUID_MISORDERED;
return HAL_OK;
}
/*
- * Find a single block by name and chunk number.
+ * Find a single block by name.
*/
-hal_error_t hal_ks_index_find(hal_ks_index_t *ksi,
- const hal_uuid_t * const name,
- const unsigned chunk,
- unsigned *blockno,
+hal_error_t hal_ks_index_find(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
int *hint)
{
- if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
- ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ if (ks == NULL || ks->index == NULL || ks->names == NULL ||
+ ks->size == 0 || ks->used > ks->size || name == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
int where;
- fsck(ksi);
+ fsck(ks);
- int ok = ks_find(ksi, name, chunk, hint, &where);
+ int ok = ks_find(ks, name, hint, &where);
if (blockno != NULL)
- *blockno = ksi->index[where];
+ *blockno = ks->index[where];
if (hint != NULL)
*hint = where;
@@ -234,73 +189,26 @@ hal_error_t hal_ks_index_find(hal_ks_index_t *ksi,
}
/*
- * Find all blocks with the given name.
- * If 'strict' is set, expect it to be a well-ordered set of chunks.
- */
-
-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;
-}
-
-/*
* Add a single block to the index.
*/
-hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
- const hal_uuid_t * const name,
- const unsigned chunk,
- unsigned *blockno,
+hal_error_t hal_ks_index_add(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
int *hint)
{
- if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
- ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ if (ks == NULL || ks->index == NULL || ks->names == NULL ||
+ ks->size == 0 || ks->used > ks->size || name == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- if (ksi->used == ksi->size)
+ if (ks->used == ks->size)
return HAL_ERROR_NO_KEY_INDEX_SLOTS;
int where;
- fsck(ksi);
+ fsck(ks);
- if (ks_find(ksi, name, chunk, hint, &where))
+ if (ks_find(ks, name, hint, &where))
return HAL_ERROR_KEY_NAME_IN_USE;
/*
@@ -308,12 +216,11 @@ hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
* 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;
+ const size_t len = (ks->used - where) * sizeof(*ks->index);
+ const uint16_t b = ks->index[ks->used++];
+ memmove(&ks->index[where + 1], &ks->index[where], len);
+ ks->index[where] = b;
+ ks->names[b] = *name;
if (blockno != NULL)
*blockno = b;
@@ -321,7 +228,7 @@ hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
if (hint != NULL)
*hint = where;
- fsck(ksi);
+ fsck(ks);
return HAL_OK;
}
@@ -330,33 +237,32 @@ hal_error_t hal_ks_index_add(hal_ks_index_t *ksi,
* Delete a single block from the index.
*/
-hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi,
- const hal_uuid_t * const name,
- const unsigned chunk,
- unsigned *blockno,
+hal_error_t hal_ks_index_delete(hal_ks_t *ks,
+ const hal_uuid_t * const name,
+ unsigned *blockno,
int *hint)
{
- if (ksi == NULL || ksi->index == NULL || ksi->names == NULL ||
- ksi->size == 0 || ksi->used > ksi->size || name == NULL)
+ if (ks == NULL || ks->index == NULL || ks->names == NULL ||
+ ks->size == 0 || ks->used > ks->size || name == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
int where;
- fsck(ksi);
+ fsck(ks);
- if (ksi->used == 0 || !ks_find(ksi, name, chunk, hint, &where))
+ if (ks->used == 0 || !ks_find(ks, name, 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]));
+ const size_t len = (ks->size - where - 1) * sizeof(*ks->index);
+ const uint16_t b = ks->index[where];
+ memmove(&ks->index[where], &ks->index[where + 1], len);
+ ks->index[ks->size - 1] = b;
+ ks->used--;
+ memset(&ks->names[b], 0, sizeof(ks->names[b]));
if (blockno != NULL)
*blockno = b;
@@ -364,94 +270,34 @@ hal_error_t hal_ks_index_delete(hal_ks_index_t *ksi,
if (hint != NULL)
*hint = where;
- fsck(ksi);
-
- return HAL_OK;
-}
-
-/*
- * Delete all blocks with the given name. If blocknos is NULL, return a
- * count of the matching blocks without deleting anything.
- */
-
-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);
+ fsck(ks);
return HAL_OK;
}
/*
- * Replace a single block in the index.
+ * Replace a single 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.
*/
-hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
+hal_error_t hal_ks_index_replace(hal_ks_t *ks,
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)
+ if (ks == NULL || ks->index == NULL || ks->names == NULL ||
+ ks->size == 0 || ks->used > ks->size || name == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- if (ksi->used == ksi->size)
+ if (ks->used == ks->size)
return HAL_ERROR_NO_KEY_INDEX_SLOTS;
int where;
- fsck(ksi);
+ fsck(ks);
- if (ksi->used == 0 || !ks_find(ksi, name, chunk, hint, &where))
+ if (ks->used == 0 || !ks_find(ks, name, hint, &where))
return HAL_ERROR_KEY_NOT_FOUND;
/*
@@ -459,15 +305,14 @@ hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
* 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]));
+ const size_t len = (ks->size - ks->used - 1) * sizeof(*ks->index);
+ const uint16_t b1 = ks->index[where];
+ const uint16_t b2 = ks->index[ks->used];
+ memmove(&ks->index[ks->used], &ks->index[ks->used + 1], len);
+ ks->index[ks->size - 1] = b1;
+ ks->index[where] = b2;
+ ks->names[b2] = *name;
+ memset(&ks->names[b1], 0, sizeof(ks->names[b1]));
if (blockno != NULL)
*blockno = b2;
@@ -475,7 +320,7 @@ hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
if (hint != NULL)
*hint = where;
- fsck(ksi);
+ fsck(ks);
return HAL_OK;
}
diff --git a/ks_mmap.c b/ks_mmap.c
deleted file mode 100644
index 066e93e..0000000
--- a/ks_mmap.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * ks_mmap.c
- * ---------
- * Keystore implementation over POSIX mmap().
- *
- * Authors: Rob Austein
- * Copyright (c) 2015, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <sys/errno.h>
-#include <unistd.h>
-
-#include "hal.h"
-#include "hal_internal.h"
-
-#ifndef HAL_KS_MMAP_FILE
-#define HAL_KS_MMAP_FILE ".cryptech_hal_keystore"
-#endif
-
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
-
-/*
- * Storing the KEK in with the keys it's protecting is a bad idea, but we have no better
- * place to put it (real protection requires dedicated hardware, which we don't have here).
- */
-
-#define KEKBUF_LEN (bitsToBytes(256))
-
-static hal_ks_keydb_t *db;
-static uint8_t *kekbuf;
-
-const hal_ks_keydb_t *hal_ks_get_keydb(void)
-{
- if (db != NULL)
- return db;
-
- const char * const env = getenv("CRYPTECH_KEYSTORE");
- const char * const home = getenv("HOME");
- const char * const base = HAL_KS_MMAP_FILE;
- const long pagemask = sysconf(_SC_PAGESIZE) - 1;
- const size_t len = (sizeof(hal_ks_keydb_t) + KEKBUF_LEN + pagemask) & ~pagemask;
-
- char fn_[strlen(base) + (home == NULL ? 0 : strlen(home)) + 2];
- const char *fn = fn_;
- int fd;
-
- if (pagemask < 0)
- return NULL;
-
- if (env != NULL)
- fn = env;
- else if (home == NULL)
- fn = base;
- else
- strcat(strcat(strcpy(fn_, home), "/"), base);
-
- if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) {
- uint8_t zeros[len];
- memset(zeros, 0, sizeof(zeros));
- (void) write(fd, zeros, sizeof(zeros));
- }
- else if (errno == EEXIST) {
- fd = open(fn, O_RDWR | O_CREAT, 0600);
- }
-
- if (fd >= 0 && (db = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0)) != NULL)
- kekbuf = (uint8_t *) (db + 1);
-
- (void) close(fd);
-
- return db;
-}
-
-hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key,
- const int loc,
- const int updating)
-{
- if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || (!key->in_use != !updating))
- return HAL_ERROR_BAD_ARGUMENTS;
-
- db->keys[loc] = *key;
- db->keys[loc].in_use = 1;
- return HAL_OK;
-}
-
-hal_error_t hal_ks_del_keydb(const int loc)
-{
- if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys))
- return HAL_ERROR_BAD_ARGUMENTS;
-
- db->keys[loc].in_use = 0;
- memset(&db->keys[loc], 0, sizeof(db->keys[loc]));
- return HAL_OK;
-}
-
-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;
-
- 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;
- }
-
- *p = *pin;
- return HAL_OK;
-}
-
-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;
-
- if (kekbuf == NULL)
- return HAL_ERROR_IMPOSSIBLE;
-
- hal_error_t err;
-
- const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) :
- (kek_max < bitsToBytes(256)) ? bitsToBytes(192) :
- bitsToBytes(256));
-
- uint8_t t = 0;
-
- for (int i = 0; i < KEKBUF_LEN; i++)
- t |= kekbuf[i];
-
- if (t == 0 && (err = hal_rpc_get_random(kekbuf, sizeof(KEKBUF_LEN))) != HAL_OK)
- return err;
-
- memcpy(kek, kekbuf, len);
- *kek_len = len;
- return HAL_OK;
-}
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/ks_token.c b/ks_token.c
new file mode 100644
index 0000000..1676bc0
--- /dev/null
+++ b/ks_token.c
@@ -0,0 +1,665 @@
+/*
+ * ks_token.c
+ * ----------
+ * Keystore implementation in flash memory.
+ *
+ * Authors: Rob Austein, Fredrik Thulin
+ * Copyright (c) 2015-2017, NORDUnet A/S All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This keystore driver operates over bare flash, versus over a flash file
+ * system or flash translation layer. The block size is large enough to
+ * hold an AES-keywrapped 4096-bit RSA key. Any remaining space in the key
+ * block may be used to store attributes (opaque TLV blobs). If the
+ * attributes overflow the key block, additional blocks may be added, but
+ * no attribute may exceed the block size.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+#include "ks.h"
+
+#include "last_gasp_pin_internal.h"
+
+#define HAL_OK CMSIS_HAL_OK
+#include "stm-keystore.h"
+#undef HAL_OK
+
+#ifndef KS_TOKEN_CACHE_SIZE
+#define KS_TOKEN_CACHE_SIZE 4
+#endif
+
+#if HAL_KS_BLOCK_SIZE % KEYSTORE_SUBSECTOR_SIZE != 0
+#error Keystore block size is not a multiple of flash subsector size
+#endif
+
+#define NUM_FLASH_BLOCKS ((KEYSTORE_NUM_SUBSECTORS * KEYSTORE_SUBSECTOR_SIZE) / HAL_KS_BLOCK_SIZE)
+#define SUBSECTORS_PER_BLOCK (HAL_KS_BLOCK_SIZE / KEYSTORE_SUBSECTOR_SIZE)
+
+/*
+ * Keystore database.
+ */
+
+typedef struct {
+ hal_ks_t ks; /* Must be first (C "subclassing") */
+ hal_ks_pin_t wheel_pin;
+ hal_ks_pin_t so_pin;
+ hal_ks_pin_t user_pin;
+} ks_token_db_t;
+
+/*
+ * This is a bit silly, but it's safe enough, and it lets us avoid a
+ * nasty mess of forward references.
+ */
+
+#define db ((ks_token_db_t * const) hal_ks_token)
+
+/*
+ * Calculate offset of the block in the flash address space.
+ */
+
+static inline uint32_t ks_token_offset(const unsigned blockno)
+{
+ return blockno * HAL_KS_BLOCK_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 ks_token_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != HAL_KS_BLOCK_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if (keystore_read_data(ks_token_offset(blockno),
+ block->bytes,
+ KEYSTORE_PAGE_SIZE) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ switch (hal_ks_block_get_type(block)) {
+ case HAL_KS_BLOCK_TYPE_ERASED:
+ case HAL_KS_BLOCK_TYPE_ZEROED:
+ return HAL_OK;
+ case HAL_KS_BLOCK_TYPE_KEY:
+ case HAL_KS_BLOCK_TYPE_PIN:
+ break;
+ default:
+ return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
+ }
+
+ switch (hal_ks_block_get_status(block)) {
+ case HAL_KS_BLOCK_STATUS_LIVE:
+ case HAL_KS_BLOCK_STATUS_TOMBSTONE:
+ break;
+ default:
+ return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
+ }
+
+ if (keystore_read_data(ks_token_offset(blockno) + KEYSTORE_PAGE_SIZE,
+ block->bytes + KEYSTORE_PAGE_SIZE,
+ sizeof(*block) - KEYSTORE_PAGE_SIZE) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ if (hal_ks_block_calculate_crc(block) != block->header.crc)
+ return HAL_ERROR_KEYSTORE_BAD_CRC;
+
+ return HAL_OK;
+}
+
+/*
+ * 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 ks_token_deprecate(hal_ks_t *ks, const unsigned blockno)
+{
+ if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page[KEYSTORE_PAGE_SIZE];
+ hal_ks_block_header_t *header = (void *) page;
+ uint32_t offset = ks_token_offset(blockno);
+
+ if (keystore_read_data(offset, page, sizeof(page)) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ header->block_status = HAL_KS_BLOCK_STATUS_TOMBSTONE;
+
+ if (keystore_write_data(offset, page, sizeof(page)) != CMSIS_HAL_OK)
+ 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 ks_token_zero(hal_ks_t *ks, const unsigned blockno)
+{
+ if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t page[KEYSTORE_PAGE_SIZE] = {0};
+
+ if (keystore_write_data(ks_token_offset(blockno), page, sizeof(page)) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * Erase a flash block. Also see ks_token_erase_maybe(), below.
+ */
+
+static hal_error_t ks_token_erase(hal_ks_t *ks, const unsigned blockno)
+{
+ if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ unsigned subsector = blockno * SUBSECTORS_PER_BLOCK;
+ const unsigned end = (blockno + 1) * SUBSECTORS_PER_BLOCK;
+
+ do {
+ if (keystore_erase_subsector(subsector) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ } while (++subsector < end);
+
+ 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 ks_token_erase_maybe(hal_ks_t *ks, const unsigned blockno)
+{
+ if (ks != hal_ks_token || blockno >= NUM_FLASH_BLOCKS)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ uint8_t mask = 0xFF;
+
+ for (uint32_t a = ks_token_offset(blockno); a < ks_token_offset(blockno + 1); a += KEYSTORE_PAGE_SIZE) {
+ uint8_t page[KEYSTORE_PAGE_SIZE];
+ if (keystore_read_data(a, page, sizeof(page)) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+ for (int i = 0; i < KEYSTORE_PAGE_SIZE; i++)
+ mask &= page[i];
+ }
+
+ return mask == 0xFF ? HAL_OK : ks_token_erase(ks, blockno);
+}
+
+/*
+ * Write a flash block, calculating CRC when appropriate.
+ */
+
+static hal_error_t ks_token_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ if (ks != hal_ks_token || block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != HAL_KS_BLOCK_SIZE)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_error_t err = ks_token_erase_maybe(ks, blockno);
+
+ if (err != HAL_OK)
+ return err;
+
+ switch (hal_ks_block_get_type(block)) {
+ case HAL_KS_BLOCK_TYPE_KEY:
+ case HAL_KS_BLOCK_TYPE_PIN:
+ block->header.crc = hal_ks_block_calculate_crc(block);
+ break;
+ default:
+ break;
+ }
+
+ if (keystore_write_data(ks_token_offset(blockno), block->bytes, sizeof(*block)) != CMSIS_HAL_OK)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ return HAL_OK;
+}
+
+/*
+ * The token keystore doesn't implement per-session objects, so these are no-ops.
+ */
+
+static hal_error_t ks_token_set_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return HAL_OK;
+}
+
+static hal_error_t ks_token_test_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ return HAL_OK;
+}
+
+static hal_error_t ks_token_copy_owner(hal_ks_t *ks,
+ const unsigned source,
+ const unsigned target)
+{
+ return HAL_OK;
+}
+
+static hal_error_t ks_token_logout(hal_ks_t *ks,
+ hal_client_handle_t client)
+{
+ return HAL_OK;
+}
+
+/*
+ * Forward reference.
+ */
+
+static hal_error_t fetch_pin_block(unsigned *b, hal_ks_block_t **block);
+
+/*
+ * Initialize keystore.
+ */
+
+static hal_error_t ks_token_init(hal_ks_t *ks, const int alloc)
+{
+ if (ks != hal_ks_token)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_ks_block_t *block = NULL;
+ hal_error_t err = HAL_OK;
+
+ if (alloc && (err = hal_ks_alloc_common(ks, NUM_FLASH_BLOCKS, KS_TOKEN_CACHE_SIZE, NULL, 0)) != HAL_OK)
+ return err;
+
+ if ((err = hal_ks_init_common(ks)) != HAL_OK)
+ return err;
+
+ /*
+ * Fetch or create the PIN block.
+ */
+
+ 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));
+
+ 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) {
+ /*
+ * 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;
+
+ if ((block = hal_ks_cache_pick_lru(ks)) == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ memset(block, 0xFF, sizeof(*block));
+
+ block->header.block_type = HAL_KS_BLOCK_TYPE_PIN;
+ block->header.block_status = HAL_KS_BLOCK_STATUS_LIVE;
+
+ 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(ks, &hal_ks_pin_uuid, &b, NULL)) != HAL_OK)
+ return err;
+
+ hal_ks_cache_mark_used(ks, block, b);
+
+ err = ks_token_write(ks, b, block);
+
+ hal_ks_cache_release(ks, block);
+ }
+
+ return err;
+}
+
+/*
+ * Dispatch vector and keystore definition, now that we've defined all
+ * the driver functions.
+ */
+
+static const hal_ks_driver_t ks_token_driver = {
+ .init = ks_token_init,
+ .read = ks_token_read,
+ .write = ks_token_write,
+ .deprecate = ks_token_deprecate,
+ .zero = ks_token_zero,
+ .erase = ks_token_erase,
+ .erase_maybe = ks_token_erase_maybe,
+ .set_owner = ks_token_set_owner,
+ .test_owner = ks_token_test_owner,
+ .copy_owner = ks_token_copy_owner,
+ .logout = ks_token_logout
+};
+
+static ks_token_db_t _db = { .ks.driver = &ks_token_driver };
+
+hal_ks_t * const hal_ks_token = &_db.ks;
+
+/*
+ * 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.
+ */
+
+/*
+ * Special bonus init routine used only by the bootloader, so that it
+ * can read PINs set by the main firmware. Yes, this is a kludge. We
+ * could of course call the real ks_init() routine instead, but it's
+ * slow, and we don't want to allow anything that would modify the
+ * flash here, so having a special entry point for this kludge is
+ * simplest, overall. Sigh.
+ */
+
+void hal_ks_init_read_only_pins_only(void)
+{
+ unsigned b, best_seen = NUM_FLASH_BLOCKS;
+ hal_ks_block_t block[1];
+
+ hal_ks_lock();
+
+ for (b = 0; b < NUM_FLASH_BLOCKS; b++) {
+ if (hal_ks_block_read(hal_ks_token, b, block) != HAL_OK ||
+ hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_PIN)
+ continue;
+ best_seen = b;
+ if (hal_ks_block_get_status(block) == HAL_KS_BLOCK_STATUS_LIVE)
+ break;
+ }
+
+ if (b != best_seen && best_seen != NUM_FLASH_BLOCKS &&
+ hal_ks_block_read(hal_ks_token, best_seen, block) != HAL_OK)
+ best_seen = NUM_FLASH_BLOCKS;
+
+ if (best_seen == NUM_FLASH_BLOCKS) {
+ memset(block, 0xFF, sizeof(*block));
+ block->pin.wheel_pin = hal_last_gasp_pin;
+ }
+
+ db->wheel_pin = block->pin.wheel_pin;
+ db->so_pin = block->pin.so_pin;
+ db->user_pin = block->pin.user_pin;
+
+ hal_ks_unlock();
+}
+
+/*
+ * 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_error_t err = HAL_OK;
+
+ hal_ks_lock();
+
+ 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: err = HAL_ERROR_BAD_ARGUMENTS;
+ }
+
+ hal_ks_unlock();
+
+ return err;
+}
+
+/*
+ * 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, hal_ks_block_t **block)
+{
+ if (block == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ hal_error_t err;
+ int hint = 0;
+ unsigned b_;
+
+ if (b == NULL)
+ b = &b_;
+
+ if ((err = hal_ks_index_find(hal_ks_token, &hal_ks_pin_uuid, b, &hint)) != HAL_OK ||
+ (err = hal_ks_block_read_cached(hal_ks_token, *b, block)) != HAL_OK)
+ return err;
+
+ hal_ks_cache_mark_used(hal_ks_token, *block, *b);
+
+ if (hal_ks_block_get_type(*block) != HAL_KS_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.
+ */
+
+static hal_error_t update_pin_block(const unsigned b,
+ hal_ks_block_t *block,
+ const hal_ks_pin_block_t * const new_data)
+{
+ if (block == NULL || new_data == NULL || hal_ks_block_get_type(block) != HAL_KS_BLOCK_TYPE_PIN)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ int hint = 0;
+
+ block->pin = *new_data;
+
+ return hal_ks_block_update(hal_ks_token, b, block, &hal_ks_pin_uuid, &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;
+
+ hal_ks_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_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: err = HAL_ERROR_BAD_ARGUMENTS; goto done;
+ }
+
+ 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;
+
+ done:
+ hal_ks_unlock();
+ 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_no_lock(uint8_t *buf, const size_t len)
+{
+ if (buf != NULL && len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ hal_ks_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_read(uint8_t *buf, const size_t len)
+{
+ hal_ks_lock();
+ const hal_error_t err = hal_mkm_flash_read_no_lock(buf, len);
+ hal_ks_unlock();
+ return err;
+}
+
+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;
+
+ hal_ks_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_pin_block_t new_data = block->pin;
+
+ new_data.kek_set = FLASH_KEK_SET;
+ memcpy(new_data.kek, buf, len);
+
+ err = update_pin_block(b, block, &new_data);
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+hal_error_t hal_mkm_flash_erase(const size_t len)
+{
+ if (len != KEK_LENGTH)
+ return HAL_ERROR_MASTERKEY_BAD_LENGTH;
+
+ hal_ks_block_t *block;
+ hal_error_t err;
+ unsigned b;
+
+ hal_ks_lock();
+
+ if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
+ goto done;
+
+ hal_ks_pin_block_t new_data = block->pin;
+
+ new_data.kek_set = FLASH_KEK_NOT_SET;
+ memset(new_data.kek, 0, len);
+
+ err = update_pin_block(b, block, &new_data);
+
+ done:
+ hal_ks_unlock();
+ return err;
+}
+
+#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_volatile.c b/ks_volatile.c
index d565c60..75d7fcb 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -41,593 +41,261 @@
#include "hal.h"
#include "hal_internal.h"
+#include "ks.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
+#ifndef KS_VOLATILE_CACHE_SIZE
+#define KS_VOLATILE_CACHE_SIZE 4
#endif
/*
- * 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).
+ * Keystore database.
*/
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;
+ hal_ks_block_t block;
+} ks_volatile_key_t;
typedef struct {
- hal_ks_index_t ksi;
- ks_key_t *keys;
-} db_t;
+ hal_ks_t ks; /* Must be first */
+ ks_volatile_key_t *keys;
+} ks_volatile_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.
+ * This is a bit silly, but it's safe enough, and it lets us avoid a
+ * nasty mess of forward references.
*/
-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;
+#define db ((ks_volatile_db_t * const) hal_ks_volatile)
/*
- * 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.
+ * Read a block. CRC probably not necessary for RAM.
*/
-#if STATIC_KS_VOLATILE_SLOTS > 0
+static hal_error_t ks_volatile_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
+{
+ if (ks != hal_ks_volatile || db->keys == NULL || block == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
-static ks_t volatile_ks;
+ memcpy(block, &db->keys[blockno].block, sizeof(*block));
-static inline ks_t *ks_to_ksv(hal_ks_t *ks)
-{
- return (ks_t *) ks;
+ return HAL_OK;
}
/*
- * 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.
- *
- * 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.
+ * Convert a live block into a tombstone.
*/
-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 ||
- hal_rpc_is_logged_in(client, HAL_USER_WHEEL) == HAL_OK);
-}
-
-static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
+static hal_error_t ks_volatile_deprecate(hal_ks_t *ks, const unsigned blockno)
{
- 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)
+ if (ks != hal_ks_volatile || db->keys == NULL || blockno >= ks->size)
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;
-
- /*
- * 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;
+ db->keys[blockno].block.header.block_status = HAL_KS_BLOCK_STATUS_TOMBSTONE;
- return hal_ks_index_setup(&ksv->db->ksi);
+ return HAL_OK;
}
-static hal_error_t ks_volatile_init(const hal_ks_driver_t * const driver, const int alloc)
-{
- hal_error_t err = HAL_OK;
-
- hal_ks_lock();
-
- 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)
- err = HAL_ERROR_ALLOCATION_FAILURE;
- else
- err = ks_init(driver, 1, &volatile_ks, mem, len);
-
- hal_ks_unlock();
- return err;
-}
+/*
+ * Zero (not erase) a flash block.
+ */
-static hal_error_t ks_volatile_shutdown(const hal_ks_driver_t * const driver)
+static hal_error_t ks_volatile_zero(hal_ks_t *ks, const unsigned blockno)
{
- if (volatile_ks.ks.driver != driver)
- return HAL_ERROR_KEYSTORE_ACCESS;
- return HAL_OK;
-}
+ if (ks != hal_ks_volatile || db->keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
-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;
-}
+ memset(&db->keys[blockno].block, 0x00, sizeof(db->keys[blockno].block));
+ db->keys[blockno].client.handle = HAL_HANDLE_NONE;
+ db->keys[blockno].session.handle = HAL_HANDLE_NONE;
-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;
- }
-}
+/*
+ * Erase a flash block.
+ */
-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)
+static hal_error_t ks_volatile_erase(hal_ks_t *ks, const unsigned blockno)
{
- 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 = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_add(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- 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 (ks != hal_ks_volatile || db->keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- if (err == HAL_OK)
- ksv->db->keys[b] = k;
- else
- (void) hal_ks_index_delete(&ksv->db->ksi, &slot->name, 0, NULL, &slot->hint);
+ memset(&db->keys[blockno].block, 0xFF, sizeof(db->keys[blockno].block));
+ db->keys[blockno].client.handle = HAL_HANDLE_NONE;
+ db->keys[blockno].session.handle = HAL_HANDLE_NONE;
- done:
- hal_ks_unlock();
- return err;
+ return HAL_OK;
}
-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 = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- const ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- 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_;
-
- 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));
- }
-
- done:
- hal_ks_unlock();
- return err;
-}
+/*
+ * Write a flash block. CRC probably not necessary for RAM.
+ */
-static hal_error_t ks_delete(hal_ks_t *ks,
- hal_pkey_slot_t *slot)
+static hal_error_t ks_volatile_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block)
{
- if (ks == NULL || slot == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, &ksv->db->keys[b])) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- if ((err = hal_ks_index_delete(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
+ if (ks != hal_ks_volatile || db->keys == NULL || block == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- memset(&ksv->db->keys[b], 0, sizeof(ksv->db->keys[b]));
+ memcpy(&db->keys[blockno].block, block, sizeof(*block));
- done:
- hal_ks_unlock();
- return err;
+ return HAL_OK;
}
-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 mask,
- 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)
+/*
+ * Set key ownership.
+ */
+
+static hal_error_t ks_volatile_set_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
{
- if (ks == NULL || (attributes == NULL && attributes_len > 0) ||
- result == NULL || result_len == NULL || previous_uuid == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
+ if (ks != hal_ks_volatile || db->keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- ks_t *ksv = ks_to_ksv(ks);
+ db->keys[blockno].client = client;
+ db->keys[blockno].session = session;
- if (ksv->db == NULL)
- return HAL_ERROR_KEYSTORE_ACCESS;
+ return HAL_OK;
+}
- hal_error_t err = HAL_OK;
- int i = -1;
+/*
+ * Test key ownership.
+ *
+ * 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.
+ *
+ * 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.
+ */
- hal_ks_lock();
+static hal_error_t ks_volatile_test_owner(hal_ks_t *ks,
+ const unsigned blockno,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session)
+{
+ if (ks != hal_ks_volatile || db->keys == NULL || blockno >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- *result_len = 0;
+ if (db->keys[blockno].client.handle == HAL_HANDLE_NONE ||
+ db->keys[blockno].client.handle == client.handle)
+ return HAL_OK;
- err = hal_ks_index_find(&ksv->db->ksi, previous_uuid, 0, NULL, &i);
+ if (hal_rpc_is_logged_in(client, HAL_USER_WHEEL) == HAL_OK)
+ return HAL_OK;
- if (err == HAL_ERROR_KEY_NOT_FOUND)
- i--;
- else if (err != HAL_OK)
- goto done;
+ return HAL_ERROR_KEY_NOT_FOUND;
+}
- while (*result_len < result_max && ++i < ksv->db->ksi.used) {
+/*
+ * Copy key ownership.
+ */
- unsigned b = ksv->db->ksi.index[i];
+static hal_error_t ks_volatile_copy_owner(hal_ks_t *ks,
+ const unsigned source,
+ const unsigned target)
+{
+ if (ks != hal_ks_volatile || db->keys == NULL || source >= ks->size || target >= ks->size)
+ return HAL_ERROR_IMPOSSIBLE;
- if (ksv->db->ksi.names[b].chunk > 0)
- continue;
+ db->keys[target].client = db->keys[source].client;
+ db->keys[target].session = db->keys[source].session;
+ return HAL_OK;
+}
- if (type != HAL_KEY_TYPE_NONE && type != ksv->db->keys[b].type)
- continue;
+/*
+ * Zero any blocks owned by a client that we're logging out.
+ */
- if (curve != HAL_CURVE_NONE && curve != ksv->db->keys[b].curve)
- continue;
+static hal_error_t ks_volatile_logout(hal_ks_t *ks,
+ hal_client_handle_t client)
+{
+ if (ks != hal_ks_volatile || client.handle == HAL_HANDLE_NONE)
+ return HAL_ERROR_IMPOSSIBLE;
- if (((flags ^ ksv->db->keys[b].flags) & mask) != 0)
- continue;
+ for (unsigned i = 0; i < ks->used; i++) {
+ unsigned b = ks->index[i];
+ hal_error_t err;
+ int hint = i;
- if (!key_visible_to_session(ksv, client, session, &ksv->db->keys[b]))
+ if (db->keys[b].client.handle != client.handle)
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)
- goto done;
-
- 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 ((err = hal_ks_index_delete(ks, &ks->names[b], NULL, &hint)) != HAL_OK ||
+ (err = hal_ks_block_zero(ks, b)) != HAL_OK)
+ return err;
- 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;
+ i--;
}
- err = HAL_OK;
-
- done:
- hal_ks_unlock();
- return err;
+ return HAL_OK;
}
-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 (ks == NULL || slot == NULL || attributes == NULL || attributes_len == 0)
- return HAL_ERROR_BAD_ARGUMENTS;
-
- ks_t *ksv = ks_to_ksv(ks);
- hal_error_t err = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- {
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- 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)
- goto done;
-
- 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)
- goto done;
- }
-
- err = HAL_OK;
-
- }
-
- done:
- hal_ks_unlock();
- return err;
-}
+/*
+ * Initialize keystore.
+ */
-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)
+static hal_error_t ks_volatile_init(hal_ks_t *ks, const int alloc)
{
- 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 = HAL_OK;
- unsigned b;
-
- hal_ks_lock();
-
- {
- if (ksv->db == NULL) {
- err = HAL_ERROR_KEYSTORE_ACCESS;
- goto done;
- }
-
- if ((err = hal_ks_index_find(&ksv->db->ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
- goto done;
-
- const ks_key_t * const k = &ksv->db->keys[b];
-
- if (!key_visible_to_session(ksv, slot->client_handle, slot->session_handle, k)) {
- err = HAL_ERROR_KEY_NOT_FOUND;
- goto done;
- }
-
- 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)
- goto done;
-
- uint8_t *abuf = attributes_buffer;
+ if (ks != hal_ks_volatile)
+ return HAL_ERROR_IMPOSSIBLE;
- 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;
+ void *mem = NULL;
+ hal_error_t err;
- if (attributes_buffer_len == 0) {
- attributes[i].value = NULL;
- attributes[i].length = found ? attrs[j].length : 0;
- continue;
- }
+ if (alloc &&
+ (err = hal_ks_alloc_common(ks, HAL_STATIC_KS_VOLATILE_SLOTS, KS_VOLATILE_CACHE_SIZE,
+ &mem, sizeof(*db->keys) * HAL_STATIC_KS_VOLATILE_SLOTS)) != HAL_OK)
+ return err;
- if (!found) {
- err = HAL_ERROR_ATTRIBUTE_NOT_FOUND;
- goto done;
- }
+ if (alloc)
+ db->keys = mem;
- if (attrs[j].length > attributes_buffer + attributes_buffer_len - abuf) {
- err = HAL_ERROR_RESULT_TOO_LONG;
- goto done;
- }
+ if (db->keys == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
- memcpy(abuf, attrs[j].value, attrs[j].length);
- attributes[i].value = abuf;
- attributes[i].length = attrs[j].length;
- abuf += attrs[j].length;
- }
+ for (unsigned b = 0; b < db->ks.size; b++)
+ if ((err = hal_ks_block_erase(ks, b)) != HAL_OK)
+ return err;
- err = HAL_OK;
+ if ((err = hal_ks_init_common(ks)) != HAL_OK)
+ return err;
- }
-
- done:
- hal_ks_unlock();
- return err;
+ return HAL_OK;
}
-const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
+/*
+ * Dispatch vector and keystore definition, now that we've defined all
+ * the driver functions.
+ */
+
+static const hal_ks_driver_t ks_volatile_driver = {
.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 */
+ .read = ks_volatile_read,
+ .write = ks_volatile_write,
+ .deprecate = ks_volatile_deprecate,
+ .zero = ks_volatile_zero,
+ .erase = ks_volatile_erase,
+ .erase_maybe = ks_volatile_erase, /* sic */
+ .set_owner = ks_volatile_set_owner,
+ .test_owner = ks_volatile_test_owner,
+ .copy_owner = ks_volatile_copy_owner,
+ .logout = ks_volatile_logout
+};
+
+static ks_volatile_db_t _db = { .ks.driver = &ks_volatile_driver };
+
+hal_ks_t * const hal_ks_volatile = &_db.ks;
/*
* Local variables:
diff --git a/mkmif.c b/mkmif.c
index 06a2c4b..bc852ef 100644
--- a/mkmif.c
+++ b/mkmif.c
@@ -50,9 +50,11 @@ hal_error_t hal_mkmif_init(hal_core_t *core)
cmd.word = htonl(MKMIF_CTRL_CMD_INIT);
- err = hal_core_alloc(MKMIF_NAME, &core) ||
- hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4) ||
- hal_io_wait_ready(core);
+ if ((err = hal_core_alloc(MKMIF_NAME, &core)) != HAL_OK)
+ return err;
+
+ if ((err = hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4)) == HAL_OK)
+ err = hal_io_wait_ready(core);
hal_core_free(core);
return err;
@@ -65,8 +67,10 @@ hal_error_t hal_mkmif_set_clockspeed(hal_core_t *core, const uint32_t divisor)
data.word = htonl(divisor);
- err = hal_core_alloc(MKMIF_NAME, &core) ||
- hal_io_write(core, MKMIF_ADDR_SCLK_DIV, data.byte, 4);
+ if ((err = hal_core_alloc(MKMIF_NAME, &core)) != HAL_OK)
+ return err;
+
+ err = hal_io_write(core, MKMIF_ADDR_SCLK_DIV, data.byte, 4);
hal_core_free(core);
return err;
@@ -77,10 +81,10 @@ hal_error_t hal_mkmif_get_clockspeed(hal_core_t *core, uint32_t *divisor)
byteword_t data;
hal_error_t err;
- err = hal_core_alloc(MKMIF_NAME, &core) ||
- hal_io_read(core, MKMIF_ADDR_SCLK_DIV, data.byte, 4);
+ if ((err = hal_core_alloc(MKMIF_NAME, &core)) != HAL_OK)
+ return err;
- if (err == HAL_OK)
+ if ((err = hal_io_read(core, MKMIF_ADDR_SCLK_DIV, data.byte, 4)) == HAL_OK)
*divisor = htonl(data.word);
hal_core_free(core);
@@ -101,11 +105,11 @@ hal_error_t hal_mkmif_write(hal_core_t *core, uint32_t addr, const uint8_t *buf,
for (; len > 0; addr += 4, buf += 4, len -= 4) {
byteword_t write_addr;
write_addr.word = htonl((uint32_t)addr);
- if ((err = hal_io_write(core, MKMIF_ADDR_EMEM_ADDR, write_addr.byte, 4)) ||
- (err = hal_io_write(core, MKMIF_ADDR_EMEM_DATA, buf, 4)) ||
- (err = hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4)) ||
- (err = hal_io_wait_ready(core)))
- return err;
+ if ((err = hal_io_write(core, MKMIF_ADDR_EMEM_ADDR, write_addr.byte, 4)) != HAL_OK ||
+ (err = hal_io_write(core, MKMIF_ADDR_EMEM_DATA, buf, 4)) != HAL_OK ||
+ (err = hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4)) != HAL_OK ||
+ (err = hal_io_wait_ready(core)) != HAL_OK)
+ break;
}
}
@@ -132,19 +136,19 @@ hal_error_t hal_mkmif_read(hal_core_t *core, uint32_t addr, uint8_t *buf, size_t
cmd.word = htonl(MKMIF_CTRL_CMD_READ);
- if ((err = hal_core_alloc(MKMIF_NAME, &core)) == HAL_OK) {
- for (; len > 0; addr += 4, buf += 4, len -= 4) {
- byteword_t read_addr;
- read_addr.word = htonl((uint32_t)addr);
- if ((err = hal_io_write(core, MKMIF_ADDR_EMEM_ADDR, read_addr.byte, 4)) ||
- (err = hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4)) ||
- (err = hal_io_wait_valid(core)) ||
- (err = hal_io_read(core, MKMIF_ADDR_EMEM_DATA, buf, 4)))
- goto out;
- }
+ if ((err = hal_core_alloc(MKMIF_NAME, &core)) != HAL_OK)
+ return err;
+
+ for (; len > 0; addr += 4, buf += 4, len -= 4) {
+ byteword_t read_addr;
+ read_addr.word = htonl((uint32_t)addr);
+ if ((err = hal_io_write(core, MKMIF_ADDR_EMEM_ADDR, read_addr.byte, 4)) != HAL_OK ||
+ (err = hal_io_write(core, MKMIF_ADDR_CTRL, cmd.byte, 4)) != HAL_OK ||
+ (err = hal_io_wait_valid(core)) != HAL_OK ||
+ (err = hal_io_read(core, MKMIF_ADDR_EMEM_DATA, buf, 4)) != HAL_OK)
+ break;
}
-out:
hal_core_free(core);
return err;
}
diff --git a/modexp.c b/modexp.c
index bad492b..37f5e0e 100644
--- a/modexp.c
+++ b/modexp.c
@@ -11,7 +11,7 @@
* enough that this module is no longer needed, it will go away.
*
* Authors: Rob Austein
- * Copyright (c) 2015, NORDUnet A/S
+ * Copyright (c) 2015-2017, NORDUnet A/S
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,6 @@
#include <stdio.h>
#include <stdint.h>
-#include <assert.h>
#include "hal.h"
#include "hal_internal.h"
@@ -60,173 +59,270 @@ void hal_modexp_set_debug(const int onoff)
}
/*
- * Check a result, report on failure if debugging, pass failures up
- * the chain.
+ * Get value of an ordinary register.
*/
-#define check(_expr_) \
- do { \
- hal_error_t _err = (_expr_); \
- if (_err != HAL_OK && debug) \
- printf("%s failed: %s\n", #_expr_, hal_error_string(_err)); \
- if (_err != HAL_OK) \
- return _err; \
- } while (0)
+static inline hal_error_t get_register(const hal_core_t *core,
+ const hal_addr_t addr,
+ uint32_t *value)
+{
+ hal_error_t err;
+ uint8_t w[4];
+
+ if (value == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ if ((err = hal_io_read(core, addr, w, sizeof(w))) != HAL_OK)
+ return err;
+
+ *value = (w[0] << 0) | (w[1] << 8) | (w[2] << 16) | (w[3] << 24);
+
+ return HAL_OK;
+}
/*
- * Set an ordinary register.
+ * Set value of an ordinary register.
*/
-static hal_error_t set_register(const hal_core_t *core,
- const hal_addr_t addr,
- uint32_t value)
+static inline hal_error_t set_register(const hal_core_t *core,
+ const hal_addr_t addr,
+ const uint32_t value)
{
- uint8_t w[4];
- int i;
-
- for (i = 3; i >= 0; i--) {
- w[i] = value & 0xFF;
- value >>= 8;
- }
+ const uint8_t w[4] = {
+ ((value >> 24) & 0xFF),
+ ((value >> 16) & 0xFF),
+ ((value >> 8) & 0xFF),
+ ((value >> 0) & 0xFF)
+ };
return hal_io_write(core, addr, w, sizeof(w));
}
/*
* Get value of a data buffer. We reverse the order of 32-bit words
- * in the buffer during the transfer to match what the modexps6 core
+ * in the buffer during the transfer to match what the modexpa7 core
* expects.
*/
-static hal_error_t get_buffer(const hal_core_t *core,
- const hal_addr_t data_addr,
- uint8_t *value,
- const size_t length)
+static inline hal_error_t get_buffer(const hal_core_t *core,
+ const hal_addr_t data_addr,
+ uint8_t *value,
+ const size_t length)
{
+ hal_error_t err;
size_t i;
- assert(value != NULL && length % 4 == 0);
+ if (value == NULL || length % 4 != 0)
+ return HAL_ERROR_IMPOSSIBLE;
for (i = 0; i < length; i += 4)
- check(hal_io_read(core, data_addr + i/4, &value[length - 4 - i], 4));
+ if ((err = hal_io_read(core, data_addr + i/4, &value[length - 4 - i], 4)) != HAL_OK)
+ return err;
return HAL_OK;
}
/*
* Set value of a data buffer. We reverse the order of 32-bit words
- * in the buffer during the transfer to match what the modexps6 core
+ * in the buffer during the transfer to match what the modexpa7 core
* expects.
+ *
+ * Do we need to zero the portion of the buffer we're not using
+ * explictly (that is, the portion between `length` and the value of
+ * the core's MODEXPA7_ADDR_BUFFER_BITS register)? We've gotten away
+ * without doing this so far, but the core doesn't take an explicit
+ * length parameter for the message itself, instead it assumes that
+ * the message is either as long as or twice as long as the exponent,
+ * depending on the setting of the CRT mode bit. Maybe initializing
+ * the core clears the excess bits so there's no issue? Dunno. Have
+ * never seen a problem with this yet, just dont' know why not.
*/
-static hal_error_t set_buffer(const hal_core_t *core,
- const hal_addr_t data_addr,
- const uint8_t * const value,
- const size_t length)
+static inline hal_error_t set_buffer(const hal_core_t *core,
+ const hal_addr_t data_addr,
+ const uint8_t * const value,
+ const size_t length)
{
+ hal_error_t err;
size_t i;
- assert(value != NULL && length % 4 == 0);
+ if (value == NULL || length % 4 != 0)
+ return HAL_ERROR_IMPOSSIBLE;
for (i = 0; i < length; i += 4)
- check(hal_io_write(core, data_addr + i/4, &value[length - 4 - i], 4));
+ if ((err = hal_io_write(core, data_addr + i/4, &value[length - 4 - i], 4)) != HAL_OK)
+ return err;
return HAL_OK;
}
/*
- * Run one modexp operation.
+ * Stuff moved out of modexp so we can run two cores in parallel more
+ * easily. We have to return to the jacket routine every time we kick
+ * a core into doing something, since only the jacket routines know
+ * how many cores we're running for any particular calculation.
+ *
+ * In theory we could do something clever where we don't wait for both
+ * cores to finish precalc before starting either of them on the main
+ * computation, but that way probably lies madness.
*/
-hal_error_t hal_modexp(hal_core_t *core,
- const uint8_t * const msg, const size_t msg_len, /* Message */
- const uint8_t * const exp, const size_t exp_len, /* Exponent */
- const uint8_t * const mod, const size_t mod_len, /* Modulus */
- uint8_t *result, const size_t result_len)
+static inline hal_error_t check_args(hal_modexp_arg_t *a)
+{
+ /*
+ * All data pointers must be set, exponent may not be longer than
+ * modulus, message may not be longer than twice the modulus (CRT
+ * mode), result buffer must not be shorter than modulus, and all
+ * input lengths must be a multiple of four bytes (the core is all
+ * about 32-bit words).
+ */
+
+ if (a == NULL ||
+ a->msg == NULL || a->msg_len > MODEXPA7_OPERAND_BYTES || a->msg_len > a->mod_len * 2 ||
+ a->exp == NULL || a->exp_len > MODEXPA7_OPERAND_BYTES || a->exp_len > a->mod_len ||
+ a->mod == NULL || a->mod_len > MODEXPA7_OPERAND_BYTES ||
+ a->result == NULL || a->result_len > MODEXPA7_OPERAND_BYTES || a->result_len < a->mod_len ||
+ a->coeff == NULL || a->coeff_len > MODEXPA7_OPERAND_BYTES ||
+ a->mont == NULL || a->mont_len > MODEXPA7_OPERAND_BYTES ||
+ ((a->msg_len | a->exp_len | a->mod_len) & 3) != 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ return HAL_OK;
+}
+
+static inline hal_error_t setup_precalc(const int precalc, hal_modexp_arg_t *a)
{
hal_error_t err;
/*
- * All pointers must be set, neither message nor exponent may be
- * longer than modulus, result buffer must not be shorter than
- * modulus, and all input lengths must be a multiple of four.
- *
- * The multiple-of-four restriction is a pain, but the rest of the
- * HAL code currently enforces the same restriction, and allowing
- * arbitrary lengths would require some tedious shuffling to deal
- * with alignment issues, so it's not worth trying to fix only here.
+ * Check that operand size is compatabible with the core.
*/
- if (msg == NULL || exp == NULL || mod == NULL || result == NULL ||
- msg_len > mod_len || exp_len > mod_len || result_len < mod_len ||
- ((msg_len | exp_len | mod_len) & 3) != 0)
+ uint32_t operand_max = 0;
+
+ if ((err = get_register(a->core, MODEXPA7_ADDR_BUFFER_BITS, &operand_max)) != HAL_OK)
+ return err;
+
+ operand_max /= 8;
+
+ if (a->msg_len > operand_max ||
+ a->exp_len > operand_max ||
+ a->mod_len > operand_max ||
+ a->coeff_len > operand_max ||
+ a->mont_len > operand_max)
return HAL_ERROR_BAD_ARGUMENTS;
- if (((err = hal_core_alloc(MODEXPS6_NAME, &core)) == HAL_ERROR_CORE_NOT_FOUND) &&
- ((err = hal_core_alloc(MODEXPA7_NAME, &core)) != HAL_OK))
+ /*
+ * Set the modulus, then initiate calculation of modulus-dependent
+ * speedup factors if necessary, by edge-triggering the "init" bit,
+ * then return to caller so it can wait for precalc.
+ */
+
+ if ((err = set_register(a->core, MODEXPA7_ADDR_MODULUS_BITS, a->mod_len * 8)) != HAL_OK ||
+ (err = set_buffer(a->core, MODEXPA7_ADDR_MODULUS, a->mod, a->mod_len)) != HAL_OK ||
+ (precalc && (err = hal_io_zero(a->core)) != HAL_OK) ||
+ (precalc && (err = hal_io_init(a->core)) != HAL_OK))
return err;
-#undef check
-#define check(_expr_) \
- do { \
- hal_error_t _err = (_expr_); \
- if (_err != HAL_OK && debug) \
- printf("%s failed: %s\n", #_expr_, hal_error_string(_err)); \
- if (_err != HAL_OK) { \
- hal_core_free(core); \
- return _err; \
- } \
- } while (0)
+ return HAL_OK;
+}
+
+static inline hal_error_t setup_calc(const int precalc, hal_modexp_arg_t *a)
+{
+ hal_error_t err;
/*
- * We probably ought to take the mode (fast vs constant-time) as an
- * argument, but for the moment we just guess that really short
- * exponent means we're using the public key and can use fast mode,
- * all other cases are something to do with the private key and
- * therefore must use constant-time mode.
- *
- * Unclear whether it's worth trying to figure out exactly how long
- * the operands are: assuming a multiple of eight is safe, but makes
- * a bit more work for the core; checking to see how many bits are
- * really set leaves the core sitting idle while the main CPU does
- * these checks. No way to know which is faster without testing;
- * take simple approach for the moment.
+ * Select CRT mode if and only if message is longer than exponent.
*/
- /* Select mode (1 = fast, 0 = safe) */
- check(set_register(core, MODEXPS6_ADDR_MODE, (exp_len <= 4)));
+ const uint32_t mode = a->msg_len > a->mod_len ? MODEXPA7_MODE_CRT : MODEXPA7_MODE_PLAIN;
- /* Set modulus size in bits */
- check(set_register(core, MODEXPS6_ADDR_MODULUS_WIDTH, mod_len * 8));
+ /*
+ * Copy out precalc results if necessary, then load everything and
+ * start the calculation by edge-triggering the "next" bit. If
+ * everything works, return to caller so it can wait for the
+ * calculation to complete.
+ */
- /* Write new modulus */
- check(set_buffer(core, MODEXPS6_ADDR_MODULUS, mod, mod_len));
+ if ((precalc &&
+ (err = get_buffer(a->core, MODEXPA7_ADDR_MODULUS_COEFF_OUT, a->coeff, a->coeff_len)) != HAL_OK) ||
+ (precalc &&
+ (err = get_buffer(a->core, MODEXPA7_ADDR_MONTGOMERY_FACTOR_OUT, a->mont, a->mont_len)) != HAL_OK) ||
+ (err = set_buffer(a->core, MODEXPA7_ADDR_MODULUS_COEFF_IN, a->coeff, a->coeff_len)) != HAL_OK ||
+ (err = set_buffer(a->core, MODEXPA7_ADDR_MONTGOMERY_FACTOR_IN, a->mont, a->mont_len)) != HAL_OK ||
+ (err = set_register(a->core, MODEXPA7_ADDR_MODE, mode)) != HAL_OK ||
+ (err = set_buffer(a->core, MODEXPA7_ADDR_MESSAGE, a->msg, a->msg_len)) != HAL_OK ||
+ (err = set_buffer(a->core, MODEXPA7_ADDR_EXPONENT, a->exp, a->exp_len)) != HAL_OK ||
+ (err = set_register(a->core, MODEXPA7_ADDR_EXPONENT_BITS, a->exp_len * 8)) != HAL_OK ||
+ (err = hal_io_zero(a->core)) != HAL_OK ||
+ (err = hal_io_next(a->core)) != HAL_OK)
+ return err;
- /* Pre-calcuate speed-up coefficient */
- check(hal_io_init(core));
+ return HAL_OK;
+}
- /* Wait for calculation to complete */
- check(hal_io_wait_ready(core));
+static inline hal_error_t extract_result(hal_modexp_arg_t *a)
+{
+ /*
+ * Extract results from the main calculation and we're done.
+ * Hardly seems worth making this a separate function.
+ */
- /* Write new message */
- check(set_buffer(core, MODEXPS6_ADDR_MESSAGE, msg, msg_len));
+ return get_buffer(a->core, MODEXPA7_ADDR_RESULT, a->result, a->mod_len);
+}
- /* Set new exponent length in bits */
- check(set_register(core, MODEXPS6_ADDR_EXPONENT_WIDTH, exp_len * 8));
+/*
+ * Run one modexp operation.
+ */
- /* Set new exponent */
- check(set_buffer(core, MODEXPS6_ADDR_EXPONENT, exp, exp_len));
+hal_error_t hal_modexp(const int precalc, hal_modexp_arg_t *a)
+{
+ hal_error_t err;
- /* Start calculation */
- check(hal_io_next(core));
+ if ((err = check_args(a)) != HAL_OK)
+ return err;
- /* Wait for result */
- check(hal_io_wait_valid(core));
+ if ((err = hal_core_alloc(MODEXPA7_NAME, &a->core)) == HAL_OK &&
+ (err = setup_precalc(precalc, a)) == HAL_OK &&
+ (!precalc ||
+ (err = hal_io_wait_ready(a->core)) == HAL_OK) &&
+ (err = setup_calc(precalc, a)) == HAL_OK &&
+ (err = hal_io_wait_valid(a->core)) == HAL_OK &&
+ (err = extract_result(a)) == HAL_OK)
+ err = HAL_OK;
+
+ hal_core_free(a->core);
+ return err;
+}
- /* Extract result */
- check(get_buffer(core, MODEXPS6_ADDR_RESULT, result, mod_len));
+/*
+ * Run two modexp operations in parallel.
+ */
- return HAL_OK;
+hal_error_t hal_modexp2(const int precalc, hal_modexp_arg_t *a1, hal_modexp_arg_t *a2)
+{
+ hal_error_t err;
+
+ if ((err = check_args(a1)) != HAL_OK ||
+ (err = check_args(a2)) != HAL_OK)
+ return err;
+
+ if ((err = hal_core_alloc2(MODEXPA7_NAME, &a1->core,
+ MODEXPA7_NAME, &a2->core)) == HAL_OK &&
+ (err = setup_precalc(precalc, a1)) == HAL_OK &&
+ (err = setup_precalc(precalc, a2)) == HAL_OK &&
+ (!precalc ||
+ (err = hal_io_wait_ready2(a1->core, a2->core)) == HAL_OK) &&
+ (err = setup_calc(precalc, a1)) == HAL_OK &&
+ (err = setup_calc(precalc, a2)) == HAL_OK &&
+ (err = hal_io_wait_valid2(a1->core, a2->core)) == HAL_OK &&
+ (err = extract_result(a1)) == HAL_OK &&
+ (err = extract_result(a2)) == HAL_OK)
+ err = HAL_OK;
+
+ hal_core_free(a1->core);
+ hal_core_free(a2->core);
+ return err;
}
/*
diff --git a/pbkdf2.c b/pbkdf2.c
index aa30bb5..87ff574 100644
--- a/pbkdf2.c
+++ b/pbkdf2.c
@@ -90,7 +90,6 @@ hal_error_t hal_pbkdf2(hal_core_t *core,
unsigned iteration;
hal_error_t err;
uint32_t block;
- int i;
if (descriptor == NULL || password == NULL || salt == NULL ||
derived_key == NULL || derived_key_length == 0 ||
@@ -148,7 +147,7 @@ hal_error_t hal_pbkdf2(hal_core_t *core,
0, mac, sizeof(mac))) != HAL_OK)
return err;
- for (i = 0; i < descriptor->digest_length; i++)
+ for (size_t i = 0; i < descriptor->digest_length; i++)
result[i] ^= mac[i];
}
diff --git a/rpc_api.c b/rpc_api.c
index 1a2d268..b75043a 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -35,6 +35,7 @@
#include "hal.h"
#include "hal_internal.h"
+#include "hashsig.h"
const hal_hash_handle_t hal_hash_handle_none = {HAL_HANDLE_NONE};
@@ -64,6 +65,10 @@ static inline int check_pkey_type(const hal_key_type_t type)
case HAL_KEY_TYPE_RSA_PUBLIC:
case HAL_KEY_TYPE_EC_PRIVATE:
case HAL_KEY_TYPE_EC_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_LMS:
+ case HAL_KEY_TYPE_HASHSIG_LMOTS:
return 1;
default:
return 0;
@@ -91,6 +96,10 @@ static inline int check_pkey_type_curve_flags(const hal_key_type_t type,
case HAL_KEY_TYPE_RSA_PRIVATE:
case HAL_KEY_TYPE_RSA_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_LMS:
+ case HAL_KEY_TYPE_HASHSIG_LMOTS:
return curve == HAL_CURVE_NONE;
case HAL_KEY_TYPE_EC_PRIVATE:
@@ -264,6 +273,20 @@ hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client,
return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, curve, flags);
}
+hal_error_t hal_rpc_pkey_generate_hashsig(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const hal_key_flags_t flags)
+{
+ if (pkey == NULL || name == NULL || !check_pkey_flags(flags))
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hal_rpc_pkey_dispatch->generate_hashsig(client, session, pkey, name, hss_levels, lms_type, lmots_type, flags);
+}
+
hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey)
{
return hal_rpc_pkey_dispatch->close(pkey);
@@ -352,7 +375,7 @@ hal_error_t hal_rpc_pkey_match(const hal_client_handle_t client,
return HAL_ERROR_BAD_ARGUMENTS;
if (attributes != NULL)
- for (int i = 0; i < attributes_len; i++)
+ for (size_t i = 0; i < attributes_len; i++)
if (attributes[i].value == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
diff --git a/rpc_client.c b/rpc_client.c
index e968369..2fb8ae6 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -4,7 +4,7 @@
* Remote procedure call client-side private API implementation.
*
* Authors: Rob Austein, Paul Selkirk
- * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -38,6 +38,7 @@
#include "hal.h"
#include "hal_internal.h"
#include "xdr_internal.h"
+#include "hashsig.h"
#ifndef HAL_RPC_CLIENT_DEBUG
#define HAL_RPC_CLIENT_DEBUG 0
@@ -139,7 +140,7 @@ static hal_error_t get_random(void *buffer, const size_t length)
uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4) + pad(length)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t rcvlen = length;
+ size_t rcvlen = length;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
@@ -152,7 +153,7 @@ static hal_error_t get_random(void *buffer, const size_t length)
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_buffer(&iptr, ilimit, buffer, &rcvlen));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, buffer, &rcvlen));
// XXX check rcvlen vs length
}
return rpc_ret;
@@ -170,7 +171,7 @@ static hal_error_t set_pin(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_SET_PIN));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, user));
- check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, (const uint8_t *)pin, pin_len));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_SET_PIN, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -205,7 +206,7 @@ static hal_error_t login(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGIN));
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, user));
- check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, (const uint8_t *)pin, pin_len));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_LOGIN, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -298,7 +299,6 @@ static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg
uint8_t outbuf[nargs(4)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4) + pad(len_max)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t len32 = len_max;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
@@ -313,8 +313,8 @@ static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_buffer(&iptr, ilimit, id, &len32));
- *len = len32;
+ *len = len_max;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, id, len));
}
return rpc_ret;
}
@@ -358,7 +358,7 @@ static hal_error_t hash_initialize(const hal_client_handle_t client,
check(hal_xdr_encode_int(&optr, olimit, client.handle));
check(hal_xdr_encode_int(&optr, olimit, session.handle));
check(hal_xdr_encode_int(&optr, olimit, alg));
- check(hal_xdr_encode_buffer(&optr, olimit, key, key_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, key, key_len));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_HASH_INITIALIZE, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -382,7 +382,7 @@ static hal_error_t hash_update(const hal_hash_handle_t hash,
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_UPDATE));
check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
check(hal_xdr_encode_int(&optr, olimit, hash.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, data, length));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, data, length));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_HASH_UPDATE, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -397,7 +397,7 @@ static hal_error_t hash_finalize(const hal_hash_handle_t hash,
uint8_t outbuf[nargs(4)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4) + pad(length)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t digest_len = length;
+ size_t digest_len = length;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
@@ -411,7 +411,7 @@ static hal_error_t hash_finalize(const hal_hash_handle_t hash,
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_buffer(&iptr, ilimit, digest, &digest_len));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, digest, &digest_len));
/* XXX check digest_len vs length */
}
return rpc_ret;
@@ -427,27 +427,25 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client,
uint8_t outbuf[nargs(5) + 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);
+ size_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
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, der, der_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, der, der_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
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) {
check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
- check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len));
if (name_len != sizeof(name->uuid))
return HAL_ERROR_KEY_NAME_TOO_LONG;
}
-
return rpc_ret;
}
@@ -464,7 +462,7 @@ static hal_error_t pkey_remote_open(const hal_client_handle_t client,
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_buffer(&optr, olimit, name->uuid, sizeof(name->uuid)));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, name->uuid, sizeof(name->uuid)));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_PKEY_OPEN, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -488,14 +486,14 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
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);
+ size_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_int(&optr, olimit, key_len));
- check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, exp, exp_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -505,7 +503,7 @@ static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
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));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len));
if (name_len != sizeof(name->uuid))
return HAL_ERROR_KEY_NAME_TOO_LONG;
}
@@ -523,7 +521,7 @@ static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
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);
+ size_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
@@ -539,7 +537,45 @@ static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
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));
+ check(hal_xdr_decode_variable_opaque(&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_generate_hashsig(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const hal_key_flags_t flags)
+{
+ uint8_t outbuf[nargs(7)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
+ const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ size_t name_len = sizeof(name->uuid);
+ hal_error_t rpc_ret;
+
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_HASHSIG));
+ 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, (uint32_t)hss_levels));
+ check(hal_xdr_encode_int(&optr, olimit, (uint32_t)lms_type));
+ check(hal_xdr_encode_int(&optr, olimit, (uint32_t)lmots_type));
+ check(hal_xdr_encode_int(&optr, olimit, flags));
+ check(hal_rpc_send(outbuf, optr - outbuf));
+
+ check(read_matching_packet(RPC_FUNC_PKEY_GENERATE_HASHSIG, 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));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len));
if (name_len != sizeof(name->uuid))
return HAL_ERROR_KEY_NAME_TOO_LONG;
}
@@ -677,12 +713,11 @@ static size_t pkey_remote_get_public_key_len(const hal_pkey_handle_t pkey)
check(read_matching_packet(RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN, 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, &len32));
+ if (rpc_ret == HAL_OK &&
+ hal_xdr_decode_int(&iptr, ilimit, &len32) == HAL_OK)
return (size_t)len32;
- }
- else
- return 0;
+
+ return 0;
}
static hal_error_t pkey_remote_get_public_key(const hal_pkey_handle_t pkey,
@@ -691,7 +726,6 @@ static hal_error_t pkey_remote_get_public_key(const hal_pkey_handle_t pkey,
uint8_t outbuf[nargs(4)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
uint8_t inbuf[nargs(4) + pad(der_max)];
const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
- uint32_t dlen32 = der_max;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
@@ -705,8 +739,8 @@ static hal_error_t pkey_remote_get_public_key(const hal_pkey_handle_t pkey,
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_buffer(&iptr, ilimit, der, &dlen32));
- *der_len = (size_t)dlen32;
+ *der_len = der_max;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, der, der_len));
}
return rpc_ret;
}
@@ -719,7 +753,6 @@ static hal_error_t pkey_remote_sign(const hal_pkey_handle_t pkey,
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;
hal_client_handle_t dummy_client = {0};
hal_error_t rpc_ret;
@@ -727,7 +760,7 @@ static hal_error_t pkey_remote_sign(const hal_pkey_handle_t pkey,
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, hash.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, input, input_len));
check(hal_xdr_encode_int(&optr, olimit, signature_max));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -735,8 +768,8 @@ static hal_error_t pkey_remote_sign(const hal_pkey_handle_t pkey,
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- check(hal_xdr_decode_buffer(&iptr, ilimit, signature, &slen32));
- *signature_len = (size_t)slen32;
+ *signature_len = signature_max;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, signature, signature_len));
}
return rpc_ret;
}
@@ -756,8 +789,8 @@ static hal_error_t pkey_remote_verify(const hal_pkey_handle_t pkey,
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, hash.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
- check(hal_xdr_encode_buffer(&optr, olimit, signature, signature_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, input, input_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, signature, signature_len));
check(hal_rpc_send(outbuf, optr - outbuf));
check(read_matching_packet(RPC_FUNC_PKEY_VERIFY, inbuf, sizeof(inbuf), &iptr, &ilimit));
@@ -802,12 +835,12 @@ static hal_error_t pkey_remote_match(const hal_client_handle_t client,
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_variable_opaque(&optr, olimit, attributes[i].value, attributes[i].length));
}
}
check(hal_xdr_encode_int(&optr, olimit, *state));
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_xdr_encode_variable_opaque(&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));
@@ -820,8 +853,8 @@ static hal_error_t pkey_remote_match(const hal_client_handle_t client,
*state = ustate;
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));
+ size_t uuid_len = sizeof(result[i].uuid);
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, result[i].uuid, &uuid_len));
if (uuid_len != sizeof(result[i].uuid))
return HAL_ERROR_KEY_NAME_TOO_LONG;
}
@@ -853,7 +886,7 @@ static hal_error_t pkey_remote_set_attributes(const hal_pkey_handle_t pkey,
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_xdr_encode_variable_opaque(&optr, olimit, attributes[i].value, attributes[i].length));
}
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -904,10 +937,10 @@ static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey,
attributes[i].length = u32;
}
else {
- u32 = attributes_buffer + attributes_buffer_len - abuf;
- check(hal_xdr_decode_buffer(&iptr, ilimit, abuf, &u32));
+ size_t len = attributes_buffer + attributes_buffer_len - abuf;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, abuf, &len));
attributes[i].value = abuf;
- attributes[i].length = u32;
+ attributes[i].length = len;
abuf += u32;
}
}
@@ -938,13 +971,10 @@ static hal_error_t pkey_remote_export(const hal_pkey_handle_t pkey,
check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
if (rpc_ret == HAL_OK) {
- uint32_t len;
- len = pkcs8_max;
- check(hal_xdr_decode_buffer(&iptr, ilimit, pkcs8, &len));
- *pkcs8_len = (size_t) len;
- len = kek_max;
- check(hal_xdr_decode_buffer(&iptr, ilimit, kek, &len));
- *kek_len = (size_t) len;
+ *pkcs8_len = pkcs8_max;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, pkcs8, pkcs8_len));
+ *kek_len = kek_max;
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, kek, kek_len));
}
return rpc_ret;
}
@@ -961,15 +991,15 @@ static hal_error_t pkey_remote_import(const hal_client_handle_t client,
uint8_t outbuf[nargs(7) + pad(pkcs8_len) + pad(kek_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);
+ size_t name_len = sizeof(name->uuid);
hal_error_t rpc_ret;
check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_IMPORT));
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, kekek.handle));
- check(hal_xdr_encode_buffer(&optr, olimit, pkcs8, pkcs8_len));
- check(hal_xdr_encode_buffer(&optr, olimit, kek, kek_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, pkcs8, pkcs8_len));
+ check(hal_xdr_encode_variable_opaque(&optr, olimit, kek, kek_len));
check(hal_xdr_encode_int(&optr, olimit, flags));
check(hal_rpc_send(outbuf, optr - outbuf));
@@ -979,7 +1009,7 @@ static hal_error_t pkey_remote_import(const hal_client_handle_t client,
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));
+ check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len));
if (name_len != sizeof(name->uuid))
return HAL_ERROR_KEY_NAME_TOO_LONG;
}
@@ -1104,6 +1134,7 @@ const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
.open = pkey_remote_open,
.generate_rsa = pkey_remote_generate_rsa,
.generate_ec = pkey_remote_generate_ec,
+ .generate_hashsig = pkey_remote_generate_hashsig,
.close = pkey_remote_close,
.delete = pkey_remote_delete,
.get_key_type = pkey_remote_get_key_type,
@@ -1126,6 +1157,7 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
.open = pkey_remote_open,
.generate_rsa = pkey_remote_generate_rsa,
.generate_ec = pkey_remote_generate_ec,
+ .generate_hashsig = pkey_remote_generate_hashsig,
.close = pkey_remote_close,
.delete = pkey_remote_delete,
.get_key_type = pkey_remote_get_key_type,
diff --git a/rpc_hash.c b/rpc_hash.c
index 0811e81..13b6891 100644
--- a/rpc_hash.c
+++ b/rpc_hash.c
@@ -93,7 +93,7 @@ static inline handle_slot_t *alloc_handle(const int is_hmac)
#if HAL_STATIC_HASH_STATE_BLOCKS > 0
if (!is_hmac) {
- for (int i = 0; i < sizeof(hash_handle)/sizeof(*hash_handle); i++) {
+ for (size_t i = 0; i < sizeof(hash_handle)/sizeof(*hash_handle); i++) {
if (hash_handle[i].state.hash != NULL)
continue;
hash_handle[i].hash_handle.handle = i | glop;
@@ -104,7 +104,7 @@ static inline handle_slot_t *alloc_handle(const int is_hmac)
#if HAL_STATIC_HMAC_STATE_BLOCKS > 0
if (is_hmac) {
- for (int i = 0; i < sizeof(hmac_handle)/sizeof(*hmac_handle); i++) {
+ for (size_t i = 0; i < sizeof(hmac_handle)/sizeof(*hmac_handle); i++) {
if (hmac_handle[i].state.hmac != NULL)
continue;
hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC;
@@ -124,7 +124,7 @@ static inline handle_slot_t *alloc_handle(const int is_hmac)
static inline handle_slot_t *find_handle(const hal_hash_handle_t handle)
{
#if HAL_STATIC_HASH_STATE_BLOCKS > 0 || HAL_STATIC_HMAC_STATE_BLOCKS > 0
- const int i = (int) (handle.handle & 0xFFFF);
+ const size_t i = (size_t) (handle.handle & 0xFFFF);
const int is_hmac = (handle.handle & HANDLE_FLAG_HMAC) != 0;
#endif
diff --git a/rpc_misc.c b/rpc_misc.c
index 3f466bb..c27913c 100644
--- a/rpc_misc.c
+++ b/rpc_misc.c
@@ -33,8 +33,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <assert.h>
-
#include "hal.h"
#include "hal_internal.h"
@@ -46,7 +44,8 @@ static hal_error_t get_version(uint32_t *version)
static hal_error_t get_random(void *buffer, const size_t length)
{
- assert(buffer != NULL && length > 0);
+ if (buffer == NULL || length == 0)
+ return HAL_ERROR_IMPOSSIBLE;
return hal_get_random(NULL, buffer, length);
}
@@ -96,7 +95,7 @@ static uint32_t hal_pin_default_iterations = HAL_PIN_DEFAULT_ITERATIONS;
#endif
#ifndef HAL_STATIC_CLIENT_STATE_BLOCKS
-#define HAL_STATIC_CLIENT_STATE_BLOCKS 10
+#define HAL_STATIC_CLIENT_STATE_BLOCKS 10
#endif
#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
@@ -109,19 +108,51 @@ static client_slot_t client_handle[HAL_STATIC_CLIENT_STATE_BLOCKS];
* them. HAL_USER_NONE indicates an empty slot in the table.
*/
-static inline client_slot_t *alloc_slot(void)
+static inline hal_error_t alloc_slot(const hal_client_handle_t client,
+ const hal_user_t user)
{
client_slot_t *slot = NULL;
hal_critical_section_start();
#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
- for (int i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
+
+ for (size_t i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
+ if (client_handle[i].logged_in != HAL_USER_NONE &&
+ client_handle[i].handle.handle == client.handle)
+ slot = &client_handle[i];
+
+ for (size_t i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
if (client_handle[i].logged_in == HAL_USER_NONE)
slot = &client_handle[i];
+
#endif
+ if (slot != NULL) {
+ slot->handle = client;
+ slot->logged_in = user;
+ }
+
hal_critical_section_end();
- return slot;
+ return slot == NULL ? HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE : HAL_OK;
+}
+
+static inline hal_error_t clear_slot(client_slot_t *slot)
+{
+ if (slot == NULL)
+ return HAL_OK;
+
+ hal_error_t err;
+
+ if ((err = hal_pkey_logout(slot->handle)) != HAL_OK)
+ return err;
+
+ hal_critical_section_start();
+
+ memset(slot, 0, sizeof(*slot));
+
+ hal_critical_section_end();
+
+ return HAL_OK;
}
static inline client_slot_t *find_handle(const hal_client_handle_t handle)
@@ -130,7 +161,7 @@ static inline client_slot_t *find_handle(const hal_client_handle_t handle)
hal_critical_section_start();
#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
- for (int i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
+ for (size_t i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
if (client_handle[i].logged_in != HAL_USER_NONE && client_handle[i].handle.handle == handle.handle)
slot = &client_handle[i];
#endif
@@ -143,8 +174,8 @@ static hal_error_t login(const hal_client_handle_t client,
const hal_user_t user,
const char * const pin, const size_t pin_len)
{
- assert(pin != NULL && pin_len != 0);
- assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL);
+ if (pin == NULL || pin_len == 0 || (user != HAL_USER_NORMAL && user != HAL_USER_SO && user != HAL_USER_WHEEL))
+ return HAL_ERROR_IMPOSSIBLE;
const hal_ks_pin_t *p;
hal_error_t err;
@@ -160,7 +191,7 @@ static hal_error_t login(const hal_client_handle_t client,
return err;
unsigned diff = 0;
- for (int i = 0; i < sizeof(buf); i++)
+ for (size_t i = 0; i < sizeof(buf); i++)
diff |= buf[i] ^ p->pin[i];
if (diff != 0) {
@@ -168,21 +199,14 @@ static hal_error_t login(const hal_client_handle_t client,
return HAL_ERROR_PIN_INCORRECT;
}
- client_slot_t *slot = find_handle(client);
-
- if (slot == NULL && (slot = alloc_slot()) == NULL)
- return HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE;
-
- slot->handle = client;
- slot->logged_in = user;
-
- return HAL_OK;
+ return alloc_slot(client, user);
}
static hal_error_t is_logged_in(const hal_client_handle_t client,
const hal_user_t user)
{
- assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL);
+ if (user != HAL_USER_NORMAL && user != HAL_USER_SO && user != HAL_USER_WHEEL)
+ return HAL_ERROR_IMPOSSIBLE;
client_slot_t *slot = find_handle(client);
@@ -194,19 +218,32 @@ static hal_error_t is_logged_in(const hal_client_handle_t client,
static hal_error_t logout(const hal_client_handle_t client)
{
- client_slot_t *slot = find_handle(client);
-
- if (slot != NULL)
- slot->logged_in = HAL_USER_NONE;
-
- return HAL_OK;
+ return clear_slot(find_handle(client));
}
static hal_error_t logout_all(void)
{
#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
- for (int i = 0; i < sizeof(client_handle)/sizeof(*client_handle); i++)
- client_handle[i].logged_in = HAL_USER_NONE;
+
+ client_slot_t *slot;
+ hal_error_t err;
+ size_t i = 0;
+
+ do {
+
+ hal_critical_section_start();
+
+ for (slot = NULL; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
+ if (client_handle[i].logged_in != HAL_USER_NONE)
+ slot = &client_handle[i];
+
+ hal_critical_section_end();
+
+ if ((err = clear_slot(slot)) != HAL_OK)
+ return err;
+
+ } while (slot != NULL);
+
#endif
return HAL_OK;
@@ -216,7 +253,8 @@ static hal_error_t set_pin(const hal_client_handle_t client,
const hal_user_t user,
const char * const newpin, const size_t newpin_len)
{
- assert(newpin != NULL && newpin_len >= hal_rpc_min_pin_length && newpin_len <= hal_rpc_max_pin_length);
+ if (newpin == NULL || newpin_len < hal_rpc_min_pin_length || newpin_len > hal_rpc_max_pin_length)
+ return HAL_ERROR_IMPOSSIBLE;
if ((user != HAL_USER_NORMAL || is_logged_in(client, HAL_USER_SO) != HAL_OK) &&
is_logged_in(client, HAL_USER_WHEEL) != HAL_OK)
diff --git a/rpc_pkey.c b/rpc_pkey.c
index bdf8a7e..1aee050 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -39,6 +39,7 @@
#include "hal.h"
#include "hal_internal.h"
#include "asn1_internal.h"
+#include "hashsig.h"
#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
#define HAL_STATIC_PKEY_STATE_BLOCKS 0
@@ -78,11 +79,11 @@ static inline hal_pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
if ((flags & HAL_KEY_FLAG_TOKEN) != 0)
glop |= HAL_PKEY_HANDLE_TOKEN_FLAG;
- for (int i = 0; slot == NULL && i < sizeof(pkey_slot)/sizeof(*pkey_slot); i++) {
- if (pkey_slot[i].pkey_handle.handle != HAL_HANDLE_NONE)
+ for (size_t i = 0; slot == NULL && i < sizeof(pkey_slot)/sizeof(*pkey_slot); i++) {
+ if (pkey_slot[i].pkey.handle != HAL_HANDLE_NONE)
continue;
memset(&pkey_slot[i], 0, sizeof(pkey_slot[i]));
- pkey_slot[i].pkey_handle.handle = i | glop;
+ pkey_slot[i].pkey.handle = i | glop;
pkey_slot[i].hint = -1;
slot = &pkey_slot[i];
}
@@ -118,9 +119,9 @@ static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
hal_critical_section_start();
#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
- const int i = (int) (handle.handle & 0xFFFF);
+ const size_t i = handle.handle & 0xFFFF;
- if (i < sizeof(pkey_slot)/sizeof(*pkey_slot) && pkey_slot[i].pkey_handle.handle == handle.handle)
+ if (i < sizeof(pkey_slot)/sizeof(*pkey_slot) && pkey_slot[i].pkey.handle == handle.handle)
slot = &pkey_slot[i];
#endif
@@ -129,6 +130,32 @@ static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
}
/*
+ * Clean up key state associated with a client when logging out.
+ */
+
+hal_error_t hal_pkey_logout(const hal_client_handle_t client)
+{
+ if (client.handle == HAL_HANDLE_NONE)
+ return HAL_OK;
+
+ hal_error_t err;
+
+ if ((err = hal_ks_logout(hal_ks_volatile, client)) != HAL_OK ||
+ (err = hal_ks_logout(hal_ks_token, client)) != HAL_OK)
+ return err;
+
+ hal_critical_section_start();
+
+ for (size_t i = 0; i < sizeof(pkey_slot)/sizeof(*pkey_slot); i++)
+ if (pkey_slot[i].pkey.handle == client.handle)
+ memset(&pkey_slot[i], 0, sizeof(pkey_slot[i]));
+
+ hal_critical_section_end();
+
+ return HAL_OK;
+}
+
+/*
* Access rules are a bit complicated, mostly due to PKCS #11.
*
* The simple, obvious rule would be that one must be logged in as
@@ -270,52 +297,25 @@ 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);
-}
-
-/*
- * Fetch a key from a driver.
+ * Given key flags, return appropriate keystore.
*/
-static inline hal_error_t ks_fetch_from_driver(const hal_ks_driver_t * const driver,
- hal_pkey_slot_t *slot,
- uint8_t *der, size_t *der_len, const size_t der_max)
+static inline hal_ks_t *ks_from_flags(const hal_key_flags_t flags)
{
- hal_ks_t *ks = NULL;
- hal_error_t err;
-
- if ((err = hal_ks_open(driver, &ks)) != HAL_OK)
- return err;
-
- if ((err = hal_ks_fetch(ks, slot, der, der_len, der_max)) == HAL_OK)
- err = hal_ks_close(ks);
- else
- (void) hal_ks_close(ks);
-
- return err;
+ return (flags & HAL_KEY_FLAG_TOKEN) == 0 ? hal_ks_volatile : hal_ks_token;
}
/*
- * Same thing but from key flag in slot object rather than explict driver.
+ * Fetch a key from keystore indicated by key flag in slot object.
*/
static inline hal_error_t ks_fetch_from_flags(hal_pkey_slot_t *slot,
uint8_t *der, size_t *der_len, const size_t der_max)
{
- assert(slot != NULL);
+ if (slot == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
- return ks_fetch_from_driver((slot->flags & HAL_KEY_FLAG_TOKEN) == 0
- ? hal_ks_volatile_driver
- : hal_ks_token_driver,
- slot, der, der_len, der_max);
+ return hal_ks_fetch(ks_from_flags(slot->flags), slot, der, der_len, der_max);
}
@@ -336,7 +336,6 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
hal_curve_name_t curve;
hal_pkey_slot_t *slot;
hal_key_type_t type;
- hal_ks_t *ks = NULL;
hal_error_t err;
if ((err = check_writable(client, flags)) != HAL_OK)
@@ -351,24 +350,18 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
return err;
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = type;
- slot->curve = curve;
- slot->flags = flags;
-
- 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);
+ slot->client = client;
+ slot->session = session;
+ slot->type = type;
+ slot->curve = curve;
+ slot->flags = flags;
- if (err != HAL_OK) {
+ if ((err = hal_ks_store(ks_from_flags(flags), slot, der, der_len)) != HAL_OK) {
slot->type = HAL_KEY_TYPE_NONE;
return err;
}
- *pkey = slot->pkey_handle;
+ *pkey = slot->pkey;
*name = slot->name;
return HAL_OK;
}
@@ -393,20 +386,20 @@ static hal_error_t pkey_local_open(const hal_client_handle_t client,
if ((slot = alloc_slot(0)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
- slot->name = *name;
- slot->client_handle = client;
- slot->session_handle = session;
+ slot->name = *name;
+ slot->client = client;
+ slot->session = session;
- if ((err = ks_fetch_from_driver(hal_ks_token_driver, slot, NULL, NULL, 0)) == HAL_OK)
- slot->pkey_handle.handle |= HAL_PKEY_HANDLE_TOKEN_FLAG;
+ if ((err = hal_ks_fetch(hal_ks_token, slot, NULL, NULL, 0)) == HAL_OK)
+ slot->pkey.handle |= HAL_PKEY_HANDLE_TOKEN_FLAG;
else if (err == HAL_ERROR_KEY_NOT_FOUND)
- err = ks_fetch_from_driver(hal_ks_volatile_driver, slot, NULL, NULL, 0);
+ err = hal_ks_fetch(hal_ks_volatile, slot, NULL, NULL, 0);
if (err != HAL_OK)
goto fail;
- *pkey = slot->pkey_handle;
+ *pkey = slot->pkey;
return HAL_OK;
fail:
@@ -431,7 +424,6 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
uint8_t keybuf[hal_rsa_key_t_size];
hal_rsa_key_t *key = NULL;
hal_pkey_slot_t *slot;
- hal_ks_t *ks = NULL;
hal_error_t err;
if ((err = check_writable(client, flags)) != HAL_OK)
@@ -443,11 +435,11 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
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;
+ slot->client = client;
+ slot->session = 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) {
@@ -458,12 +450,8 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
uint8_t der[hal_rsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
- (err = 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_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_store(ks_from_flags(flags), slot, der, der_len);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -473,7 +461,7 @@ static hal_error_t pkey_local_generate_rsa(const hal_client_handle_t client,
return err;
}
- *pkey = slot->pkey_handle;
+ *pkey = slot->pkey;
*name = slot->name;
return HAL_OK;
}
@@ -495,7 +483,6 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
uint8_t keybuf[hal_ecdsa_key_t_size];
hal_ecdsa_key_t *key = NULL;
hal_pkey_slot_t *slot;
- hal_ks_t *ks = NULL;
hal_error_t err;
if ((err = check_writable(client, flags)) != HAL_OK)
@@ -507,11 +494,11 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
if ((err = hal_uuid_gen(&slot->name)) != HAL_OK)
return err;
- slot->client_handle = client;
- slot->session_handle = session;
- slot->type = HAL_KEY_TYPE_EC_PRIVATE;
- slot->curve = curve;
- slot->flags = flags;
+ slot->client = client;
+ slot->session = 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;
@@ -521,12 +508,8 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
uint8_t der[hal_ecdsa_private_key_to_der_len(key)];
size_t der_len;
- if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK &&
- (err = 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_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_store(ks_from_flags(flags), slot, der, der_len);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -536,7 +519,69 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
return err;
}
- *pkey = slot->pkey_handle;
+ *pkey = slot->pkey;
+ *name = slot->name;
+ return HAL_OK;
+}
+
+/*
+ * Generate a new hash-tree key with supplied name, return a key handle.
+ */
+
+static hal_error_t pkey_local_generate_hashsig(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const size_t hss_levels,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ const hal_key_flags_t flags)
+{
+ assert(pkey != NULL && name != NULL);
+
+ hal_hashsig_key_t *key = NULL;
+ hal_pkey_slot_t *slot;
+ hal_error_t err;
+
+ 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_uuid_gen(&slot->name)) != HAL_OK)
+ return err;
+
+ slot->client = client;
+ slot->session = session;
+ slot->type = HAL_KEY_TYPE_HASHSIG_PRIVATE,
+ slot->curve = HAL_CURVE_NONE;
+ slot->flags = flags;
+
+ if ((err = hal_hashsig_key_gen(NULL, &key, hss_levels, lms_type, lmots_type)) != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
+ return err;
+ }
+
+ uint8_t der[hal_hashsig_private_key_to_der_len(key)];
+ size_t der_len;
+
+ if ((err = hal_hashsig_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_store(ks_from_flags(flags), slot, der, der_len);
+
+ /* There's nothing sensitive in the top-level private key, but we wipe
+ * the der anyway, for symmetry with other key types. The actual key buf
+ * is allocated internally and stays in memory, because everything else
+ * is linked off of it.
+ */
+ memset(der, 0, sizeof(der));
+
+ if (err != HAL_OK) {
+ slot->type = HAL_KEY_TYPE_NONE;
+ return err;
+ }
+
+ *pkey = slot->pkey;
*name = slot->name;
return HAL_OK;
}
@@ -560,6 +605,7 @@ static hal_error_t pkey_local_close(const hal_pkey_handle_t pkey)
/*
* Delete a key from the store, given its key 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_delete(const hal_pkey_handle_t pkey)
{
@@ -568,17 +614,27 @@ static hal_error_t pkey_local_delete(const hal_pkey_handle_t 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)
+ if ((err = check_writable(slot->client, 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);
+ hal_key_type_t key_type;
+ if ((err = pkey_local_get_key_type(pkey, &key_type)) != HAL_OK)
+ return err;
+
+ if (key_type == HAL_KEY_TYPE_HASHSIG_PRIVATE) {
+ hal_hashsig_key_t *key;
+ uint8_t keybuf[hal_hashsig_key_t_size];
+ uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
+ size_t der_len;
+ if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) != HAL_OK ||
+ (err = hal_hashsig_private_key_from_der(&key, keybuf, sizeof(keybuf), der, der_len)) != HAL_OK ||
+ (err = hal_hashsig_key_delete(key)) != HAL_OK)
+ return err;
+ }
+
+ err = hal_ks_delete(ks_from_flags(slot->flags), slot);
if (err == HAL_OK || err == HAL_ERROR_KEY_NOT_FOUND)
clear_slot(slot);
@@ -659,9 +715,15 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
size_t result = 0;
- uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
- hal_rsa_key_t *rsa_key = NULL;
- hal_ecdsa_key_t *ecdsa_key = NULL;
+#ifndef max
+#define max(a, b) ((a) >= (b) ? (a) : (b))
+#endif
+ size_t keybuf_size = max(hal_rsa_key_t_size, hal_ecdsa_key_t_size);
+ keybuf_size = max(keybuf_size, hal_hashsig_key_t_size);
+ uint8_t keybuf[keybuf_size];
+ hal_rsa_key_t *rsa_key = NULL;
+ hal_ecdsa_key_t *ecdsa_key = NULL;
+ hal_hashsig_key_t *hashsig_key = NULL;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
hal_error_t err;
@@ -671,6 +733,7 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
case HAL_KEY_TYPE_RSA_PUBLIC:
case HAL_KEY_TYPE_EC_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
result = der_len;
break;
@@ -684,6 +747,11 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
result = hal_ecdsa_public_key_to_der_len(ecdsa_key);
break;
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ if (hal_hashsig_private_key_from_der(&hashsig_key, keybuf, sizeof(keybuf), der, der_len) == HAL_OK)
+ result = hal_hashsig_public_key_to_der_len(hashsig_key);
+ break;
+
default:
break;
}
@@ -707,10 +775,12 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size
- ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
- hal_rsa_key_t *rsa_key = NULL;
- hal_ecdsa_key_t *ecdsa_key = NULL;
+ size_t keybuf_size = max(hal_rsa_key_t_size, hal_ecdsa_key_t_size);
+ keybuf_size = max(keybuf_size, hal_hashsig_key_t_size);
+ uint8_t keybuf[keybuf_size];
+ hal_rsa_key_t *rsa_key = NULL;
+ hal_ecdsa_key_t *ecdsa_key = NULL;
+ hal_hashsig_key_t *hashsig_key = NULL;
uint8_t buf[HAL_KS_WRAPPED_KEYSIZE];
size_t buf_len;
hal_error_t err;
@@ -720,6 +790,7 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
case HAL_KEY_TYPE_RSA_PUBLIC:
case HAL_KEY_TYPE_EC_PUBLIC:
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
if (der_len != NULL)
*der_len = buf_len;
if (der != NULL && der_max < buf_len)
@@ -738,6 +809,11 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
err = hal_ecdsa_public_key_to_der(ecdsa_key, der, der_len, der_max);
break;
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ if ((err = hal_hashsig_private_key_from_der(&hashsig_key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK)
+ err = hal_hashsig_public_key_to_der(hashsig_key, der, der_len, der_max);
+ break;
+
default:
err = HAL_ERROR_UNSUPPORTED_KEY;
break;
@@ -757,7 +833,8 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
* algorithm-specific functions.
*/
-static hal_error_t pkey_local_sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
+static hal_error_t pkey_local_sign_rsa(hal_pkey_slot_t *slot,
+ uint8_t *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len,
const hal_hash_handle_t hash,
const uint8_t * input, size_t input_len,
@@ -782,14 +859,25 @@ static hal_error_t pkey_local_sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
input = signature;
}
- if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len, 0x01)) != HAL_OK ||
- (err = hal_rsa_decrypt(NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK)
+ if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len, 0x01)) != HAL_OK ||
+ (err = hal_rsa_decrypt(NULL, NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK)
return err;
+ if (hal_rsa_key_needs_saving(key)) {
+ uint8_t pkcs8[hal_rsa_private_key_to_der_extra_len(key)];
+ size_t pkcs8_len = 0;
+ if ((err = hal_rsa_private_key_to_der_extra(key, pkcs8, &pkcs8_len, sizeof(pkcs8))) == HAL_OK)
+ err = hal_ks_rewrite_der(ks_from_flags(slot->flags), slot, pkcs8, pkcs8_len);
+ memset(pkcs8, 0, sizeof(pkcs8));
+ if (err != HAL_OK)
+ return err;
+ }
+
return HAL_OK;
}
-static hal_error_t pkey_local_sign_ecdsa(uint8_t *keybuf, const size_t keybuf_len,
+static hal_error_t pkey_local_sign_ecdsa(hal_pkey_slot_t *slot,
+ uint8_t *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len,
const hal_hash_handle_t hash,
const uint8_t * input, size_t input_len,
@@ -826,6 +914,44 @@ 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_hashsig(hal_pkey_slot_t *slot,
+ uint8_t *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len,
+ const hal_hash_handle_t hash,
+ const uint8_t * input, size_t input_len,
+ uint8_t * signature, size_t *signature_len, const size_t signature_max)
+{
+ hal_hashsig_key_t *key = NULL;
+ hal_error_t err;
+
+ assert(signature != NULL && signature_len != NULL);
+ assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0));
+
+ if ((err = hal_hashsig_private_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
+ return err;
+
+ if (input == NULL || input_len == 0) {
+ hal_digest_algorithm_t alg;
+
+ if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK ||
+ (err = hal_rpc_hash_get_digest_length(alg, &input_len)) != HAL_OK)
+ return err;
+
+ if (input_len > signature_max)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ if ((err = hal_rpc_hash_finalize(hash, signature, input_len)) != HAL_OK)
+ return err;
+
+ input = signature;
+ }
+
+ if ((err = hal_hashsig_sign(NULL, key, input, input_len, signature, signature_len, signature_max)) != HAL_OK)
+ return err;
+
+ return HAL_OK;
+}
+
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,
@@ -836,18 +962,26 @@ static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey,
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- hal_error_t (*signer)(uint8_t *keybuf, const size_t keybuf_len,
+ hal_error_t (*signer)(hal_pkey_slot_t *slot,
+ uint8_t *keybuf, const size_t keybuf_len,
const uint8_t * const der, const size_t der_len,
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);
+ size_t keybuf_size;
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PRIVATE:
signer = pkey_local_sign_rsa;
+ keybuf_size = hal_rsa_key_t_size;
break;
case HAL_KEY_TYPE_EC_PRIVATE:
signer = pkey_local_sign_ecdsa;
+ keybuf_size = hal_ecdsa_key_t_size;
+ break;
+ case HAL_KEY_TYPE_HASHSIG_PRIVATE:
+ signer = pkey_local_sign_hashsig;
+ keybuf_size = hal_hashsig_key_t_size;
break;
default:
return HAL_ERROR_UNSUPPORTED_KEY;
@@ -856,14 +990,13 @@ static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey,
if ((slot->flags & HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) == 0)
return HAL_ERROR_FORBIDDEN;
- 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 keybuf[keybuf_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
hal_error_t err;
if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) == HAL_OK)
- err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len,
+ err = signer(slot, keybuf, sizeof(keybuf), der, der_len, hash, input, input_len,
signature, signature_len, signature_max);
memset(keybuf, 0, sizeof(keybuf));
@@ -917,7 +1050,7 @@ static hal_error_t pkey_local_verify_rsa(uint8_t *keybuf, const size_t keybuf_le
return err;
unsigned diff = 0;
- for (int i = 0; i < signature_len; i++)
+ for (size_t i = 0; i < signature_len; i++)
diff |= expected[i] ^ received[i + sizeof(received) - sizeof(expected)];
if (diff != 0)
@@ -970,6 +1103,40 @@ 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_hashsig(uint8_t *keybuf, const size_t keybuf_len, const hal_key_type_t type,
+ const uint8_t * const der, const size_t der_len,
+ const hal_hash_handle_t hash,
+ const uint8_t * input, size_t input_len,
+ const uint8_t * const signature, const size_t signature_len)
+{
+ uint8_t digest[signature_len];
+ hal_hashsig_key_t *key = NULL;
+ hal_error_t err;
+
+ assert(signature != NULL && signature_len > 0);
+ assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0));
+
+ if ((err = hal_hashsig_public_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK)
+ return err;
+
+ if (input == NULL || input_len == 0) {
+ hal_digest_algorithm_t alg;
+
+ // ???
+ if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK ||
+ (err = hal_rpc_hash_get_digest_length(alg, &input_len)) != HAL_OK ||
+ (err = hal_rpc_hash_finalize(hash, digest, sizeof(digest))) != HAL_OK)
+ return err;
+
+ input = digest;
+ }
+
+ if ((err = hal_hashsig_verify(NULL, key, input, input_len, signature, signature_len)) != HAL_OK)
+ return err;
+
+ return HAL_OK;
+}
+
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,
@@ -985,15 +1152,22 @@ 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);
+ size_t keybuf_size;
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PRIVATE:
case HAL_KEY_TYPE_RSA_PUBLIC:
verifier = pkey_local_verify_rsa;
+ keybuf_size = hal_rsa_key_t_size;
break;
case HAL_KEY_TYPE_EC_PRIVATE:
case HAL_KEY_TYPE_EC_PUBLIC:
verifier = pkey_local_verify_ecdsa;
+ keybuf_size = hal_ecdsa_key_t_size;
+ break;
+ case HAL_KEY_TYPE_HASHSIG_PUBLIC:
+ verifier = pkey_local_verify_hashsig;
+ keybuf_size = hal_hashsig_key_t_size;
break;
default:
return HAL_ERROR_UNSUPPORTED_KEY;
@@ -1002,8 +1176,7 @@ static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey,
if ((slot->flags & HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) == 0)
return HAL_ERROR_FORBIDDEN;
- 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 keybuf[keybuf_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
hal_error_t err;
@@ -1018,7 +1191,7 @@ static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey,
return err;
}
-static inline hal_error_t match_one_keystore(const hal_ks_driver_t * const driver,
+static inline hal_error_t match_one_keystore(hal_ks_t *ks,
const hal_client_handle_t client,
const hal_session_handle_t session,
const hal_key_type_t type,
@@ -1032,21 +1205,12 @@ static inline hal_error_t match_one_keystore(const hal_ks_driver_t * const drive
const unsigned result_max,
const hal_uuid_t * const previous_uuid)
{
- hal_ks_t *ks = NULL;
hal_error_t err;
unsigned len;
- if ((err = hal_ks_open(driver, &ks)) != HAL_OK)
- return err;
-
if ((err = hal_ks_match(ks, client, session, type, curve,
mask, flags, attributes, attributes_len,
- *result, &len, result_max, previous_uuid)) != HAL_OK) {
- (void) hal_ks_close(ks);
- return err;
- }
-
- if ((err = hal_ks_close(ks)) != HAL_OK)
+ *result, &len, result_max, previous_uuid)) != HAL_OK)
return err;
*result += len;
@@ -1097,7 +1261,7 @@ static hal_error_t pkey_local_match(const hal_client_handle_t client,
case MATCH_STATE_TOKEN:
if (((mask & HAL_KEY_FLAG_TOKEN) == 0 || (mask & flags & HAL_KEY_FLAG_TOKEN) != 0) &&
- (err = match_one_keystore(hal_ks_token_driver, client, session, type, curve,
+ (err = match_one_keystore(hal_ks_token, client, session, type, curve,
mask, flags, attributes, attributes_len,
&result, result_len, result_max - *result_len, prev)) != HAL_OK)
return err;
@@ -1108,7 +1272,7 @@ static hal_error_t pkey_local_match(const hal_client_handle_t client,
case MATCH_STATE_VOLATILE:
if (((mask & HAL_KEY_FLAG_TOKEN) == 0 || (mask & flags & HAL_KEY_FLAG_TOKEN) == 0) &&
- (err = match_one_keystore(hal_ks_volatile_driver, client, session, type, curve,
+ (err = match_one_keystore(hal_ks_volatile, client, session, type, curve,
mask, flags, attributes, attributes_len,
&result, result_len, result_max - *result_len, prev)) != HAL_OK)
return err;
@@ -1133,19 +1297,12 @@ static hal_error_t pkey_local_set_attributes(const hal_pkey_handle_t 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)
+ if ((err = check_writable(slot->client, 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;
+ return hal_ks_set_attributes(ks_from_flags(slot->flags), slot, attributes, attributes_len);
}
static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t pkey,
@@ -1159,17 +1316,8 @@ static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t 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;
+ return hal_ks_get_attributes(ks_from_flags(slot->flags), slot, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len);
}
static hal_error_t pkey_local_export(const hal_pkey_handle_t pkey_handle,
@@ -1311,7 +1459,7 @@ static hal_error_t pkey_local_import(const hal_client_handle_t client,
goto fail;
}
- if ((err = hal_rsa_decrypt(NULL, rsa, data, data_len, der, data_len)) != HAL_OK)
+ if ((err = hal_rsa_decrypt(NULL, NULL, rsa, data, data_len, der, data_len)) != HAL_OK)
goto fail;
if ((err = hal_get_random(NULL, kek, sizeof(kek))) != HAL_OK)
@@ -1352,6 +1500,7 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.open = pkey_local_open,
.generate_rsa = pkey_local_generate_rsa,
.generate_ec = pkey_local_generate_ec,
+ .generate_hashsig = pkey_local_generate_hashsig,
.close = pkey_local_close,
.delete = pkey_local_delete,
.get_key_type = pkey_local_get_key_type,
diff --git a/rpc_server.c b/rpc_server.c
index a01572e..5a06e37 100644
--- a/rpc_server.c
+++ b/rpc_server.c
@@ -3,7 +3,7 @@
* ------------
* Remote procedure call server-side private API implementation.
*
- * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -35,6 +35,7 @@
#include "hal.h"
#include "hal_internal.h"
#include "xdr_internal.h"
+#include "hashsig.h"
/*
* RPC calls.
@@ -49,45 +50,34 @@
static hal_error_t get_version(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
uint32_t version;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
-
- /* call the local function */
- ret = hal_rpc_get_version(&version);
+ check(hal_rpc_get_version(&version));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, version));
-
- return ret;
+ return hal_xdr_encode_int(optr, olimit, version);
}
static hal_error_t get_random(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
uint32_t length;
- hal_error_t ret;
+ hal_error_t err;
+
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &length));
/* sanity check length */
- if (length == 0 || length > olimit - *optr - 4)
+ if (length == 0 || length > (uint32_t)(olimit - *optr - nargs(1)))
return HAL_ERROR_RPC_PACKET_OVERFLOW;
- /* call the local function */
/* get the data directly into the output buffer */
- check(hal_xdr_encode_int(optr, olimit, length));
- ret = hal_rpc_get_random(*optr, (size_t)length);
- if (ret == HAL_OK)
+ if ((err = hal_rpc_get_random(*optr + nargs(1), (size_t)length)) == HAL_OK) {
+ check(hal_xdr_encode_int(optr, olimit, length));
*optr += pad(length);
- else
- /* don't return data if error */
- *optr -= 4;
+ }
- return ret;
+ return err;
}
static hal_error_t set_pin(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -96,17 +86,13 @@ static hal_error_t set_pin(const uint8_t **iptr, const uint8_t * const ilimit,
hal_client_handle_t client;
uint32_t user;
const uint8_t *pin;
- uint32_t pin_len;
- hal_error_t ret;
+ size_t pin_len;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &user));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
-
- /* call the local function */
- ret = hal_rpc_set_pin(client, user, (const char * const)pin, pin_len);
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &pin, &pin_len));
- return ret;
+ return hal_rpc_set_pin(client, user, (const char * const)pin, pin_len);
}
static hal_error_t login(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -115,45 +101,29 @@ static hal_error_t login(const uint8_t **iptr, const uint8_t * const ilimit,
hal_client_handle_t client;
uint32_t user;
const uint8_t *pin;
- uint32_t pin_len;
- hal_error_t ret;
+ size_t pin_len;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &user));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &pin, &pin_len));
- /* call the local function */
- ret = hal_rpc_login(client, user, (const char * const)pin, pin_len);
-
- return ret;
+ return hal_rpc_login(client, user, (const char * const)pin, pin_len);
}
static hal_error_t logout(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
hal_client_handle_t client;
- hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- /* call the local function */
- ret = hal_rpc_logout(client);
-
- return ret;
+ return hal_rpc_logout(client);
}
static hal_error_t logout_all(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_error_t ret;
-
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
-
- /* call the local function */
- ret = hal_rpc_logout_all();
-
- return ret;
+ return hal_rpc_logout_all();
}
static hal_error_t is_logged_in(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -161,88 +131,69 @@ static hal_error_t is_logged_in(const uint8_t **iptr, const uint8_t * const ilim
{
hal_client_handle_t client;
uint32_t user;
- hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &user));
- /* call the local function */
- ret = hal_rpc_is_logged_in(client, user);
-
- return ret;
+ return hal_rpc_is_logged_in(client, user);
}
static hal_error_t hash_get_digest_len(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
uint32_t alg;
size_t length;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &alg));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_hash_get_digest_length(alg, &length);
+ check(hal_xdr_decode_int(iptr, ilimit, &alg));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, length));
+ check(hal_rpc_hash_get_digest_length(alg, &length));
- return ret;
+ return hal_xdr_encode_int(optr, olimit, length);
}
static hal_error_t hash_get_digest_algorithm_id(const uint8_t **iptr, const uint8_t * const ilimit,
uint8_t **optr, const uint8_t * const olimit)
{
- hal_client_handle_t client __attribute__((unused));
uint32_t alg;
size_t len;
uint32_t len_max;
- uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
+
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &alg));
check(hal_xdr_decode_int(iptr, ilimit, &len_max));
/* sanity check len_max */
- if (len_max > olimit - *optr - 4)
+ if (len_max > (uint32_t)(olimit - *optr - nargs(1)))
return HAL_ERROR_RPC_PACKET_OVERFLOW;
- /* call the local function */
/* get the data directly into the output buffer */
- *optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_hash_get_digest_algorithm_id(alg, *optr, &len, (size_t)len_max);
- if (ret == HAL_OK) {
- *optr = optr_orig;
+ if ((err = hal_rpc_hash_get_digest_algorithm_id(alg, *optr + nargs(1), &len, (size_t)len_max)) == HAL_OK) {
check(hal_xdr_encode_int(optr, olimit, len));
*optr += pad(len);
}
- else {
- /* don't return data if error */
- *optr = optr_orig;
- }
- return ret;
+
+ return err;
}
static hal_error_t hash_get_algorithm(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_hash_handle_t hash;
hal_digest_algorithm_t alg;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_hash_get_algorithm(hash, &alg);
+ check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, alg));
+ check(hal_rpc_hash_get_algorithm(hash, &alg));
- return ret;
+ return hal_xdr_encode_int(optr, olimit, alg);
}
static hal_error_t hash_initialize(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -253,67 +204,57 @@ static hal_error_t hash_initialize(const uint8_t **iptr, const uint8_t * const i
hal_hash_handle_t hash;
uint32_t alg;
const uint8_t *key;
- uint32_t key_len;
- hal_error_t ret;
+ size_t key_len;
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, &alg));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &key, &key_len));
-
- /* call the local function */
- ret = hal_rpc_hash_initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len);
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &key, &key_len));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, hash.handle));
+ check(hal_rpc_hash_initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len));
- return ret;
+ return hal_xdr_encode_int(optr, olimit, hash.handle);
}
static hal_error_t hash_update(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_hash_handle_t hash;
const uint8_t *data;
- uint32_t length;
- hal_error_t ret;
+ size_t length;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &data, &length));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_hash_update(hash, data, (size_t)length);
+ check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &data, &length));
- return ret;
+ return hal_rpc_hash_update(hash, data, (size_t)length);
}
static hal_error_t hash_finalize(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_hash_handle_t hash;
uint32_t length;
- hal_error_t ret;
+ hal_error_t err;
+
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &hash.handle));
check(hal_xdr_decode_int(iptr, ilimit, &length));
/* sanity check length */
- if (length == 0 || length > olimit - *optr - 4)
+ if (length > (uint32_t)(olimit - *optr - nargs(1)))
return HAL_ERROR_RPC_PACKET_OVERFLOW;
- /* call the local function */
/* get the data directly into the output buffer */
- check(hal_xdr_encode_int(optr, olimit, length));
- ret = hal_rpc_hash_finalize(hash, *optr, (size_t)length);
- if (ret == HAL_OK)
+ if ((err = hal_rpc_hash_finalize(hash, *optr + nargs(1), (size_t)length)) == HAL_OK) {
+ check(hal_xdr_encode_int(optr, olimit, length));
*optr += pad(length);
- else
- /* don't return data if error */
- *optr -= 4;
- return ret;
+ }
+
+ return err;
}
static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -324,28 +265,23 @@ static hal_error_t pkey_load(const uint8_t **iptr, const uint8_t * const ilimit,
hal_pkey_handle_t pkey;
hal_uuid_t name;
const uint8_t *der;
- uint32_t der_len;
+ size_t der_len;
hal_key_flags_t flags;
- hal_error_t ret;
uint8_t *optr_orig = *optr;
+ hal_error_t err;
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, &der, &der_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &der, &der_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
- ret = hal_rpc_pkey_load(client, session, &pkey, &name, der, der_len, flags);
-
- if (ret == HAL_OK)
- ret = hal_xdr_encode_int(optr, olimit, pkey.handle);
-
- if (ret == HAL_OK)
- ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid));
+ check(hal_rpc_pkey_load(client, session, &pkey, &name, der, der_len, flags));
- if (ret != HAL_OK)
+ if ((err = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
*optr = optr_orig;
- return ret;
+ return err;
}
static hal_error_t pkey_open(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -355,23 +291,18 @@ static hal_error_t pkey_open(const uint8_t **iptr, const uint8_t * const ilimit,
hal_session_handle_t session;
hal_pkey_handle_t pkey;
const uint8_t *name_ptr;
- uint32_t name_len;
- hal_error_t ret;
+ size_t name_len;
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_ptr, &name_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &name_ptr, &name_len));
if (name_len != sizeof(hal_uuid_t))
return HAL_ERROR_KEY_NAME_TOO_LONG;
- /* call the local function */
- ret = hal_rpc_pkey_open(client, session, &pkey, (const hal_uuid_t *) name_ptr);
+ check(hal_rpc_pkey_open(client, session, &pkey, (const hal_uuid_t *) name_ptr));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, pkey.handle));
-
- return ret;
+ return hal_xdr_encode_int(optr, olimit, pkey.handle);
}
static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -383,27 +314,24 @@ static hal_error_t pkey_generate_rsa(const uint8_t **iptr, const uint8_t * const
hal_uuid_t name;
uint32_t key_len;
const uint8_t *exp;
- uint32_t exp_len;
+ size_t exp_len;
hal_key_flags_t flags;
- hal_error_t ret;
+ uint8_t *optr_orig = *optr;
+ hal_error_t err;
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, &key_len));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &exp, &exp_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
- /* call the local function */
- ret = hal_rpc_pkey_generate_rsa(client, session, &pkey, &name, key_len, exp, exp_len, flags);
+ check(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;
- }
+ if ((err = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
- return ret;
+ return err;
}
static hal_error_t pkey_generate_ec(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -415,76 +343,93 @@ static hal_error_t pkey_generate_ec(const uint8_t **iptr, const uint8_t * const
hal_uuid_t name;
uint32_t curve;
hal_key_flags_t flags;
- hal_error_t ret;
+ uint8_t *optr_orig = *optr;
+ hal_error_t err;
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, &curve));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
- /* call the local function */
- ret = hal_rpc_pkey_generate_ec(client, session, &pkey, &name, curve, flags);
+ check(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;
- }
+ if ((err = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
- return ret;
+ return err;
+}
+
+static hal_error_t pkey_generate_hashsig(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;
+ hal_uuid_t name;
+ uint32_t hss_levels;
+ uint32_t lms_type;
+ uint32_t lmots_type;
+ hal_key_flags_t flags;
+ uint8_t *optr_orig = *optr;
+ hal_error_t err;
+
+ 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, &hss_levels));
+ check(hal_xdr_decode_int(iptr, ilimit, &lms_type));
+ check(hal_xdr_decode_int(iptr, ilimit, &lmots_type));
+ check(hal_xdr_decode_int(iptr, ilimit, &flags));
+
+ check(hal_rpc_pkey_generate_hashsig(client, session, &pkey, &name, hss_levels, lms_type, lmots_type, flags));
+
+ if ((err = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
+ *optr = optr_orig;
+
+ return err;
}
static hal_error_t pkey_close(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;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_pkey_close(pkey);
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- return ret;
+ return hal_rpc_pkey_close(pkey);
}
static hal_error_t pkey_delete(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;
- hal_error_t ret;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
- check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_pkey_delete(pkey);
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- return ret;
+ return hal_rpc_pkey_delete(pkey);
}
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;
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));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_pkey_get_key_type(pkey, &type);
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, type));
+ check(hal_rpc_pkey_get_key_type(pkey, &type));
- return ret;
+ return hal_xdr_encode_int(optr, olimit, type);
}
static hal_error_t pkey_get_key_curve(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -493,89 +438,71 @@ static hal_error_t pkey_get_key_curve(const uint8_t **iptr, const uint8_t * cons
hal_client_handle_t client;
hal_pkey_handle_t pkey;
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_pkey_get_key_curve(pkey, &curve);
+ check(hal_rpc_pkey_get_key_curve(pkey, &curve));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, curve));
-
- return ret;
+ return hal_xdr_encode_int(optr, olimit, curve);
}
static hal_error_t pkey_get_key_flags(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;
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, &pkey.handle));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- /* call the local function */
- ret = hal_rpc_pkey_get_key_flags(pkey, &flags);
+ check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- if (ret == HAL_OK)
- check(hal_xdr_encode_int(optr, olimit, flags));
+ check(hal_rpc_pkey_get_key_flags(pkey, &flags));
- return ret;
+ return hal_xdr_encode_int(optr, olimit, flags);
}
static hal_error_t pkey_get_public_key_len(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;
size_t len;
- check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+ /* skip over unused client argument */
+ *iptr += nargs(1);
+
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
- /* call the local function */
len = hal_rpc_pkey_get_public_key_len(pkey);
- check(hal_xdr_encode_int(optr, olimit, len));
-
- return HAL_OK;
+ return hal_xdr_encode_int(optr, olimit, len);
}
static hal_error_t pkey_get_public_key(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;
size_t len;
uint32_t len_max;
- uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
+
+ /* skip over unused client argument */
+ *iptr += nargs(1);
- 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, &len_max));
/* sanity check len_max */
- if (len_max > olimit - *optr - 4)
+ if (len_max > (uint32_t)(olimit - *optr - nargs(1)))
return HAL_ERROR_RPC_PACKET_OVERFLOW;
- /* call the local function */
/* get the data directly into the output buffer */
- *optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_pkey_get_public_key(pkey, *optr, &len, len_max);
- if (ret == HAL_OK) {
- *optr = optr_orig;
+ if ((err = hal_rpc_pkey_get_public_key(pkey, *optr + nargs(1), &len, len_max)) == HAL_OK) {
check(hal_xdr_encode_int(optr, olimit, len));
*optr += pad(len);
}
- else {
- /* don't return data if error */
- *optr = optr_orig;
- }
- return ret;
+
+ return err;
}
static hal_error_t pkey_sign(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -585,31 +512,28 @@ static hal_error_t pkey_sign(const uint8_t **iptr, const uint8_t * const ilimit,
hal_pkey_handle_t pkey;
hal_hash_handle_t hash;
const uint8_t *input;
- uint32_t input_len;
+ size_t input_len;
uint32_t sig_max;
size_t sig_len;
- uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
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, &hash.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &input, &input_len));
check(hal_xdr_decode_int(iptr, ilimit, &sig_max));
/* sanity check sig_max */
- if (sig_max > olimit - *optr - 4)
+ if (sig_max > (uint32_t)(olimit - *optr - nargs(1)))
return HAL_ERROR_RPC_PACKET_OVERFLOW;
- /* call the local function */
/* get the data directly into the output buffer */
- *optr += 4; /* reserve 4 bytes for length */
- ret = hal_rpc_pkey_sign(pkey, hash, input, input_len, *optr, &sig_len, sig_max);
- *optr = optr_orig;
- if (ret == HAL_OK) {
+ err = hal_rpc_pkey_sign(pkey, hash, input, input_len, *optr + nargs(1), &sig_len, sig_max);
+ if (err == HAL_OK) {
check(hal_xdr_encode_int(optr, olimit, sig_len));
*optr += pad(sig_len);
}
- return ret;
+
+ return err;
}
static hal_error_t pkey_verify(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -619,21 +543,17 @@ static hal_error_t pkey_verify(const uint8_t **iptr, const uint8_t * const ilimi
hal_pkey_handle_t pkey;
hal_hash_handle_t hash;
const uint8_t *input;
- uint32_t input_len;
+ size_t input_len;
const uint8_t *sig;
- uint32_t sig_len;
- hal_error_t ret;
+ size_t sig_len;
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, &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));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &input, &input_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &sig, &sig_len));
- /* call the local function */
- ret = hal_rpc_pkey_verify(pkey, hash, input, input_len, sig, sig_len);
-
- return ret;
+ return hal_rpc_pkey_verify(pkey, hash, input, input_len, sig, sig_len);
}
static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -641,11 +561,12 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit
{
hal_client_handle_t client;
hal_session_handle_t session;
- uint32_t type, curve, attributes_len, state, result_max, previous_uuid_len;
+ uint32_t type, curve, attributes_len, state, result_max;
+ size_t previous_uuid_len;
const uint8_t *previous_uuid_ptr;
hal_key_flags_t mask, flags;
uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &session.handle));
@@ -657,19 +578,19 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit
hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
- for (int i = 0; i < attributes_len; i++) {
+ for (size_t i = 0; i < attributes_len; i++) {
hal_pkey_attribute_t *a = &attributes[i];
const uint8_t *value;
- uint32_t value_len;
+ size_t value_len;
check(hal_xdr_decode_int(iptr, ilimit, &a->type));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &value, &value_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &value, &value_len));
a->value = value;
a->length = value_len;
}
check(hal_xdr_decode_int(iptr, ilimit, &state));
check(hal_xdr_decode_int(iptr, ilimit, &result_max));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &previous_uuid_ptr, &previous_uuid_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &previous_uuid_ptr, &previous_uuid_len));
if (previous_uuid_len != sizeof(hal_uuid_t))
return HAL_ERROR_KEY_NAME_TOO_LONG;
@@ -679,24 +600,21 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit
hal_uuid_t result[result_max];
unsigned result_len, ustate = state;
- ret = hal_rpc_pkey_match(client, session, type, curve, mask, flags,
- attributes, attributes_len,
- &ustate, result, &result_len, result_max,
- previous_uuid);
+ check(hal_rpc_pkey_match(client, session, type, curve, mask, flags,
+ attributes, attributes_len, &ustate, result,
+ &result_len, result_max, previous_uuid));
- if (ret == HAL_OK)
- ret = hal_xdr_encode_int(optr, olimit, ustate);
+ if ((err = hal_xdr_encode_int(optr, olimit, ustate)) == HAL_OK)
+ err = hal_xdr_encode_int(optr, olimit, result_len);
- if (ret == HAL_OK)
- ret = hal_xdr_encode_int(optr, olimit, result_len);
+ for (size_t i = 0; err == HAL_OK && i < result_len; ++i)
+ err = hal_xdr_encode_variable_opaque(optr, olimit, result[i].uuid,
+ sizeof(result[i].uuid));
- 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)
+ if (err != HAL_OK)
*optr = optr_orig;
- return ret;
+ return err;
}
static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -705,7 +623,6 @@ static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * con
hal_client_handle_t client;
hal_pkey_handle_t pkey;
uint32_t attributes_len;
- hal_error_t ret;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
@@ -713,7 +630,7 @@ static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * con
hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
- for (int i = 0; i < attributes_len; i++) {
+ for (size_t 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;
@@ -724,14 +641,14 @@ static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * con
else {
*iptr = iptr_prior_to_decoding_length;
const uint8_t *value;
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &value, &a->length));
+ size_t len;
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &value, &len));
a->value = value;
+ a->length = len;
}
}
- ret = hal_rpc_pkey_set_attributes(pkey, attributes, attributes_len);
-
- return ret;
+ return hal_rpc_pkey_set_attributes(pkey, attributes, attributes_len);
}
static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -741,7 +658,7 @@ static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * con
hal_pkey_handle_t pkey;
uint32_t attributes_len, u32;
uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
@@ -749,38 +666,36 @@ static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * con
hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
- for (int i = 0; i < attributes_len; i++)
+ for (size_t 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)
+ if (nargs(1 + 2 * attributes_len) + attributes_buffer_len > (uint32_t)(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);
-
- if (ret == HAL_OK) {
- 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);
+ check(hal_rpc_pkey_get_attributes(pkey, attributes, attributes_len,
+ attributes_buffer, attributes_buffer_len));
+
+ if ((err = hal_xdr_encode_int(optr, olimit, attributes_len)) == HAL_OK) {
+ for (size_t i = 0; err == HAL_OK && i < attributes_len; i++) {
+ if ((err = hal_xdr_encode_int(optr, olimit, attributes[i].type)) == HAL_OK) {
+ if (attributes_buffer_len == 0)
+ err = hal_xdr_encode_int(optr, olimit, attributes[i].length);
+ else
+ err = hal_xdr_encode_variable_opaque(optr, olimit, attributes[i].value, attributes[i].length);
+ }
}
}
- if (ret != HAL_OK)
+ if (err != HAL_OK)
*optr = optr_orig;
- return ret;
+ return err;
}
static hal_error_t pkey_export(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -792,7 +707,7 @@ static hal_error_t pkey_export(const uint8_t **iptr, const uint8_t * const ilimi
size_t pkcs8_len, kek_len;
uint32_t pkcs8_max, kek_max;
uint8_t *optr_orig = *optr;
- hal_error_t ret;
+ hal_error_t err;
check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
@@ -802,18 +717,13 @@ static hal_error_t pkey_export(const uint8_t **iptr, const uint8_t * const ilimi
uint8_t pkcs8[pkcs8_max], kek[kek_max];
- ret = hal_rpc_pkey_export(pkey, kekek, pkcs8, &pkcs8_len, sizeof(pkcs8), kek, &kek_len, sizeof(kek));
+ check(hal_rpc_pkey_export(pkey, kekek, pkcs8, &pkcs8_len, sizeof(pkcs8), kek, &kek_len, sizeof(kek)));
- if (ret == HAL_OK)
- ret = hal_xdr_encode_buffer(optr, olimit, pkcs8, pkcs8_len);
-
- if (ret == HAL_OK)
- ret = hal_xdr_encode_buffer(optr, olimit, kek, kek_len);
-
- if (ret != HAL_OK)
+ if ((err = hal_xdr_encode_variable_opaque(optr, olimit, pkcs8, pkcs8_len)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, kek, kek_len)) != HAL_OK)
*optr = optr_orig;
- return ret;
+ return err;
}
static hal_error_t pkey_import(const uint8_t **iptr, const uint8_t * const ilimit,
@@ -825,30 +735,25 @@ static hal_error_t pkey_import(const uint8_t **iptr, const uint8_t * const ilimi
hal_pkey_handle_t kekek;
hal_uuid_t name;
const uint8_t *pkcs8, *kek;
- uint32_t pkcs8_len, kek_len;
+ size_t pkcs8_len, kek_len;
uint8_t *optr_orig = *optr;
hal_key_flags_t flags;
- hal_error_t ret;
+ hal_error_t err;
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, &kekek.handle));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pkcs8, &pkcs8_len));
- check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &kek, &kek_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &pkcs8, &pkcs8_len));
+ check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &kek, &kek_len));
check(hal_xdr_decode_int(iptr, ilimit, &flags));
- ret = hal_rpc_pkey_import(client, session, &pkey, &name, kekek, pkcs8, pkcs8_len, kek, kek_len, flags);
-
- if (ret == HAL_OK)
- ret = hal_xdr_encode_int(optr, olimit, pkey.handle);
+ check(hal_rpc_pkey_import(client, session, &pkey, &name, kekek, pkcs8, pkcs8_len, kek, kek_len, flags));
- if (ret == HAL_OK)
- ret = hal_xdr_encode_buffer(optr, olimit, name.uuid, sizeof(name.uuid));
-
- if (ret != HAL_OK)
+ if ((err = hal_xdr_encode_int(optr, olimit, pkey.handle)) != HAL_OK ||
+ (err = hal_xdr_encode_variable_opaque(optr, olimit, name.uuid, sizeof(name.uuid))) != HAL_OK)
*optr = optr_orig;
- return ret;
+ return err;
}
@@ -857,17 +762,16 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
{
const uint8_t * iptr = ibuf;
const uint8_t * const ilimit = ibuf + ilen;
- uint8_t * optr = obuf + 12; /* reserve space for opcode, client, and response code */
+ uint8_t * optr = obuf + nargs(3); /* reserve space for opcode, client, and response code */
const uint8_t * const olimit = obuf + *olen;
uint32_t rpc_func_num;
uint32_t client_handle;
- hal_error_t ret;
+ hal_error_t err;
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));
+ check(hal_xdr_decode_int_peek(&iptr, ilimit, &client_handle));
switch (rpc_func_num) {
case RPC_FUNC_GET_VERSION:
@@ -921,6 +825,9 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
case RPC_FUNC_PKEY_GENERATE_EC:
handler = pkey_generate_ec;
break;
+ case RPC_FUNC_PKEY_GENERATE_HASHSIG:
+ handler = pkey_generate_hashsig;
+ break;
case RPC_FUNC_PKEY_CLOSE:
handler = pkey_close;
break;
@@ -966,16 +873,16 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
}
if (handler)
- ret = handler(&iptr, ilimit, &optr, olimit);
+ err = handler(&iptr, ilimit, &optr, olimit);
else
- ret = HAL_ERROR_RPC_BAD_FUNCTION;
+ err = HAL_ERROR_RPC_BAD_FUNCTION;
/* Encode opcode, client ID, and response code at the beginning of the payload */
*olen = optr - obuf;
optr = obuf;
check(hal_xdr_encode_int(&optr, olimit, rpc_func_num));
check(hal_xdr_encode_int(&optr, olimit, client_handle));
- check(hal_xdr_encode_int(&optr, olimit, ret));
+ check(hal_xdr_encode_int(&optr, olimit, err));
return HAL_OK;
}
@@ -993,9 +900,9 @@ hal_error_t hal_rpc_server_init(void)
{
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)
+ if ((err = hal_ks_init(hal_ks_volatile, 1)) != HAL_OK ||
+ (err = hal_ks_init(hal_ks_token, 1)) != HAL_OK ||
+ (err = hal_rpc_server_transport_init()) != HAL_OK)
return err;
return HAL_OK;
@@ -1005,9 +912,7 @@ hal_error_t hal_rpc_server_close(void)
{
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)
+ if ((err = hal_rpc_server_transport_close()) != HAL_OK)
return err;
return HAL_OK;
diff --git a/rsa.c b/rsa.c
index 3cea42c..01d8290 100644
--- a/rsa.c
+++ b/rsa.c
@@ -70,7 +70,6 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
-#include <assert.h>
#include "hal.h"
#include "hal_internal.h"
@@ -78,12 +77,15 @@
#include "asn1_internal.h"
/*
- * Whether to use ModExp core. It works, but at the moment it's so
- * slow that a full test run can take more than an hour.
+ * Whether to use ModExp core. It works, but it's painfully slow.
*/
-#ifndef HAL_RSA_USE_MODEXP
-#define HAL_RSA_USE_MODEXP 1
+#ifndef HAL_RSA_SIGN_USE_MODEXP
+#define HAL_RSA_SIGN_USE_MODEXP 1
+#endif
+
+#ifndef HAL_RSA_KEYGEN_USE_MODEXP
+#define HAL_RSA_KEYGEN_USE_MODEXP 0
#endif
#if defined(RPC_CLIENT) && RPC_CLIENT != RPC_CLIENT_LOCAL
@@ -91,6 +93,15 @@
#endif
/*
+ * How big to make the buffers for the modulus coefficient and
+ * Montgomery factor. This will almost certainly want tuning.
+ */
+
+#ifndef HAL_RSA_MAX_OPERAND_LENGTH
+#define HAL_RSA_MAX_OPERAND_LENGTH MODEXPA7_OPERAND_BYTES
+#endif
+
+/*
* Whether we want debug output.
*/
@@ -120,7 +131,7 @@ void hal_rsa_set_blinding(const int onoff)
*/
struct hal_rsa_key {
- hal_key_type_t type; /* What kind of key this is */
+ hal_key_type_t type; /* What kind of key this is */
fp_int n[1]; /* The modulus */
fp_int e[1]; /* Public exponent */
fp_int d[1]; /* Private exponent */
@@ -129,8 +140,17 @@ struct hal_rsa_key {
fp_int u[1]; /* 1/q mod p */
fp_int dP[1]; /* d mod (p - 1) */
fp_int dQ[1]; /* d mod (q - 1) */
+ unsigned flags; /* Internal key flags */
+ uint8_t /* ModExpA7 speedup factors */
+ nC[HAL_RSA_MAX_OPERAND_LENGTH], nF[HAL_RSA_MAX_OPERAND_LENGTH],
+ pC[HAL_RSA_MAX_OPERAND_LENGTH/2], pF[HAL_RSA_MAX_OPERAND_LENGTH/2],
+ qC[HAL_RSA_MAX_OPERAND_LENGTH/2], qF[HAL_RSA_MAX_OPERAND_LENGTH/2];
};
+#define RSA_FLAG_NEEDS_SAVING (1 << 0)
+#define RSA_FLAG_PRECALC_N_DONE (1 << 1)
+#define RSA_FLAG_PRECALC_PQ_DONE (1 << 2)
+
const size_t hal_rsa_key_t_size = sizeof(hal_rsa_key_t);
/*
@@ -155,7 +175,7 @@ const size_t hal_rsa_key_t_size = sizeof(hal_rsa_key_t);
case FP_OKAY: break; \
case FP_VAL: lose(HAL_ERROR_BAD_ARGUMENTS); \
case FP_MEM: lose(HAL_ERROR_ALLOCATION_FAILURE); \
- default: lose(HAL_ERROR_IMPOSSIBLE); \
+ default: lose(HAL_ERROR_IMPOSSIBLE); \
} \
} while (0)
@@ -168,7 +188,8 @@ static hal_error_t unpack_fp(const fp_int * const bn, uint8_t *buffer, const siz
{
hal_error_t err = HAL_OK;
- assert(bn != NULL && buffer != NULL);
+ if (bn == NULL || buffer == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
const size_t bytes = fp_unsigned_bin_size(unconst_fp_int(bn));
@@ -182,47 +203,50 @@ static hal_error_t unpack_fp(const fp_int * const bn, uint8_t *buffer, const siz
return err;
}
-#if HAL_RSA_USE_MODEXP
+#if HAL_RSA_SIGN_USE_MODEXP
/*
* Unwrap bignums into byte arrays, feed them into hal_modexp(), and
* wrap result back up as a bignum.
*/
-static hal_error_t modexp(const hal_core_t *core,
- const fp_int * msg,
+static hal_error_t modexp(hal_core_t *core,
+ const int precalc,
+ const fp_int * const msg,
const fp_int * const exp,
const fp_int * const mod,
- fp_int *res)
+ fp_int *res,
+ uint8_t *coeff, const size_t coeff_len,
+ uint8_t *mont, const size_t mont_len)
{
hal_error_t err = HAL_OK;
- assert(msg != NULL && exp != NULL && mod != NULL && res != NULL);
-
- fp_int reduced_msg[1] = INIT_FP_INT;
-
- if (fp_cmp_mag(unconst_fp_int(msg), unconst_fp_int(mod)) != FP_LT) {
- fp_init(reduced_msg);
- fp_mod(unconst_fp_int(msg), unconst_fp_int(mod), reduced_msg);
- msg = reduced_msg;
- }
+ if (msg == NULL || exp == NULL || mod == NULL || res == NULL || coeff == NULL || mont == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+ const size_t msg_len = (fp_unsigned_bin_size(unconst_fp_int(msg)) + 3) & ~3;
const size_t exp_len = (fp_unsigned_bin_size(unconst_fp_int(exp)) + 3) & ~3;
const size_t mod_len = (fp_unsigned_bin_size(unconst_fp_int(mod)) + 3) & ~3;
- uint8_t msgbuf[mod_len];
+ uint8_t msgbuf[msg_len];
uint8_t expbuf[exp_len];
uint8_t modbuf[mod_len];
uint8_t resbuf[mod_len];
+ hal_modexp_arg_t args = {
+ .core = core,
+ .msg = msgbuf, .msg_len = sizeof(msgbuf),
+ .exp = expbuf, .exp_len = sizeof(expbuf),
+ .mod = modbuf, .mod_len = sizeof(modbuf),
+ .result = resbuf, .result_len = sizeof(resbuf),
+ .coeff = coeff, .coeff_len = coeff_len,
+ .mont = mont, .mont_len = mont_len
+ };
+
if ((err = unpack_fp(msg, msgbuf, sizeof(msgbuf))) != HAL_OK ||
(err = unpack_fp(exp, expbuf, sizeof(expbuf))) != HAL_OK ||
(err = unpack_fp(mod, modbuf, sizeof(modbuf))) != HAL_OK ||
- (err = hal_modexp(core,
- msgbuf, sizeof(msgbuf),
- expbuf, sizeof(expbuf),
- modbuf, sizeof(modbuf),
- resbuf, sizeof(resbuf))) != HAL_OK)
+ (err = hal_modexp(precalc, &args)) != HAL_OK)
goto fail;
fp_read_unsigned_bin(res, resbuf, sizeof(resbuf));
@@ -231,37 +255,105 @@ static hal_error_t modexp(const hal_core_t *core,
memset(msgbuf, 0, sizeof(msgbuf));
memset(expbuf, 0, sizeof(expbuf));
memset(modbuf, 0, sizeof(modbuf));
+ memset(resbuf, 0, sizeof(resbuf));
+ memset(&args, 0, sizeof(args));
return err;
}
-/*
- * Wrapper to let us export our modexp function as a replacement for
- * TFM's, to avoid dragging in all of the TFM montgomery code when we
- * use TFM's Miller-Rabin test code.
- *
- * This code is here rather than in a separate module because of the
- * error handling: TFM's error codes aren't really capable of
- * expressing all the things that could go wrong here.
- */
-
-int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+static hal_error_t modexp2(const int precalc,
+ const fp_int * const msg,
+ hal_core_t *core1,
+ const fp_int * const exp1,
+ const fp_int * const mod1,
+ fp_int * res1,
+ uint8_t *coeff1, const size_t coeff1_len,
+ uint8_t *mont1, const size_t mont1_len,
+ hal_core_t *core2,
+ const fp_int * const exp2,
+ const fp_int * const mod2,
+ fp_int * res2,
+ uint8_t *coeff2, const size_t coeff2_len,
+ uint8_t *mont2, const size_t mont2_len)
{
- return modexp(NULL, a, b, c, d) == HAL_OK ? FP_OKAY : FP_VAL;
+ hal_error_t err = HAL_OK;
+
+ if (msg == NULL ||
+ exp1 == NULL || mod1 == NULL || res1 == NULL || coeff1 == NULL || mont1 == NULL ||
+ exp2 == NULL || mod2 == NULL || res2 == NULL || coeff2 == NULL || mont2 == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+
+ const size_t msg_len = (fp_unsigned_bin_size(unconst_fp_int(msg)) + 3) & ~3;
+ const size_t exp1_len = (fp_unsigned_bin_size(unconst_fp_int(exp1)) + 3) & ~3;
+ const size_t mod1_len = (fp_unsigned_bin_size(unconst_fp_int(mod1)) + 3) & ~3;
+ const size_t exp2_len = (fp_unsigned_bin_size(unconst_fp_int(exp2)) + 3) & ~3;
+ const size_t mod2_len = (fp_unsigned_bin_size(unconst_fp_int(mod2)) + 3) & ~3;
+
+ uint8_t msgbuf[msg_len];
+ uint8_t expbuf1[exp1_len], modbuf1[mod1_len], resbuf1[mod1_len];
+ uint8_t expbuf2[exp2_len], modbuf2[mod2_len], resbuf2[mod2_len];
+
+ hal_modexp_arg_t args1 = {
+ .core = core1,
+ .msg = msgbuf, .msg_len = sizeof(msgbuf),
+ .exp = expbuf1, .exp_len = sizeof(expbuf1),
+ .mod = modbuf1, .mod_len = sizeof(modbuf1),
+ .result = resbuf1, .result_len = sizeof(resbuf1),
+ .coeff = coeff1, .coeff_len = coeff1_len,
+ .mont = mont1, .mont_len = mont1_len
+ };
+
+ hal_modexp_arg_t args2 = {
+ .core = core2,
+ .msg = msgbuf, .msg_len = sizeof(msgbuf),
+ .exp = expbuf2, .exp_len = sizeof(expbuf2),
+ .mod = modbuf2, .mod_len = sizeof(modbuf2),
+ .result = resbuf2, .result_len = sizeof(resbuf2),
+ .coeff = coeff2, .coeff_len = coeff2_len,
+ .mont = mont2, .mont_len = mont2_len
+ };
+
+ if ((err = unpack_fp(msg, msgbuf, sizeof(msgbuf))) != HAL_OK ||
+ (err = unpack_fp(exp1, expbuf1, sizeof(expbuf1))) != HAL_OK ||
+ (err = unpack_fp(mod1, modbuf1, sizeof(modbuf1))) != HAL_OK ||
+ (err = unpack_fp(exp2, expbuf2, sizeof(expbuf2))) != HAL_OK ||
+ (err = unpack_fp(mod2, modbuf2, sizeof(modbuf2))) != HAL_OK ||
+ (err = hal_modexp2(precalc, &args1, &args2)) != HAL_OK)
+ goto fail;
+
+ fp_read_unsigned_bin(res1, resbuf1, sizeof(resbuf1));
+ fp_read_unsigned_bin(res2, resbuf2, sizeof(resbuf2));
+
+ fail:
+ memset(msgbuf, 0, sizeof(msgbuf));
+ memset(expbuf1, 0, sizeof(expbuf1));
+ memset(modbuf1, 0, sizeof(modbuf1));
+ memset(resbuf1, 0, sizeof(resbuf1));
+ memset(&args1, 0, sizeof(args1));
+ memset(expbuf2, 0, sizeof(expbuf2));
+ memset(modbuf2, 0, sizeof(modbuf2));
+ memset(resbuf2, 0, sizeof(resbuf2));
+ memset(&args2, 0, sizeof(args2));
+ return err;
}
-#else /* HAL_RSA_USE_MODEXP */
+#else /* HAL_RSA_SIGN_USE_MODEXP */
/*
- * Workaround to let us use TFM's software implementation of modular
- * exponentiation when we want to test other things and don't want to
- * wait for the slow FPGA implementation.
+ * Use libtfm's software implementation of modular exponentiation.
+ * Now that the ModExpA7 core performs about as well as the software
+ * implementation, there's probably no need to use this, but we're
+ * still tuning things, so leave the hook here for now.
*/
static hal_error_t modexp(const hal_core_t *core, /* ignored */
+ const int precalc, /* ignored */
const fp_int * const msg,
const fp_int * const exp,
const fp_int * const mod,
- fp_int *res)
+ fp_int *res,
+ uint8_t *coeff, const size_t coeff_len, /* ignored */
+ uint8_t *mont, const size_t mont_len) /* ignored */
+
{
hal_error_t err = HAL_OK;
FP_CHECK(fp_exptmod(unconst_fp_int(msg), unconst_fp_int(exp), unconst_fp_int(mod), res));
@@ -269,7 +361,58 @@ static hal_error_t modexp(const hal_core_t *core, /* ignored */
return err;
}
-#endif /* HAL_RSA_USE_MODEXP */
+static hal_error_t modexp2(const int precalc, /* ignored */
+ const fp_int * const msg,
+ hal_core_t *core1, /* ignored */
+ const fp_int * const exp1,
+ const fp_int * const mod1,
+ fp_int * res1,
+ uint8_t *coeff1, const size_t coeff1_len, /* ignored */
+ uint8_t *mont1, const size_t mont1_len, /* ignored */
+ hal_core_t *core2, /* ignored */
+ const fp_int * const exp2,
+ const fp_int * const mod2,
+ fp_int * res2,
+ uint8_t *coeff2, const size_t coeff2_len, /* ignored */
+ uint8_t *mont2, const size_t mont2_len) /* ignored */
+{
+ hal_error_t err = HAL_OK;
+ FP_CHECK(fp_exptmod(unconst_fp_int(msg), unconst_fp_int(exp1), unconst_fp_int(mod1), res1));
+ FP_CHECK(fp_exptmod(unconst_fp_int(msg), unconst_fp_int(exp2), unconst_fp_int(mod2), res2));
+ fail:
+ return err;
+}
+
+#endif /* HAL_RSA_SIGN_USE_MODEXP */
+
+/*
+ * Wrapper to let us export our modexp function as a replacement for
+ * libtfm's when running libtfm's Miller-Rabin test code.
+ *
+ * At the moment, the libtfm software implementation performs
+ * disproportionately better than our core does for the specific case
+ * of Miller-Rabin tests, for reasons we don't really understand.
+ * So there's not much point in enabling this, except as a test to
+ * confirm this behavior.
+ *
+ * This code is here rather than in a separate module because of the
+ * error handling: libtfm's error codes aren't really capable of
+ * expressing all the things that could go wrong here.
+ */
+
+#if HAL_RSA_SIGN_USE_MODEXP && HAL_RSA_KEYGEN_USE_MODEXP
+
+int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+ const size_t len = (fp_unsigned_bin_size(unconst_fp_int(b)) + 3) & ~3;
+ uint8_t C[len], F[len];
+ const hal_error_t err = modexp(NULL, 0, a, b, c, d, C, sizeof(C), F, sizeof(F));
+ memset(C, 0, sizeof(C));
+ memset(F, 0, sizeof(F));
+ return err == HAL_OK ? FP_OKAY : FP_VAL;
+}
+
+#endif /* HAL_RSA_SIGN_USE_MODEXP && HAL_RSA_KEYGEN_USE_MODEXP */
/*
* Create blinding factors. There are various schemes for amortizing
@@ -277,10 +420,12 @@ static hal_error_t modexp(const hal_core_t *core, /* ignored */
* try. Come back to this if it looks like a bottleneck.
*/
-static hal_error_t create_blinding_factors(const hal_core_t *core, const hal_rsa_key_t * const key, fp_int *bf, fp_int *ubf)
+static hal_error_t create_blinding_factors(hal_core_t *core, hal_rsa_key_t *key, fp_int *bf, fp_int *ubf)
{
- assert(key != NULL && bf != NULL && ubf != NULL);
+ if (key == NULL || bf == NULL || ubf == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+ const int precalc = !(key->flags & RSA_FLAG_PRECALC_N_DONE);
uint8_t rnd[fp_unsigned_bin_size(unconst_fp_int(key->n))];
hal_error_t err = HAL_OK;
@@ -291,9 +436,13 @@ static hal_error_t create_blinding_factors(const hal_core_t *core, const hal_rsa
fp_read_unsigned_bin(bf, rnd, sizeof(rnd));
fp_copy(bf, ubf);
- if ((err = modexp(core, bf, key->e, key->n, bf)) != HAL_OK)
+ if ((err = modexp(core, precalc, bf, key->e, key->n, bf,
+ key->nC, sizeof(key->nC), key->nF, sizeof(key->nF))) != HAL_OK)
goto fail;
+ if (precalc)
+ key->flags |= RSA_FLAG_PRECALC_N_DONE | RSA_FLAG_NEEDS_SAVING;
+
FP_CHECK(fp_invmod(ubf, unconst_fp_int(key->n), ubf));
fail:
@@ -305,10 +454,12 @@ static hal_error_t create_blinding_factors(const hal_core_t *core, const hal_rsa
* RSA decryption via Chinese Remainder Theorem (Garner's formula).
*/
-static hal_error_t rsa_crt(const hal_core_t *core, const hal_rsa_key_t * const key, fp_int *msg, fp_int *sig)
+static hal_error_t rsa_crt(hal_core_t *core1, hal_core_t *core2, hal_rsa_key_t *key, fp_int *msg, fp_int *sig)
{
- assert(key != NULL && msg != NULL && sig != NULL);
+ if (key == NULL || msg == NULL || sig == NULL)
+ return HAL_ERROR_IMPOSSIBLE;
+ const int precalc = !(key->flags & RSA_FLAG_PRECALC_PQ_DONE);
hal_error_t err = HAL_OK;
fp_int t[1] = INIT_FP_INT;
fp_int m1[1] = INIT_FP_INT;
@@ -320,7 +471,7 @@ static hal_error_t rsa_crt(const hal_core_t *core, const hal_rsa_key_t * const k
* Handle blinding if requested.
*/
if (blinding) {
- if ((err = create_blinding_factors(core, key, bf, ubf)) != HAL_OK)
+ if ((err = create_blinding_factors(core1, key, bf, ubf)) != HAL_OK)
goto fail;
FP_CHECK(fp_mulmod(msg, bf, unconst_fp_int(key->n), msg));
}
@@ -329,10 +480,14 @@ static hal_error_t rsa_crt(const hal_core_t *core, const hal_rsa_key_t * const k
* m1 = msg ** dP mod p
* m2 = msg ** dQ mod q
*/
- if ((err = modexp(core, msg, key->dP, key->p, m1)) != HAL_OK ||
- (err = modexp(core, msg, key->dQ, key->q, m2)) != HAL_OK)
+ if ((err = modexp2(precalc, msg,
+ core1, key->dP, key->p, m1, key->pC, sizeof(key->pC), key->pF, sizeof(key->pF),
+ core2, key->dQ, key->q, m2, key->qC, sizeof(key->qC), key->qF, sizeof(key->qF))) != HAL_OK)
goto fail;
+ if (precalc)
+ key->flags |= RSA_FLAG_PRECALC_PQ_DONE | RSA_FLAG_NEEDS_SAVING;
+
/*
* t = m1 - m2.
*/
@@ -376,8 +531,8 @@ static hal_error_t rsa_crt(const hal_core_t *core, const hal_rsa_key_t * const k
* to the caller.
*/
-hal_error_t hal_rsa_encrypt(const hal_core_t *core,
- const hal_rsa_key_t * const key,
+hal_error_t hal_rsa_encrypt(hal_core_t *core,
+ hal_rsa_key_t *key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len)
{
@@ -386,23 +541,29 @@ hal_error_t hal_rsa_encrypt(const hal_core_t *core,
if (key == NULL || input == NULL || output == NULL || input_len > output_len)
return HAL_ERROR_BAD_ARGUMENTS;
+ const int precalc = !(key->flags & RSA_FLAG_PRECALC_N_DONE);
fp_int i[1] = INIT_FP_INT;
fp_int o[1] = INIT_FP_INT;
fp_read_unsigned_bin(i, unconst_uint8_t(input), input_len);
- if ((err = modexp(core, i, key->e, key->n, o)) != HAL_OK ||
- (err = unpack_fp(o, output, output_len)) != HAL_OK)
- goto fail;
+ err = modexp(core, precalc, i, key->e, key->n, o,
+ key->nC, sizeof(key->nC), key->nF, sizeof(key->nF));
+
+ if (err == HAL_OK && precalc)
+ key->flags |= RSA_FLAG_PRECALC_N_DONE | RSA_FLAG_NEEDS_SAVING;
+
+ if (err == HAL_OK)
+ err = unpack_fp(o, output, output_len);
- fail:
fp_zero(i);
fp_zero(o);
return err;
}
-hal_error_t hal_rsa_decrypt(const hal_core_t *core,
- const hal_rsa_key_t * const key,
+hal_error_t hal_rsa_decrypt(hal_core_t *core1,
+ hal_core_t *core2,
+ hal_rsa_key_t *key,
const uint8_t * const input, const size_t input_len,
uint8_t * output, const size_t output_len)
{
@@ -421,10 +582,17 @@ hal_error_t hal_rsa_decrypt(const hal_core_t *core,
* just do brute force ModExp.
*/
- if (fp_iszero(key->p) || fp_iszero(key->q) || fp_iszero(key->u) || fp_iszero(key->dP) || fp_iszero(key->dQ))
- err = modexp(core, i, key->d, key->n, o);
- else
- err = rsa_crt(core, key, i, o);
+ if (!fp_iszero(key->p) && !fp_iszero(key->q) && !fp_iszero(key->u) &&
+ !fp_iszero(key->dP) && !fp_iszero(key->dQ))
+ err = rsa_crt(core1, core2, key, i, o);
+
+ else {
+ const int precalc = !(key->flags & RSA_FLAG_PRECALC_N_DONE);
+ err = modexp(core1, precalc, i, key->d, key->n, o, key->nC, sizeof(key->nC),
+ key->nF, sizeof(key->nF));
+ if (err == HAL_OK && precalc)
+ key->flags |= RSA_FLAG_PRECALC_N_DONE | RSA_FLAG_NEEDS_SAVING;
+ }
if (err != HAL_OK || (err = unpack_fp(o, output, output_len)) != HAL_OK)
goto fail;
@@ -583,29 +751,120 @@ hal_error_t hal_rsa_key_get_public_exponent(const hal_rsa_key_t * const key,
/*
* Generate a prime factor for an RSA keypair.
*
- * Get random bytes, munge a few bits, and stuff into a bignum. Keep
- * doing this until we find a result that's (probably) prime and for
- * which result - 1 is relatively prime with respect to e.
+ * Get random bytes, munge a few bits, and stuff into a bignum to
+ * construct our initial candidate.
+ *
+ * Initialize table of remainders when dividing candidate by each
+ * entry in corresponding table of small primes. We'd have to perform
+ * these tests in any case for any succesful candidate, and doing it
+ * up front lets us amortize the cost over the entire search, so we do
+ * this unconditionally before entering the search loop.
+ *
+ * If all of the remainders were non-zero, run the requisite number of
+ * Miller-Rabin tests using the first few entries from that same table
+ * of small primes as the test values. If we get past Miller-Rabin,
+ * the candidate is (probably) prime, to a confidence level which we
+ * can tune by adjusting the number of Miller-Rabin tests.
+ *
+ * For RSA, we also need (result - 1) to be relatively prime with
+ * respect to the public exponent. If a (probable) prime passes that
+ * test, we have a winner.
+ *
+ * If any of the above tests failed, we increment the candidate and
+ * all remainders by two, then loop back to the remainder test. This
+ * is where the table pays off: incrementing remainders is really
+ * cheap, and since most composite numbers fail the small primes test,
+ * making that cheap makes the whole loop run significantly faster.
+ *
+ * General approach suggested by HAC note 4.51. Range of small prime
+ * table and default number of Miller-Rabin tests suggested by Schneier.
*/
+#ifndef HAL_RSA_MILLER_RABIN_TESTS
+#define HAL_RSA_MILLER_RABIN_TESTS (5)
+#endif
+
+static const uint16_t small_prime[] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
+ 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277,
+ 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
+ 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
+ 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521,
+ 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
+ 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683,
+ 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773,
+ 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
+ 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967,
+ 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039,
+ 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109,
+ 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
+ 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
+ 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367,
+ 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523,
+ 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601,
+ 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669,
+ 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759,
+ 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867,
+ 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
+ 1951, 1973, 1979, 1987, 1993, 1997, 1999
+};
+
static hal_error_t find_prime(const unsigned prime_length,
const fp_int * const e,
fp_int *result)
{
+ uint16_t remainder[sizeof(small_prime)/sizeof(*small_prime)];
uint8_t buffer[prime_length];
- hal_error_t err;
fp_int t[1] = INIT_FP_INT;
+ hal_error_t err;
- do {
- if ((err = hal_get_random(NULL, buffer, sizeof(buffer))) != HAL_OK)
- return err;
- buffer[0 ] |= 0xc0;
- buffer[sizeof(buffer) - 1] |= 0x01;
- fp_read_unsigned_bin(result, buffer, sizeof(buffer));
+ if ((err = hal_get_random(NULL, buffer, sizeof(buffer))) != HAL_OK)
+ return err;
+
+ buffer[0] &= ~0x01; /* Headroom for search */
+ buffer[0] |= 0xc0; /* Result large enough */
+ buffer[sizeof(buffer) - 1] |= 0x01; /* Candidates are odd */
+
+ fp_read_unsigned_bin(result, buffer, sizeof(buffer));
+ memset(buffer, 0, sizeof(buffer));
+
+ for (size_t i = 0; i < sizeof(small_prime)/sizeof(*small_prime); i++) {
+ fp_digit d;
+ fp_mod_d(result, small_prime[i], &d);
+ remainder[i] = d;
+ }
+
+ for (;;) {
+ int possible = 1;
+
+ for (size_t i = 0; i < sizeof(small_prime)/sizeof(*small_prime); i++)
+ possible &= remainder[i] != 0;
- } while (!fp_isprime(result) ||
- (fp_sub_d(result, 1, t), fp_gcd(t, unconst_fp_int(e), t), fp_cmp_d(t, 1) != FP_EQ));
+ for (size_t i = 0; possible && i < HAL_RSA_MILLER_RABIN_TESTS; i++) {
+ fp_set(t, small_prime[i]);
+ fp_prime_miller_rabin(result, t, &possible);
+ }
+ if (possible) {
+ fp_sub_d(result, 1, t);
+ fp_gcd(t, unconst_fp_int(e), t);
+ possible = fp_cmp_d(t, 1) == FP_EQ;
+ }
+
+ if (possible)
+ break;
+
+ fp_add_d(result, 2, result);
+
+ for (size_t i = 0; i < sizeof(small_prime)/sizeof(*small_prime); i++)
+ if ((remainder[i] += 2) >= small_prime[i])
+ remainder[i] -= small_prime[i];
+ }
+
+ memset(remainder, 0, sizeof(remainder));
fp_zero(t);
return HAL_OK;
}
@@ -614,7 +873,7 @@ static hal_error_t find_prime(const unsigned prime_length,
* Generate a new RSA keypair.
*/
-hal_error_t hal_rsa_key_gen(const hal_core_t *core,
+hal_error_t hal_rsa_key_gen(hal_core_t *core,
hal_rsa_key_t **key_,
void *keybuf, const size_t keybuf_len,
const unsigned key_length,
@@ -659,6 +918,8 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core,
FP_CHECK(fp_mod(key->d, q_1, key->dQ)); /* dQ = d % (q-1) */
FP_CHECK(fp_invmod(key->q, key->p, key->u)); /* u = (1/q) % p */
+ key->flags |= RSA_FLAG_NEEDS_SAVING;
+
*key_ = key;
/* Fall through to cleanup */
@@ -672,10 +933,26 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core,
}
/*
+ * Whether a key contains new data that need saving (newly generated
+ * key, updated speedup components, whatever).
+ */
+
+int hal_rsa_key_needs_saving(const hal_rsa_key_t * const key)
+{
+ return key != NULL && (key->flags & RSA_FLAG_NEEDS_SAVING);
+}
+
+/*
* Just enough ASN.1 to read and write PKCS #1.5 RSAPrivateKey syntax
* (RFC 2313 section 7.2) wrapped in a PKCS #8 PrivateKeyInfo (RFC 5208).
*
* RSAPrivateKey fields in the required order.
+ *
+ * The "extra" fields are additional key components specific to the
+ * systolic modexpa7 core. We represent these in ASN.1 as OPTIONAL
+ * fields using IMPLICIT PRIVATE tags, since this is neither
+ * standardized nor meaningful to anybody else. Underlying encoding
+ * is INTEGER or OCTET STRING (currently the latter).
*/
#define RSAPrivateKey_fields \
@@ -689,8 +966,17 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core,
_(key->dQ); \
_(key->u);
-hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key,
- uint8_t *der, size_t *der_len, const size_t der_max)
+#define RSAPrivateKey_extra_fields \
+ _(ASN1_PRIVATE + 0, nC, RSA_FLAG_PRECALC_N_DONE); \
+ _(ASN1_PRIVATE + 1, nF, RSA_FLAG_PRECALC_N_DONE); \
+ _(ASN1_PRIVATE + 2, pC, RSA_FLAG_PRECALC_PQ_DONE); \
+ _(ASN1_PRIVATE + 3, pF, RSA_FLAG_PRECALC_PQ_DONE); \
+ _(ASN1_PRIVATE + 4, qC, RSA_FLAG_PRECALC_PQ_DONE); \
+ _(ASN1_PRIVATE + 5, qF, RSA_FLAG_PRECALC_PQ_DONE);
+
+hal_error_t hal_rsa_private_key_to_der_internal(const hal_rsa_key_t * const key,
+ const int include_extra,
+ uint8_t *der, size_t *der_len, const size_t der_max)
{
hal_error_t err = HAL_OK;
@@ -705,10 +991,32 @@ hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key,
size_t hlen = 0, vlen = 0;
-#define _(x) { size_t n; if ((err = hal_asn1_encode_integer(x, NULL, &n, der_max - vlen)) != HAL_OK) return err; vlen += n; }
+#define _(x) \
+ { \
+ size_t n = 0; \
+ err = hal_asn1_encode_integer(x, NULL, &n, der_max - vlen); \
+ if (err != HAL_OK) \
+ return err; \
+ vlen += n; \
+ }
+
RSAPrivateKey_fields;
#undef _
+#define _(x,y,z) \
+ if ((key->flags & z) != 0) { \
+ size_t n = 0; \
+ if ((err = hal_asn1_encode_header(x, sizeof(key->y), NULL, \
+ &n, 0)) != HAL_OK) \
+ return err; \
+ vlen += n + sizeof(key->y); \
+ }
+
+ if (include_extra) {
+ RSAPrivateKey_extra_fields;
+ }
+#undef _
+
if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0)) != HAL_OK)
return err;
@@ -729,18 +1037,51 @@ hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key,
uint8_t *d = der + hlen;
memset(d, 0, vlen);
-#define _(x) { size_t n; if ((err = hal_asn1_encode_integer(x, d, &n, vlen)) != HAL_OK) return err; d += n; vlen -= n; }
+#define _(x) \
+ { \
+ size_t n = 0; \
+ err = hal_asn1_encode_integer(x, d, &n, vlen); \
+ if (err != HAL_OK) \
+ return err; \
+ d += n; \
+ vlen -= n; \
+ }
+
RSAPrivateKey_fields;
#undef _
+#define _(x,y,z) \
+ if ((key->flags & z) != 0) { \
+ size_t n = 0; \
+ if ((err = hal_asn1_encode_header(x, sizeof(key->y), d, \
+ &n, vlen)) != HAL_OK) \
+ return err; \
+ d += n; \
+ vlen -= n; \
+ memcpy(d, key->y, sizeof(key->y)); \
+ d += sizeof(key->y); \
+ vlen -= sizeof(key->y); \
+ }
+
+ if (include_extra) {
+ RSAPrivateKey_extra_fields;
+ }
+#undef _
+
return hal_asn1_encode_pkcs8_privatekeyinfo(hal_asn1_oid_rsaEncryption, hal_asn1_oid_rsaEncryption_len,
NULL, 0, der, d - der, der, der_len, der_max);
}
-size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key)
+hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_rsa_private_key_to_der_internal(key, 0, der, der_len, der_max);
+}
+
+hal_error_t hal_rsa_private_key_to_der_extra(const hal_rsa_key_t * const key,
+ uint8_t *der, size_t *der_len, const size_t der_max)
{
- size_t len = 0;
- return hal_rsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0;
+ return hal_rsa_private_key_to_der_internal(key, 1, der, der_len, der_max);
}
hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key_,
@@ -778,12 +1119,48 @@ hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key_,
fp_int version[1] = INIT_FP_INT;
-#define _(x) { size_t n; if ((err = hal_asn1_decode_integer(x, d, &n, vlen)) != HAL_OK) return err; d += n; vlen -= n; }
+#define _(x) \
+ { \
+ size_t n; \
+ err = hal_asn1_decode_integer(x, d, &n, vlen); \
+ if (err != HAL_OK) \
+ return err; \
+ d += n; \
+ vlen -= n; \
+ }
+
RSAPrivateKey_fields;
#undef _
- if (d != privkey + privkey_len || !fp_iszero(version))
+#define _(x,y,z) \
+ if (hal_asn1_peek(x, d, vlen)) { \
+ size_t hl = 0, vl = 0; \
+ if ((err = hal_asn1_decode_header(x, d, vlen, &hl, &vl)) != HAL_OK) \
+ return err; \
+ if (vl > sizeof(key->y)) { \
+ hal_log(HAL_LOG_DEBUG, "extra factor %s too big (%lu > %lu)", \
+ #y, (unsigned long) vl, (unsigned long) sizeof(key->y)); \
+ return HAL_ERROR_ASN1_PARSE_FAILED; \
+ } \
+ memcpy(key->y, d + hl, vl); \
+ key->flags |= z; \
+ d += hl + vl; \
+ vlen -= hl + vl; \
+ }
+
+ RSAPrivateKey_extra_fields;
+#undef _
+
+ if (d != privkey + privkey_len) {
+ hal_log(HAL_LOG_DEBUG, "not at end of buffer (0x%lx != 0x%lx)",
+ (unsigned long) d, (unsigned long) privkey + privkey_len);
return HAL_ERROR_ASN1_PARSE_FAILED;
+ }
+
+ if (!fp_iszero(version)) {
+ hal_log(HAL_LOG_DEBUG, "nonzero version");
+ return HAL_ERROR_ASN1_PARSE_FAILED;
+ }
*key_ = key;
diff --git a/slip.c b/slip.c
index b28b7e1..b53d54c 100644
--- a/slip.c
+++ b/slip.c
@@ -85,7 +85,7 @@ hal_error_t hal_slip_send(const uint8_t * const buf, const size_t len)
/* for each byte in the packet, send the appropriate character
* sequence
*/
- for (int i = 0; i < len; ++i) {
+ for (size_t i = 0; i < len; ++i) {
hal_error_t ret;
if ((ret = hal_slip_send_char(buf[i])) != HAL_OK)
return ret;
diff --git a/tests/Makefile b/tests/Makefile
index 79cb3ff..d186000 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -45,7 +45,7 @@ CFLAGS ?= -g3 -Wall -fPIC -std=c99 -I${LIBHAL_SRC} -I${LIBTFM_BLD}
CORE_TESTS = test-aes-key-wrap test-hash test-pbkdf2 test-ecdsa test-bus test-trng test-rsa test-mkmif
SERVER_TESTS = test-rpc_server
-CLIENT_TESTS = test-rpc_hash test-rpc_pkey test-rpc_get_version test-rpc_get_random test-rpc_login test-rpc_bighash
+CLIENT_TESTS = test-rpc_hash test-rpc_pkey test-rpc_get_version test-rpc_get_random test-rpc_login test-rpc_bighash test-xdr test-rpc_hashsig
ALL_TESTS = ${CORE_TESTS} ${SERVER_TESTS} ${CLIENT_TESTS}
@@ -78,3 +78,5 @@ ${BIN}: %: %.o ${LIBS}
%.o: %.c ${LBHAL_SRC}/*.h ${LIBTFM_BLD}/tfm.h
${CC} ${CFLAGS} -c -o $@ $<
+
+test-rpc_hashsig.o: test-hashsig.h
diff --git a/tests/parallel-signatures.py b/tests/parallel-signatures.py
new file mode 100755
index 0000000..006b753
--- /dev/null
+++ b/tests/parallel-signatures.py
@@ -0,0 +1,409 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016-2018, 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.
+
+"""
+Test multiple clients and parallel RSA signatures.
+"""
+
+# This was originally going to be a complete asynchronous-capable
+# version of cryptech.libhal, but that turned into a yak shaving
+# exercise, so refocused on just solving the immediate task at hand,
+# to wit, parallel signing tests.
+
+import os
+import sys
+import uuid
+import xdrlib
+import socket
+import logging
+import datetime
+import collections
+
+import cryptech.libhal
+
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+
+from tornado.gen import Return, coroutine
+from tornado.ioloop import IOLoop
+from tornado.iostream import IOStream, StreamClosedError
+from tornado.queues import Queue
+
+from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
+from Crypto.Util.number import inverse
+from Crypto.PublicKey import RSA
+from Crypto.Cipher.PKCS1_v1_5 import PKCS115_Cipher
+from Crypto.Signature.PKCS1_v1_5 import PKCS115_SigScheme
+from Crypto.Hash.SHA256 import SHA256Hash as SHA256
+from Crypto.Hash.SHA384 import SHA384Hash as SHA384
+from Crypto.Hash.SHA512 import SHA512Hash as SHA512
+
+
+logger = logging.getLogger(__name__)
+
+
+globals().update((name, getattr(cryptech.libhal, name))
+ for name in dir(cryptech.libhal)
+ if any(name.startswith(prefix)
+ for prefix in ("HAL", "RPC", "SLIP")))
+
+
+class PKey(cryptech.libhal.Handle):
+
+ def __init__(self, hsm, handle, uuid):
+ self.hsm = hsm
+ self.handle = handle
+ self.uuid = uuid
+ self.deleted = False
+
+ @coroutine
+ def close(self):
+ yield self.hsm.pkey_close(self)
+
+ @coroutine
+ def delete(self):
+ yield self.hsm.pkey_delete(self)
+ self.deleted = True
+
+ @coroutine
+ def sign(self, data, length = 1024):
+ r = yield self.hsm.pkey_sign(self, data = data, length = length)
+ raise Return(r)
+
+ @coroutine
+ def verify(self, data = "", signature = None):
+ yield self.hsm.pkey_verify(self, data = data, signature = signature)
+
+
+class ContextManagedUnpacker(xdrlib.Unpacker):
+ def __enter__(self):
+ return self
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.done()
+
+
+class HSM(cryptech.libhal.HSM):
+
+ def __init__(self,
+ sockname = os.getenv("CRYPTECH_RPC_CLIENT_SOCKET_NAME",
+ "/tmp/.cryptech_muxd.rpc"),
+ debug_io = False):
+ self.hsm = self
+ self.debug_io = debug_io
+ self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.socket.connect(sockname)
+ self.iostream = IOStream(self.socket)
+
+ @coroutine
+ 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)
+ packer = cryptech.libhal.slip_encode(packer.get_buffer())
+ if self.debug_io:
+ logger.debug("send: %s", ":".join("{:02x}".format(ord(c)) for c in packer))
+ yield self.iostream.write(packer)
+ while True:
+ try:
+ unpacker = yield self.iostream.read_until(SLIP_END)
+ except StreamClosedError:
+ raise HAL_ERROR_RPC_TRANSPORT()
+ if self.debug_io:
+ logger.debug("recv: %s", ":".join("{:02x}".format(ord(c)) for c in unpacker))
+ unpacker = cryptech.libhal.slip_decode(unpacker)
+ if not unpacker:
+ continue
+ unpacker = ContextManagedUnpacker("".join(unpacker))
+ if unpacker.unpack_uint() == code:
+ break
+ client = unpacker.unpack_uint()
+ self._raise_if_error(unpacker.unpack_uint())
+ raise Return(unpacker)
+
+ @coroutine
+ def login(self, user, pin, client = 0):
+ with (yield self.rpc(RPC_FUNC_LOGIN, user, pin, client = client)):
+ pass
+
+ @coroutine
+ def logout(self, client = 0):
+ with (yield self.rpc(RPC_FUNC_LOGOUT, client = client)):
+ pass
+
+ @coroutine
+ def pkey_load(self, der, flags = 0, client = 0, session = 0):
+ r = yield self.rpc(RPC_FUNC_PKEY_LOAD, session, der, flags, client = client)
+ with r:
+ pkey = PKey(self, r.unpack_uint(), cryptech.libhal.UUID(bytes = r.unpack_bytes()))
+ logger.debug("Loaded pkey %s", pkey.uuid)
+ raise Return(pkey)
+
+ @coroutine
+ def pkey_close(self, pkey):
+ try:
+ logger.debug("Closing pkey %s", pkey.uuid)
+ except AttributeError:
+ pass
+ with (yield self.rpc(RPC_FUNC_PKEY_CLOSE, pkey)):
+ pass
+
+ @coroutine
+ def pkey_delete(self, pkey):
+ try:
+ logger.debug("Deleting pkey %s", pkey.uuid)
+ except AttributeError:
+ pass
+ with (yield self.rpc(RPC_FUNC_PKEY_DELETE, pkey)):
+ pass
+
+ @coroutine
+ def pkey_sign(self, pkey, data, length = 1024):
+ with (yield self.rpc(RPC_FUNC_PKEY_SIGN, pkey, 0, data, length)) as r:
+ raise Return(r.unpack_bytes())
+
+
+def pkcs1_hash_and_pad(text):
+ return DerSequence([DerSequence([SHA256.oid, DerNull().encode()]).encode(),
+ DerOctetString(SHA256(text).digest()).encode()]).encode()
+
+
+@coroutine
+def worker(args, k, p, q, r, m):
+ while True:
+ n = yield q.get()
+ logger.debug("Signing %s", n)
+ try:
+ t0 = datetime.datetime.now()
+ s = yield p.sign(data = m)
+ t1 = datetime.datetime.now()
+ if args.verify:
+ k.verify(s)
+ r.add(t0, t1)
+ except:
+ logger.exception("Signature failed")
+ finally:
+ q.task_done()
+
+@coroutine
+def main():
+ parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter)
+ parser.add_argument("-i", "--iterations", default = 1000, type = int, help = "iterations")
+ parser.add_argument("-k", "--key", choices = tuple(key_table),
+ default = "rsa_2048", help = "key to test")
+ parser.add_argument("-p", "--pin", default = "fnord", help = "user PIN")
+ parser.add_argument("-q", "--quiet", action = "store_true", help = "be less chatty")
+ parser.add_argument("-t", "--text", default = "Hamsters'R'Us", help = "plaintext to sign")
+ parser.add_argument("-v", "--verify", action = "store_true", help = "verify signatures")
+ parser.add_argument("-w", "--workers", default = 4, type = int, help = "worker count")
+ args = parser.parse_args()
+
+ k = key_table[args.key]
+ q = Queue()
+
+ tbs = pkcs1_hash_and_pad(args.text)
+ der = k.exportKey(format = "DER", pkcs = 8)
+
+ hsms = [HSM() for i in xrange(args.workers)]
+
+ for hsm in hsms:
+ yield hsm.login(HAL_USER_NORMAL, args.pin)
+
+ pkeys = yield [hsm.pkey_load(der, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) for hsm in hsms]
+
+ r = Result(args, args.key)
+
+ for pkey in pkeys:
+ IOLoop.current().spawn_callback(worker, args, k, pkey, q, r, tbs)
+
+ yield [q.put(i) for i in xrange(args.iterations)]
+ yield q.join()
+
+ yield [pkey.delete() for pkey in pkeys]
+
+ r.report()
+
+
+class Result(object):
+
+ def __init__(self, args, name):
+ self.args = args
+ self.name = name
+ self.sum = datetime.timedelta(seconds = 0)
+ self.t0 = None
+ self.t1 = None
+ self.n = 0
+
+ def add(self, t0, t1):
+ if self.t0 is None:
+ self.t0 = t0
+ self.t1 = t1
+ delta = t1 - t0
+ self.sum += delta
+ self.n += 1
+ if not self.args.quiet:
+ sys.stdout.write("\r{:4d} {}".format(self.n, delta))
+ sys.stdout.flush()
+
+ @property
+ def mean(self):
+ return self.sum / self.n
+
+ @property
+ def secs_per_sig(self):
+ return (self.t1 - self.t0) / self.n
+
+ @property
+ def sigs_per_sec(self):
+ return self.n / (self.t1 - self.t0).total_seconds()
+
+ @property
+ def speedup(self):
+ return self.sum.total_seconds() / (self.t1 - self.t0).total_seconds()
+
+ def report(self):
+ sys.stdout.write(("\r{0.name} "
+ "sigs/sec {0.sigs_per_sec} "
+ "secs/sig {0.secs_per_sig} "
+ "mean {0.mean} "
+ "speedup {0.speedup} "
+ "(n {0.n}, "
+ "t0 {0.t0} "
+ "t1 {0.t1})\n").format(self))
+ sys.stdout.flush()
+
+
+key_table = collections.OrderedDict()
+
+key_table.update(rsa_1024 = RSA.importKey('''\
+-----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-----
+'''))
+
+key_table.update(rsa_2048 = RSA.importKey('''\
+-----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-----
+'''))
+
+key_table.update(rsa_4096 = RSA.importKey('''\
+-----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-----
+'''))
+
+if __name__ == "__main__":
+ IOLoop.current().run_sync(main)
diff --git a/tests/test-aes-key-wrap.c b/tests/test-aes-key-wrap.c
index 5ecd46d..aa894cc 100644
--- a/tests/test-aes-key-wrap.c
+++ b/tests/test-aes-key-wrap.c
@@ -163,7 +163,7 @@ static int run_test(hal_core_t *core,
return ok1 && ok2;
}
-int main (int argc, char *argv[])
+int main(void)
{
int failures = 0;
diff --git a/tests/test-ecdsa.c b/tests/test-ecdsa.c
index da2b367..fe04a87 100644
--- a/tests/test-ecdsa.c
+++ b/tests/test-ecdsa.c
@@ -359,7 +359,7 @@ static void show_core(const hal_core_t *core, const char *whinge)
printf("%s core not present\n", whinge);
}
-int main(int argc, char *argv[])
+int main(void)
{
const hal_core_t *sha256_core = hal_core_find(SHA256_NAME, NULL);
const hal_core_t *sha512_core = hal_core_find(SHA512_NAME, NULL);
diff --git a/tests/test-hash.c b/tests/test-hash.c
index 4e78243..20bd446 100644
--- a/tests/test-hash.c
+++ b/tests/test-hash.c
@@ -652,7 +652,7 @@ static void show_core(hal_core_t *core, const char *whinge)
printf("%s core not present\n", whinge);
}
-int main (int argc, char *argv[])
+int main(void)
{
hal_core_t * const sha1_core = hal_core_find(SHA1_NAME, NULL);
hal_core_t * const sha256_core = hal_core_find(SHA256_NAME, NULL);
diff --git a/tests/test-hashsig.h b/tests/test-hashsig.h
new file mode 100644
index 0000000..4b8333f
--- /dev/null
+++ b/tests/test-hashsig.h
@@ -0,0 +1,925 @@
+/*
+ * draft-mcgrew test cases
+ */
+
+/* Test Case 1 Public Key */
+
+static uint8_t tc1_key[] = {
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x61, 0xa5, 0xd5, 0x7d, 0x37, 0xf5, 0xe4, 0x6b,
+ 0xfb, 0x75, 0x20, 0x80, 0x6b, 0x07, 0xa1, 0xb8,
+ 0x50, 0x65, 0x0e, 0x3b, 0x31, 0xfe, 0x4a, 0x77,
+ 0x3e, 0xa2, 0x9a, 0x07, 0xf0, 0x9c, 0xf2, 0xea,
+ 0x30, 0xe5, 0x79, 0xf0, 0xdf, 0x58, 0xef, 0x8e,
+ 0x29, 0x8d, 0xa0, 0x43, 0x4c, 0xb2, 0xb8, 0x78,
+};
+
+/* Test Case 1 Message */
+
+static uint8_t tc1_msg[] = {
+ 0x54, 0x68, 0x65, 0x20, 0x70, 0x6f, 0x77, 0x65,
+ 0x72, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64,
+ 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64,
+ 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20,
+ 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x62, 0x79,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e,
+ 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f,
+ 0x6e, 0x2c, 0x20, 0x6e, 0x6f, 0x72, 0x20, 0x70,
+ 0x72, 0x6f, 0x68, 0x69, 0x62, 0x69, 0x74, 0x65,
+ 0x64, 0x20, 0x62, 0x79, 0x20, 0x69, 0x74, 0x20,
+ 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x73, 0x2c, 0x20, 0x61,
+ 0x72, 0x65, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72,
+ 0x76, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63,
+ 0x74, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x2c, 0x20,
+ 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x70, 0x65, 0x6f, 0x70, 0x6c, 0x65,
+ 0x2e, 0x0a,
+};
+
+/* Test Case 1 Signature */
+/* 2 levels, both h=5, w=8 */
+
+static uint8_t tc1_sig[] = {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04,
+ 0xd3, 0x2b, 0x56, 0x67, 0x1d, 0x7e, 0xb9, 0x88,
+ 0x33, 0xc4, 0x9b, 0x43, 0x3c, 0x27, 0x25, 0x86,
+ 0xbc, 0x4a, 0x1c, 0x8a, 0x89, 0x70, 0x52, 0x8f,
+ 0xfa, 0x04, 0xb9, 0x66, 0xf9, 0x42, 0x6e, 0xb9,
+ 0x96, 0x5a, 0x25, 0xbf, 0xd3, 0x7f, 0x19, 0x6b,
+ 0x90, 0x73, 0xf3, 0xd4, 0xa2, 0x32, 0xfe, 0xb6,
+ 0x91, 0x28, 0xec, 0x45, 0x14, 0x6f, 0x86, 0x29,
+ 0x2f, 0x9d, 0xff, 0x96, 0x10, 0xa7, 0xbf, 0x95,
+ 0xa6, 0x4c, 0x7f, 0x60, 0xf6, 0x26, 0x1a, 0x62,
+ 0x04, 0x3f, 0x86, 0xc7, 0x03, 0x24, 0xb7, 0x70,
+ 0x7f, 0x5b, 0x4a, 0x8a, 0x6e, 0x19, 0xc1, 0x14,
+ 0xc7, 0xbe, 0x86, 0x6d, 0x48, 0x87, 0x78, 0xa0,
+ 0xe0, 0x5f, 0xd5, 0xc6, 0x50, 0x9a, 0x6e, 0x61,
+ 0xd5, 0x59, 0xcf, 0x1a, 0x77, 0xa9, 0x70, 0xde,
+ 0x92, 0x7d, 0x60, 0xc7, 0x0d, 0x3d, 0xe3, 0x1a,
+ 0x7f, 0xa0, 0x10, 0x09, 0x94, 0xe1, 0x62, 0xa2,
+ 0x58, 0x2e, 0x8f, 0xf1, 0xb1, 0x0c, 0xd9, 0x9d,
+ 0x4e, 0x8e, 0x41, 0x3e, 0xf4, 0x69, 0x55, 0x9f,
+ 0x7d, 0x7e, 0xd1, 0x2c, 0x83, 0x83, 0x42, 0xf9,
+ 0xb9, 0xc9, 0x6b, 0x83, 0xa4, 0x94, 0x3d, 0x16,
+ 0x81, 0xd8, 0x4b, 0x15, 0x35, 0x7f, 0xf4, 0x8c,
+ 0xa5, 0x79, 0xf1, 0x9f, 0x5e, 0x71, 0xf1, 0x84,
+ 0x66, 0xf2, 0xbb, 0xef, 0x4b, 0xf6, 0x60, 0xc2,
+ 0x51, 0x8e, 0xb2, 0x0d, 0xe2, 0xf6, 0x6e, 0x3b,
+ 0x14, 0x78, 0x42, 0x69, 0xd7, 0xd8, 0x76, 0xf5,
+ 0xd3, 0x5d, 0x3f, 0xbf, 0xc7, 0x03, 0x9a, 0x46,
+ 0x2c, 0x71, 0x6b, 0xb9, 0xf6, 0x89, 0x1a, 0x7f,
+ 0x41, 0xad, 0x13, 0x3e, 0x9e, 0x1f, 0x6d, 0x95,
+ 0x60, 0xb9, 0x60, 0xe7, 0x77, 0x7c, 0x52, 0xf0,
+ 0x60, 0x49, 0x2f, 0x2d, 0x7c, 0x66, 0x0e, 0x14,
+ 0x71, 0xe0, 0x7e, 0x72, 0x65, 0x55, 0x62, 0x03,
+ 0x5a, 0xbc, 0x9a, 0x70, 0x1b, 0x47, 0x3e, 0xcb,
+ 0xc3, 0x94, 0x3c, 0x6b, 0x9c, 0x4f, 0x24, 0x05,
+ 0xa3, 0xcb, 0x8b, 0xf8, 0xa6, 0x91, 0xca, 0x51,
+ 0xd3, 0xf6, 0xad, 0x2f, 0x42, 0x8b, 0xab, 0x6f,
+ 0x3a, 0x30, 0xf5, 0x5d, 0xd9, 0x62, 0x55, 0x63,
+ 0xf0, 0xa7, 0x5e, 0xe3, 0x90, 0xe3, 0x85, 0xe3,
+ 0xae, 0x0b, 0x90, 0x69, 0x61, 0xec, 0xf4, 0x1a,
+ 0xe0, 0x73, 0xa0, 0x59, 0x0c, 0x2e, 0xb6, 0x20,
+ 0x4f, 0x44, 0x83, 0x1c, 0x26, 0xdd, 0x76, 0x8c,
+ 0x35, 0xb1, 0x67, 0xb2, 0x8c, 0xe8, 0xdc, 0x98,
+ 0x8a, 0x37, 0x48, 0x25, 0x52, 0x30, 0xce, 0xf9,
+ 0x9e, 0xbf, 0x14, 0xe7, 0x30, 0x63, 0x2f, 0x27,
+ 0x41, 0x44, 0x89, 0x80, 0x8a, 0xfa, 0xb1, 0xd1,
+ 0xe7, 0x83, 0xed, 0x04, 0x51, 0x6d, 0xe0, 0x12,
+ 0x49, 0x86, 0x82, 0x21, 0x2b, 0x07, 0x81, 0x05,
+ 0x79, 0xb2, 0x50, 0x36, 0x59, 0x41, 0xbc, 0xc9,
+ 0x81, 0x42, 0xda, 0x13, 0x60, 0x9e, 0x97, 0x68,
+ 0xaa, 0xf6, 0x5d, 0xe7, 0x62, 0x0d, 0xab, 0xec,
+ 0x29, 0xeb, 0x82, 0xa1, 0x7f, 0xde, 0x35, 0xaf,
+ 0x15, 0xad, 0x23, 0x8c, 0x73, 0xf8, 0x1b, 0xdb,
+ 0x8d, 0xec, 0x2f, 0xc0, 0xe7, 0xf9, 0x32, 0x70,
+ 0x10, 0x99, 0x76, 0x2b, 0x37, 0xf4, 0x3c, 0x4a,
+ 0x3c, 0x20, 0x01, 0x0a, 0x3d, 0x72, 0xe2, 0xf6,
+ 0x06, 0xbe, 0x10, 0x8d, 0x31, 0x0e, 0x63, 0x9f,
+ 0x09, 0xce, 0x72, 0x86, 0x80, 0x0d, 0x9e, 0xf8,
+ 0xa1, 0xa4, 0x02, 0x81, 0xcc, 0x5a, 0x7e, 0xa9,
+ 0x8d, 0x2a, 0xdc, 0x7c, 0x74, 0x00, 0xc2, 0xfe,
+ 0x5a, 0x10, 0x15, 0x52, 0xdf, 0x4e, 0x3c, 0xcc,
+ 0xfd, 0x0c, 0xbf, 0x2d, 0xdf, 0x5d, 0xc6, 0x77,
+ 0x9c, 0xbb, 0xc6, 0x8f, 0xee, 0x0c, 0x3e, 0xfe,
+ 0x4e, 0xc2, 0x2b, 0x83, 0xa2, 0xca, 0xa3, 0xe4,
+ 0x8e, 0x08, 0x09, 0xa0, 0xa7, 0x50, 0xb7, 0x3c,
+ 0xcd, 0xcf, 0x3c, 0x79, 0xe6, 0x58, 0x0c, 0x15,
+ 0x4f, 0x8a, 0x58, 0xf7, 0xf2, 0x43, 0x35, 0xee,
+ 0xc5, 0xc5, 0xeb, 0x5e, 0x0c, 0xf0, 0x1d, 0xcf,
+ 0x44, 0x39, 0x42, 0x40, 0x95, 0xfc, 0xeb, 0x07,
+ 0x7f, 0x66, 0xde, 0xd5, 0xbe, 0xc7, 0x3b, 0x27,
+ 0xc5, 0xb9, 0xf6, 0x4a, 0x2a, 0x9a, 0xf2, 0xf0,
+ 0x7c, 0x05, 0xe9, 0x9e, 0x5c, 0xf8, 0x0f, 0x00,
+ 0x25, 0x2e, 0x39, 0xdb, 0x32, 0xf6, 0xc1, 0x96,
+ 0x74, 0xf1, 0x90, 0xc9, 0xfb, 0xc5, 0x06, 0xd8,
+ 0x26, 0x85, 0x77, 0x13, 0xaf, 0xd2, 0xca, 0x6b,
+ 0xb8, 0x5c, 0xd8, 0xc1, 0x07, 0x34, 0x75, 0x52,
+ 0xf3, 0x05, 0x75, 0xa5, 0x41, 0x78, 0x16, 0xab,
+ 0x4d, 0xb3, 0xf6, 0x03, 0xf2, 0xdf, 0x56, 0xfb,
+ 0xc4, 0x13, 0xe7, 0xd0, 0xac, 0xd8, 0xbd, 0xd8,
+ 0x13, 0x52, 0xb2, 0x47, 0x1f, 0xc1, 0xbc, 0x4f,
+ 0x1e, 0xf2, 0x96, 0xfe, 0xa1, 0x22, 0x04, 0x03,
+ 0x46, 0x6b, 0x1a, 0xfe, 0x78, 0xb9, 0x4f, 0x7e,
+ 0xcf, 0x7c, 0xc6, 0x2f, 0xb9, 0x2b, 0xe1, 0x4f,
+ 0x18, 0xc2, 0x19, 0x23, 0x84, 0xeb, 0xce, 0xaf,
+ 0x88, 0x01, 0xaf, 0xdf, 0x94, 0x7f, 0x69, 0x8c,
+ 0xe9, 0xc6, 0xce, 0xb6, 0x96, 0xed, 0x70, 0xe9,
+ 0xe8, 0x7b, 0x01, 0x44, 0x41, 0x7e, 0x8d, 0x7b,
+ 0xaf, 0x25, 0xeb, 0x5f, 0x70, 0xf0, 0x9f, 0x01,
+ 0x6f, 0xc9, 0x25, 0xb4, 0xdb, 0x04, 0x8a, 0xb8,
+ 0xd8, 0xcb, 0x2a, 0x66, 0x1c, 0xe3, 0xb5, 0x7a,
+ 0xda, 0x67, 0x57, 0x1f, 0x5d, 0xd5, 0x46, 0xfc,
+ 0x22, 0xcb, 0x1f, 0x97, 0xe0, 0xeb, 0xd1, 0xa6,
+ 0x59, 0x26, 0xb1, 0x23, 0x4f, 0xd0, 0x4f, 0x17,
+ 0x1c, 0xf4, 0x69, 0xc7, 0x6b, 0x88, 0x4c, 0xf3,
+ 0x11, 0x5c, 0xce, 0x6f, 0x79, 0x2c, 0xc8, 0x4e,
+ 0x36, 0xda, 0x58, 0x96, 0x0c, 0x5f, 0x1d, 0x76,
+ 0x0f, 0x32, 0xc1, 0x2f, 0xae, 0xf4, 0x77, 0xe9,
+ 0x4c, 0x92, 0xeb, 0x75, 0x62, 0x5b, 0x6a, 0x37,
+ 0x1e, 0xfc, 0x72, 0xd6, 0x0c, 0xa5, 0xe9, 0x08,
+ 0xb3, 0xa7, 0xdd, 0x69, 0xfe, 0xf0, 0x24, 0x91,
+ 0x50, 0xe3, 0xee, 0xbd, 0xfe, 0xd3, 0x9c, 0xbd,
+ 0xc3, 0xce, 0x97, 0x04, 0x88, 0x2a, 0x20, 0x72,
+ 0xc7, 0x5e, 0x13, 0x52, 0x7b, 0x7a, 0x58, 0x1a,
+ 0x55, 0x61, 0x68, 0x78, 0x3d, 0xc1, 0xe9, 0x75,
+ 0x45, 0xe3, 0x18, 0x65, 0xdd, 0xc4, 0x6b, 0x3c,
+ 0x95, 0x78, 0x35, 0xda, 0x25, 0x2b, 0xb7, 0x32,
+ 0x8d, 0x3e, 0xe2, 0x06, 0x24, 0x45, 0xdf, 0xb8,
+ 0x5e, 0xf8, 0xc3, 0x5f, 0x8e, 0x1f, 0x33, 0x71,
+ 0xaf, 0x34, 0x02, 0x3c, 0xef, 0x62, 0x6e, 0x0a,
+ 0xf1, 0xe0, 0xbc, 0x01, 0x73, 0x51, 0xaa, 0xe2,
+ 0xab, 0x8f, 0x5c, 0x61, 0x2e, 0xad, 0x0b, 0x72,
+ 0x9a, 0x1d, 0x05, 0x9d, 0x02, 0xbf, 0xe1, 0x8e,
+ 0xfa, 0x97, 0x1b, 0x73, 0x00, 0xe8, 0x82, 0x36,
+ 0x0a, 0x93, 0xb0, 0x25, 0xff, 0x97, 0xe9, 0xe0,
+ 0xee, 0xc0, 0xf3, 0xf3, 0xf1, 0x30, 0x39, 0xa1,
+ 0x7f, 0x88, 0xb0, 0xcf, 0x80, 0x8f, 0x48, 0x84,
+ 0x31, 0x60, 0x6c, 0xb1, 0x3f, 0x92, 0x41, 0xf4,
+ 0x0f, 0x44, 0xe5, 0x37, 0xd3, 0x02, 0xc6, 0x4a,
+ 0x4f, 0x1f, 0x4a, 0xb9, 0x49, 0xb9, 0xfe, 0xef,
+ 0xad, 0xcb, 0x71, 0xab, 0x50, 0xef, 0x27, 0xd6,
+ 0xd6, 0xca, 0x85, 0x10, 0xf1, 0x50, 0xc8, 0x5f,
+ 0xb5, 0x25, 0xbf, 0x25, 0x70, 0x3d, 0xf7, 0x20,
+ 0x9b, 0x60, 0x66, 0xf0, 0x9c, 0x37, 0x28, 0x0d,
+ 0x59, 0x12, 0x8d, 0x2f, 0x0f, 0x63, 0x7c, 0x7d,
+ 0x7d, 0x7f, 0xad, 0x4e, 0xd1, 0xc1, 0xea, 0x04,
+ 0xe6, 0x28, 0xd2, 0x21, 0xe3, 0xd8, 0xdb, 0x77,
+ 0xb7, 0xc8, 0x78, 0xc9, 0x41, 0x1c, 0xaf, 0xc5,
+ 0x07, 0x1a, 0x34, 0xa0, 0x0f, 0x4c, 0xf0, 0x77,
+ 0x38, 0x91, 0x27, 0x53, 0xdf, 0xce, 0x48, 0xf0,
+ 0x75, 0x76, 0xf0, 0xd4, 0xf9, 0x4f, 0x42, 0xc6,
+ 0xd7, 0x6f, 0x7c, 0xe9, 0x73, 0xe9, 0x36, 0x70,
+ 0x95, 0xba, 0x7e, 0x9a, 0x36, 0x49, 0xb7, 0xf4,
+ 0x61, 0xd9, 0xf9, 0xac, 0x13, 0x32, 0xa4, 0xd1,
+ 0x04, 0x4c, 0x96, 0xae, 0xfe, 0xe6, 0x76, 0x76,
+ 0x40, 0x1b, 0x64, 0x45, 0x7c, 0x54, 0xd6, 0x5f,
+ 0xef, 0x65, 0x00, 0xc5, 0x9c, 0xdf, 0xb6, 0x9a,
+ 0xf7, 0xb6, 0xdd, 0xdf, 0xcb, 0x0f, 0x08, 0x62,
+ 0x78, 0xdd, 0x8a, 0xd0, 0x68, 0x60, 0x78, 0xdf,
+ 0xb0, 0xf3, 0xf7, 0x9c, 0xd8, 0x93, 0xd3, 0x14,
+ 0x16, 0x86, 0x48, 0x49, 0x98, 0x98, 0xfb, 0xc0,
+ 0xce, 0xd5, 0xf9, 0x5b, 0x74, 0xe8, 0xff, 0x14,
+ 0xd7, 0x35, 0xcd, 0xea, 0x96, 0x8b, 0xee, 0x74,
+ 0x00, 0x00, 0x00, 0x05,
+ 0xd8, 0xb8, 0x11, 0x2f, 0x92, 0x00, 0xa5, 0xe5,
+ 0x0c, 0x4a, 0x26, 0x21, 0x65, 0xbd, 0x34, 0x2c,
+ 0xd8, 0x00, 0xb8, 0x49, 0x68, 0x10, 0xbc, 0x71,
+ 0x62, 0x77, 0x43, 0x5a, 0xc3, 0x76, 0x72, 0x8d,
+ 0x12, 0x9a, 0xc6, 0xed, 0xa8, 0x39, 0xa6, 0xf3,
+ 0x57, 0xb5, 0xa0, 0x43, 0x87, 0xc5, 0xce, 0x97,
+ 0x38, 0x2a, 0x78, 0xf2, 0xa4, 0x37, 0x29, 0x17,
+ 0xee, 0xfc, 0xbf, 0x93, 0xf6, 0x3b, 0xb5, 0x91,
+ 0x12, 0xf5, 0xdb, 0xe4, 0x00, 0xbd, 0x49, 0xe4,
+ 0x50, 0x1e, 0x85, 0x9f, 0x88, 0x5b, 0xf0, 0x73,
+ 0x6e, 0x90, 0xa5, 0x09, 0xb3, 0x0a, 0x26, 0xbf,
+ 0xac, 0x8c, 0x17, 0xb5, 0x99, 0x1c, 0x15, 0x7e,
+ 0xb5, 0x97, 0x11, 0x15, 0xaa, 0x39, 0xef, 0xd8,
+ 0xd5, 0x64, 0xa6, 0xb9, 0x02, 0x82, 0xc3, 0x16,
+ 0x8a, 0xf2, 0xd3, 0x0e, 0xf8, 0x9d, 0x51, 0xbf,
+ 0x14, 0x65, 0x45, 0x10, 0xa1, 0x2b, 0x8a, 0x14,
+ 0x4c, 0xca, 0x18, 0x48, 0xcf, 0x7d, 0xa5, 0x9c,
+ 0xc2, 0xb3, 0xd9, 0xd0, 0x69, 0x2d, 0xd2, 0xa2,
+ 0x0b, 0xa3, 0x86, 0x34, 0x80, 0xe2, 0x5b, 0x1b,
+ 0x85, 0xee, 0x86, 0x0c, 0x62, 0xbf, 0x51, 0x36,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04,
+ 0xd2, 0xf1, 0x4f, 0xf6, 0x34, 0x6a, 0xf9, 0x64,
+ 0x56, 0x9f, 0x7d, 0x6c, 0xb8, 0x80, 0xa1, 0xb6,
+ 0x6c, 0x50, 0x04, 0x91, 0x7d, 0xa6, 0xea, 0xfe,
+ 0x4d, 0x9e, 0xf6, 0xc6, 0x40, 0x7b, 0x3d, 0xb0,
+ 0xe5, 0x48, 0x5b, 0x12, 0x2d, 0x9e, 0xbe, 0x15,
+ 0xcd, 0xa9, 0x3c, 0xfe, 0xc5, 0x82, 0xd7, 0xab,
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x07, 0x03, 0xc4, 0x91, 0xe7, 0x55, 0x8b, 0x35,
+ 0x01, 0x1e, 0xce, 0x35, 0x92, 0xea, 0xa5, 0xda,
+ 0x4d, 0x91, 0x87, 0x86, 0x77, 0x12, 0x33, 0xe8,
+ 0x35, 0x3b, 0xc4, 0xf6, 0x23, 0x23, 0x18, 0x5c,
+ 0x95, 0xca, 0xe0, 0x5b, 0x89, 0x9e, 0x35, 0xdf,
+ 0xfd, 0x71, 0x70, 0x54, 0x70, 0x62, 0x09, 0x98,
+ 0x8e, 0xbf, 0xdf, 0x6e, 0x37, 0x96, 0x0b, 0xb5,
+ 0xc3, 0x8d, 0x76, 0x57, 0xe8, 0xbf, 0xfe, 0xef,
+ 0x9b, 0xc0, 0x42, 0xda, 0x4b, 0x45, 0x25, 0x65,
+ 0x04, 0x85, 0xc6, 0x6d, 0x0c, 0xe1, 0x9b, 0x31,
+ 0x75, 0x87, 0xc6, 0xba, 0x4b, 0xff, 0xcc, 0x42,
+ 0x8e, 0x25, 0xd0, 0x89, 0x31, 0xe7, 0x2d, 0xfb,
+ 0x6a, 0x12, 0x0c, 0x56, 0x12, 0x34, 0x42, 0x58,
+ 0xb8, 0x5e, 0xfd, 0xb7, 0xdb, 0x1d, 0xb9, 0xe1,
+ 0x86, 0x5a, 0x73, 0xca, 0xf9, 0x65, 0x57, 0xeb,
+ 0x39, 0xed, 0x3e, 0x3f, 0x42, 0x69, 0x33, 0xac,
+ 0x9e, 0xed, 0xdb, 0x03, 0xa1, 0xd2, 0x37, 0x4a,
+ 0xf7, 0xbf, 0x77, 0x18, 0x55, 0x77, 0x45, 0x62,
+ 0x37, 0xf9, 0xde, 0x2d, 0x60, 0x11, 0x3c, 0x23,
+ 0xf8, 0x46, 0xdf, 0x26, 0xfa, 0x94, 0x20, 0x08,
+ 0xa6, 0x98, 0x99, 0x4c, 0x08, 0x27, 0xd9, 0x0e,
+ 0x86, 0xd4, 0x3e, 0x0d, 0xf7, 0xf4, 0xbf, 0xcd,
+ 0xb0, 0x9b, 0x86, 0xa3, 0x73, 0xb9, 0x82, 0x88,
+ 0xb7, 0x09, 0x4a, 0xd8, 0x1a, 0x01, 0x85, 0xac,
+ 0x10, 0x0e, 0x4f, 0x2c, 0x5f, 0xc3, 0x8c, 0x00,
+ 0x3c, 0x1a, 0xb6, 0xfe, 0xa4, 0x79, 0xeb, 0x2f,
+ 0x5e, 0xbe, 0x48, 0xf5, 0x84, 0xd7, 0x15, 0x9b,
+ 0x8a, 0xda, 0x03, 0x58, 0x6e, 0x65, 0xad, 0x9c,
+ 0x96, 0x9f, 0x6a, 0xec, 0xbf, 0xe4, 0x4c, 0xf3,
+ 0x56, 0x88, 0x8a, 0x7b, 0x15, 0xa3, 0xff, 0x07,
+ 0x4f, 0x77, 0x17, 0x60, 0xb2, 0x6f, 0x9c, 0x04,
+ 0x88, 0x4e, 0xe1, 0xfa, 0xa3, 0x29, 0xfb, 0xf4,
+ 0xe6, 0x1a, 0xf2, 0x3a, 0xee, 0x7f, 0xa5, 0xd4,
+ 0xd9, 0xa5, 0xdf, 0xcf, 0x43, 0xc4, 0xc2, 0x6c,
+ 0xe8, 0xae, 0xa2, 0xce, 0x8a, 0x29, 0x90, 0xd7,
+ 0xba, 0x7b, 0x57, 0x10, 0x8b, 0x47, 0xda, 0xbf,
+ 0xbe, 0xad, 0xb2, 0xb2, 0x5b, 0x3c, 0xac, 0xc1,
+ 0xac, 0x0c, 0xef, 0x34, 0x6c, 0xbb, 0x90, 0xfb,
+ 0x04, 0x4b, 0xee, 0xe4, 0xfa, 0xc2, 0x60, 0x3a,
+ 0x44, 0x2b, 0xdf, 0x7e, 0x50, 0x72, 0x43, 0xb7,
+ 0x31, 0x9c, 0x99, 0x44, 0xb1, 0x58, 0x6e, 0x89,
+ 0x9d, 0x43, 0x1c, 0x7f, 0x91, 0xbc, 0xcc, 0xc8,
+ 0x69, 0x0d, 0xbf, 0x59, 0xb2, 0x83, 0x86, 0xb2,
+ 0x31, 0x5f, 0x3d, 0x36, 0xef, 0x2e, 0xaa, 0x3c,
+ 0xf3, 0x0b, 0x2b, 0x51, 0xf4, 0x8b, 0x71, 0xb0,
+ 0x03, 0xdf, 0xb0, 0x82, 0x49, 0x48, 0x42, 0x01,
+ 0x04, 0x3f, 0x65, 0xf5, 0xa3, 0xef, 0x6b, 0xbd,
+ 0x61, 0xdd, 0xfe, 0xe8, 0x1a, 0xca, 0x9c, 0xe6,
+ 0x00, 0x81, 0x26, 0x2a, 0x00, 0x00, 0x04, 0x80,
+ 0xdc, 0xbc, 0x9a, 0x3d, 0xa6, 0xfb, 0xef, 0x5c,
+ 0x1c, 0x0a, 0x55, 0xe4, 0x8a, 0x0e, 0x72, 0x9f,
+ 0x91, 0x84, 0xfc, 0xb1, 0x40, 0x7c, 0x31, 0x52,
+ 0x9d, 0xb2, 0x68, 0xf6, 0xfe, 0x50, 0x03, 0x2a,
+ 0x36, 0x3c, 0x98, 0x01, 0x30, 0x68, 0x37, 0xfa,
+ 0xfa, 0xbd, 0xf9, 0x57, 0xfd, 0x97, 0xea, 0xfc,
+ 0x80, 0xdb, 0xd1, 0x65, 0xe4, 0x35, 0xd0, 0xe2,
+ 0xdf, 0xd8, 0x36, 0xa2, 0x8b, 0x35, 0x40, 0x23,
+ 0x92, 0x4b, 0x6f, 0xb7, 0xe4, 0x8b, 0xc0, 0xb3,
+ 0xed, 0x95, 0xee, 0xa6, 0x4c, 0x2d, 0x40, 0x2f,
+ 0x4d, 0x73, 0x4c, 0x8d, 0xc2, 0x6f, 0x3a, 0xc5,
+ 0x91, 0x82, 0x5d, 0xae, 0xf0, 0x1e, 0xae, 0x3c,
+ 0x38, 0xe3, 0x32, 0x8d, 0x00, 0xa7, 0x7d, 0xc6,
+ 0x57, 0x03, 0x4f, 0x28, 0x7c, 0xcb, 0x0f, 0x0e,
+ 0x1c, 0x9a, 0x7c, 0xbd, 0xc8, 0x28, 0xf6, 0x27,
+ 0x20, 0x5e, 0x47, 0x37, 0xb8, 0x4b, 0x58, 0x37,
+ 0x65, 0x51, 0xd4, 0x4c, 0x12, 0xc3, 0xc2, 0x15,
+ 0xc8, 0x12, 0xa0, 0x97, 0x07, 0x89, 0xc8, 0x3d,
+ 0xe5, 0x1d, 0x6a, 0xd7, 0x87, 0x27, 0x19, 0x63,
+ 0x32, 0x7f, 0x0a, 0x5f, 0xbb, 0x6b, 0x59, 0x07,
+ 0xde, 0xc0, 0x2c, 0x9a, 0x90, 0x93, 0x4a, 0xf5,
+ 0xa1, 0xc6, 0x3b, 0x72, 0xc8, 0x26, 0x53, 0x60,
+ 0x5d, 0x1d, 0xcc, 0xe5, 0x15, 0x96, 0xb3, 0xc2,
+ 0xb4, 0x56, 0x96, 0x68, 0x9f, 0x2e, 0xb3, 0x82,
+ 0x00, 0x74, 0x97, 0x55, 0x76, 0x92, 0xca, 0xac,
+ 0x4d, 0x57, 0xb5, 0xde, 0x9f, 0x55, 0x69, 0xbc,
+ 0x2a, 0xd0, 0x13, 0x7f, 0xd4, 0x7f, 0xb4, 0x7e,
+ 0x66, 0x4f, 0xcb, 0x6d, 0xb4, 0x97, 0x1f, 0x5b,
+ 0x3e, 0x07, 0xac, 0xed, 0xa9, 0xac, 0x13, 0x0e,
+ 0x9f, 0x38, 0x18, 0x2d, 0xe9, 0x94, 0xcf, 0xf1,
+ 0x92, 0xec, 0x0e, 0x82, 0xfd, 0x6d, 0x4c, 0xb7,
+ 0xf3, 0xfe, 0x00, 0x81, 0x25, 0x89, 0xb7, 0xa7,
+ 0xce, 0x51, 0x54, 0x40, 0x45, 0x64, 0x33, 0x01,
+ 0x6b, 0x84, 0xa5, 0x9b, 0xec, 0x66, 0x19, 0xa1,
+ 0xc6, 0xc0, 0xb3, 0x7d, 0xd1, 0x45, 0x0e, 0xd4,
+ 0xf2, 0xd8, 0xb5, 0x84, 0x41, 0x0c, 0xed, 0xa8,
+ 0x02, 0x5f, 0x5d, 0x2d, 0x8d, 0xd0, 0xd2, 0x17,
+ 0x6f, 0xc1, 0xcf, 0x2c, 0xc0, 0x6f, 0xa8, 0xc8,
+ 0x2b, 0xed, 0x4d, 0x94, 0x4e, 0x71, 0x33, 0x9e,
+ 0xce, 0x78, 0x0f, 0xd0, 0x25, 0xbd, 0x41, 0xec,
+ 0x34, 0xeb, 0xff, 0x9d, 0x42, 0x70, 0xa3, 0x22,
+ 0x4e, 0x01, 0x9f, 0xcb, 0x44, 0x44, 0x74, 0xd4,
+ 0x82, 0xfd, 0x2d, 0xbe, 0x75, 0xef, 0xb2, 0x03,
+ 0x89, 0xcc, 0x10, 0xcd, 0x60, 0x0a, 0xbb, 0x54,
+ 0xc4, 0x7e, 0xde, 0x93, 0xe0, 0x8c, 0x11, 0x4e,
+ 0xdb, 0x04, 0x11, 0x7d, 0x71, 0x4d, 0xc1, 0xd5,
+ 0x25, 0xe1, 0x1b, 0xed, 0x87, 0x56, 0x19, 0x2f,
+ 0x92, 0x9d, 0x15, 0x46, 0x2b, 0x93, 0x9f, 0xf3,
+ 0xf5, 0x2f, 0x22, 0x52, 0xda, 0x2e, 0xd6, 0x4d,
+ 0x8f, 0xae, 0x88, 0x81, 0x8b, 0x1e, 0xfa, 0x2c,
+ 0x7b, 0x08, 0xc8, 0x79, 0x4f, 0xb1, 0xb2, 0x14,
+ 0xaa, 0x23, 0x3d, 0xb3, 0x16, 0x28, 0x33, 0x14,
+ 0x1e, 0xa4, 0x38, 0x3f, 0x1a, 0x6f, 0x12, 0x0b,
+ 0xe1, 0xdb, 0x82, 0xce, 0x36, 0x30, 0xb3, 0x42,
+ 0x91, 0x14, 0x46, 0x31, 0x57, 0xa6, 0x4e, 0x91,
+ 0x23, 0x4d, 0x47, 0x5e, 0x2f, 0x79, 0xcb, 0xf0,
+ 0x5e, 0x4d, 0xb6, 0xa9, 0x40, 0x7d, 0x72, 0xc6,
+ 0xbf, 0xf7, 0xd1, 0x19, 0x8b, 0x5c, 0x4d, 0x6a,
+ 0xad, 0x28, 0x31, 0xdb, 0x61, 0x27, 0x49, 0x93,
+ 0x71, 0x5a, 0x01, 0x82, 0xc7, 0xdc, 0x80, 0x89,
+ 0xe3, 0x2c, 0x85, 0x31, 0xde, 0xed, 0x4f, 0x74,
+ 0x31, 0xc0, 0x7c, 0x02, 0x19, 0x5e, 0xba, 0x2e,
+ 0xf9, 0x1e, 0xfb, 0x56, 0x13, 0xc3, 0x7a, 0xf7,
+ 0xae, 0x0c, 0x06, 0x6b, 0xab, 0xc6, 0x93, 0x69,
+ 0x70, 0x0e, 0x1d, 0xd2, 0x6e, 0xdd, 0xc0, 0xd2,
+ 0x16, 0xc7, 0x81, 0xd5, 0x6e, 0x4c, 0xe4, 0x7e,
+ 0x33, 0x03, 0xfa, 0x73, 0x00, 0x7f, 0xf7, 0xb9,
+ 0x49, 0xef, 0x23, 0xbe, 0x2a, 0xa4, 0xdb, 0xf2,
+ 0x52, 0x06, 0xfe, 0x45, 0xc2, 0x0d, 0xd8, 0x88,
+ 0x39, 0x5b, 0x25, 0x26, 0x39, 0x1a, 0x72, 0x49,
+ 0x96, 0xa4, 0x41, 0x56, 0xbe, 0xac, 0x80, 0x82,
+ 0x12, 0x85, 0x87, 0x92, 0xbf, 0x8e, 0x74, 0xcb,
+ 0xa4, 0x9d, 0xee, 0x5e, 0x88, 0x12, 0xe0, 0x19,
+ 0xda, 0x87, 0x45, 0x4b, 0xff, 0x9e, 0x84, 0x7e,
+ 0xd8, 0x3d, 0xb0, 0x7a, 0xf3, 0x13, 0x74, 0x30,
+ 0x82, 0xf8, 0x80, 0xa2, 0x78, 0xf6, 0x82, 0xc2,
+ 0xbd, 0x0a, 0xd6, 0x88, 0x7c, 0xb5, 0x9f, 0x65,
+ 0x2e, 0x15, 0x59, 0x87, 0xd6, 0x1b, 0xbf, 0x6a,
+ 0x88, 0xd3, 0x6e, 0xe9, 0x3b, 0x60, 0x72, 0xe6,
+ 0x65, 0x6d, 0x9c, 0xcb, 0xaa, 0xe3, 0xd6, 0x55,
+ 0x85, 0x2e, 0x38, 0xde, 0xb3, 0xa2, 0xdc, 0xf8,
+ 0x05, 0x8d, 0xc9, 0xfb, 0x6f, 0x2a, 0xb3, 0xd3,
+ 0xb3, 0x53, 0x9e, 0xb7, 0x7b, 0x24, 0x8a, 0x66,
+ 0x10, 0x91, 0xd0, 0x5e, 0xb6, 0xe2, 0xf2, 0x97,
+ 0x77, 0x4f, 0xe6, 0x05, 0x35, 0x98, 0x45, 0x7c,
+ 0xc6, 0x19, 0x08, 0x31, 0x8d, 0xe4, 0xb8, 0x26,
+ 0xf0, 0xfc, 0x86, 0xd4, 0xbb, 0x11, 0x7d, 0x33,
+ 0xe8, 0x65, 0xaa, 0x80, 0x50, 0x09, 0xcc, 0x29,
+ 0x18, 0xd9, 0xc2, 0xf8, 0x40, 0xc4, 0xda, 0x43,
+ 0xa7, 0x03, 0xad, 0x9f, 0x5b, 0x58, 0x06, 0x16,
+ 0x3d, 0x71, 0x61, 0x69, 0x6b, 0x5a, 0x0a, 0xdc,
+ 0x00, 0x00, 0x00, 0x05,
+ 0xd5, 0xc0, 0xd1, 0xbe, 0xbb, 0x06, 0x04, 0x8e,
+ 0xd6, 0xfe, 0x2e, 0xf2, 0xc6, 0xce, 0xf3, 0x05,
+ 0xb3, 0xed, 0x63, 0x39, 0x41, 0xeb, 0xc8, 0xb3,
+ 0xbe, 0xc9, 0x73, 0x87, 0x54, 0xcd, 0xdd, 0x60,
+ 0xe1, 0x92, 0x0a, 0xda, 0x52, 0xf4, 0x3d, 0x05,
+ 0x5b, 0x50, 0x31, 0xce, 0xe6, 0x19, 0x25, 0x20,
+ 0xd6, 0xa5, 0x11, 0x55, 0x14, 0x85, 0x1c, 0xe7,
+ 0xfd, 0x44, 0x8d, 0x4a, 0x39, 0xfa, 0xe2, 0xab,
+ 0x23, 0x35, 0xb5, 0x25, 0xf4, 0x84, 0xe9, 0xb4,
+ 0x0d, 0x6a, 0x4a, 0x96, 0x93, 0x94, 0x84, 0x3b,
+ 0xdc, 0xf6, 0xd1, 0x4c, 0x48, 0xe8, 0x01, 0x5e,
+ 0x08, 0xab, 0x92, 0x66, 0x2c, 0x05, 0xc6, 0xe9,
+ 0xf9, 0x0b, 0x65, 0xa7, 0xa6, 0x20, 0x16, 0x89,
+ 0x99, 0x9f, 0x32, 0xbf, 0xd3, 0x68, 0xe5, 0xe3,
+ 0xec, 0x9c, 0xb7, 0x0a, 0xc7, 0xb8, 0x39, 0x90,
+ 0x03, 0xf1, 0x75, 0xc4, 0x08, 0x85, 0x08, 0x1a,
+ 0x09, 0xab, 0x30, 0x34, 0x91, 0x1f, 0xe1, 0x25,
+ 0x63, 0x10, 0x51, 0xdf, 0x04, 0x08, 0xb3, 0x94,
+ 0x6b, 0x0b, 0xde, 0x79, 0x09, 0x11, 0xe8, 0x97,
+ 0x8b, 0xa0, 0x7d, 0xd5, 0x6c, 0x73, 0xe7, 0xee,
+};
+
+/* Test Case 2 Public Key */
+
+static uint8_t tc2_key[] = {
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x03,
+ 0xd0, 0x8f, 0xab, 0xd4, 0xa2, 0x09, 0x1f, 0xf0,
+ 0xa8, 0xcb, 0x4e, 0xd8, 0x34, 0xe7, 0x45, 0x34,
+ 0x32, 0xa5, 0x88, 0x85, 0xcd, 0x9b, 0xa0, 0x43,
+ 0x12, 0x35, 0x46, 0x6b, 0xff, 0x96, 0x51, 0xc6,
+ 0xc9, 0x21, 0x24, 0x40, 0x4d, 0x45, 0xfa, 0x53,
+ 0xcf, 0x16, 0x1c, 0x28, 0xf1, 0xad, 0x5a, 0x8e,
+};
+
+/* Test Case 2 Message */
+
+static uint8_t tc2_msg[] = {
+ 0x54, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x75, 0x6d,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43,
+ 0x6f, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74,
+ 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x6f, 0x66, 0x20,
+ 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2c, 0x20,
+ 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x20, 0x6e, 0x6f,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6f, 0x6e,
+ 0x73, 0x74, 0x72, 0x75, 0x65, 0x64, 0x20, 0x74,
+ 0x6f, 0x20, 0x64, 0x65, 0x6e, 0x79, 0x20, 0x6f,
+ 0x72, 0x20, 0x64, 0x69, 0x73, 0x70, 0x61, 0x72,
+ 0x61, 0x67, 0x65, 0x20, 0x6f, 0x74, 0x68, 0x65,
+ 0x72, 0x73, 0x20, 0x72, 0x65, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x70, 0x65, 0x6f, 0x70, 0x6c,
+ 0x65, 0x2e, 0x0a,
+};
+
+/* Test Case 2 Signature */
+/* 2 levels: h=10, w=4; h=5, w=8 */
+
+static uint8_t tc2_sig[] = {
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x03,
+ 0x3d, 0x46, 0xbe, 0xe8, 0x66, 0x0f, 0x8f, 0x21,
+ 0x5d, 0x3f, 0x96, 0x40, 0x8a, 0x7a, 0x64, 0xcf,
+ 0x1c, 0x4d, 0xa0, 0x2b, 0x63, 0xa5, 0x5f, 0x62,
+ 0xc6, 0x66, 0xef, 0x57, 0x07, 0xa9, 0x14, 0xce,
+ 0x06, 0x74, 0xe8, 0xcb, 0x7a, 0x55, 0xf0, 0xc4,
+ 0x8d, 0x48, 0x4f, 0x31, 0xf3, 0xaa, 0x4a, 0xf9,
+ 0x71, 0x9a, 0x74, 0xf2, 0x2c, 0xf8, 0x23, 0xb9,
+ 0x44, 0x31, 0xd0, 0x1c, 0x92, 0x6e, 0x2a, 0x76,
+ 0xbb, 0x71, 0x22, 0x6d, 0x27, 0x97, 0x00, 0xec,
+ 0x81, 0xc9, 0xe9, 0x5f, 0xb1, 0x1a, 0x0d, 0x10,
+ 0xd0, 0x65, 0x27, 0x9a, 0x57, 0x96, 0xe2, 0x65,
+ 0xae, 0x17, 0x73, 0x7c, 0x44, 0xeb, 0x8c, 0x59,
+ 0x45, 0x08, 0xe1, 0x26, 0xa9, 0xa7, 0x87, 0x0b,
+ 0xf4, 0x36, 0x08, 0x20, 0xbd, 0xeb, 0x9a, 0x01,
+ 0xd9, 0x69, 0x37, 0x79, 0xe4, 0x16, 0x82, 0x8e,
+ 0x75, 0xbd, 0xdd, 0x7d, 0x8c, 0x70, 0xd5, 0x0a,
+ 0x0a, 0xc8, 0xba, 0x39, 0x81, 0x09, 0x09, 0xd4,
+ 0x45, 0xf4, 0x4c, 0xb5, 0xbb, 0x58, 0xde, 0x73,
+ 0x7e, 0x60, 0xcb, 0x43, 0x45, 0x30, 0x27, 0x86,
+ 0xef, 0x2c, 0x6b, 0x14, 0xaf, 0x21, 0x2c, 0xa1,
+ 0x9e, 0xde, 0xaa, 0x3b, 0xfc, 0xfe, 0x8b, 0xaa,
+ 0x66, 0x21, 0xce, 0x88, 0x48, 0x0d, 0xf2, 0x37,
+ 0x1d, 0xd3, 0x7a, 0xdd, 0x73, 0x2c, 0x9d, 0xe4,
+ 0xea, 0x2c, 0xe0, 0xdf, 0xfa, 0x53, 0xc9, 0x26,
+ 0x49, 0xa1, 0x8d, 0x39, 0xa5, 0x07, 0x88, 0xf4,
+ 0x65, 0x29, 0x87, 0xf2, 0x26, 0xa1, 0xd4, 0x81,
+ 0x68, 0x20, 0x5d, 0xf6, 0xae, 0x7c, 0x58, 0xe0,
+ 0x49, 0xa2, 0x5d, 0x49, 0x07, 0xed, 0xc1, 0xaa,
+ 0x90, 0xda, 0x8a, 0xa5, 0xe5, 0xf7, 0x67, 0x17,
+ 0x73, 0xe9, 0x41, 0xd8, 0x05, 0x53, 0x60, 0x21,
+ 0x5c, 0x6b, 0x60, 0xdd, 0x35, 0x46, 0x3c, 0xf2,
+ 0x24, 0x0a, 0x9c, 0x06, 0xd6, 0x94, 0xe9, 0xcb,
+ 0x54, 0xe7, 0xb1, 0xe1, 0xbf, 0x49, 0x4d, 0x0d,
+ 0x1a, 0x28, 0xc0, 0xd3, 0x1a, 0xcc, 0x75, 0x16,
+ 0x1f, 0x4f, 0x48, 0x5d, 0xfd, 0x3c, 0xb9, 0x57,
+ 0x8e, 0x83, 0x6e, 0xc2, 0xdc, 0x72, 0x2f, 0x37,
+ 0xed, 0x30, 0x87, 0x2e, 0x07, 0xf2, 0xb8, 0xbd,
+ 0x03, 0x74, 0xeb, 0x57, 0xd2, 0x2c, 0x61, 0x4e,
+ 0x09, 0x15, 0x0f, 0x6c, 0x0d, 0x87, 0x74, 0xa3,
+ 0x9a, 0x6e, 0x16, 0x82, 0x11, 0x03, 0x5d, 0xc5,
+ 0x29, 0x88, 0xab, 0x46, 0xea, 0xca, 0x9e, 0xc5,
+ 0x97, 0xfb, 0x18, 0xb4, 0x93, 0x6e, 0x66, 0xef,
+ 0x2f, 0x0d, 0xf2, 0x6e, 0x8d, 0x1e, 0x34, 0xda,
+ 0x28, 0xcb, 0xb3, 0xaf, 0x75, 0x23, 0x13, 0x72,
+ 0x0c, 0x7b, 0x34, 0x54, 0x34, 0xf7, 0x2d, 0x65,
+ 0x31, 0x43, 0x28, 0xbb, 0xb0, 0x30, 0xd0, 0xf0,
+ 0xf6, 0xd5, 0xe4, 0x7b, 0x28, 0xea, 0x91, 0x00,
+ 0x8f, 0xb1, 0x1b, 0x05, 0x01, 0x77, 0x05, 0xa8,
+ 0xbe, 0x3b, 0x2a, 0xdb, 0x83, 0xc6, 0x0a, 0x54,
+ 0xf9, 0xd1, 0xd1, 0xb2, 0xf4, 0x76, 0xf9, 0xe3,
+ 0x93, 0xeb, 0x56, 0x95, 0x20, 0x3d, 0x2b, 0xa6,
+ 0xad, 0x81, 0x5e, 0x6a, 0x11, 0x1e, 0xa2, 0x93,
+ 0xdc, 0xc2, 0x10, 0x33, 0xf9, 0x45, 0x3d, 0x49,
+ 0xc8, 0xe5, 0xa6, 0x38, 0x7f, 0x58, 0x8b, 0x1e,
+ 0xa4, 0xf7, 0x06, 0x21, 0x7c, 0x15, 0x1e, 0x05,
+ 0xf5, 0x5a, 0x6e, 0xb7, 0x99, 0x7b, 0xe0, 0x9d,
+ 0x56, 0xa3, 0x26, 0xa3, 0x2f, 0x9c, 0xba, 0x1f,
+ 0xbe, 0x1c, 0x07, 0xbb, 0x49, 0xfa, 0x04, 0xce,
+ 0xcf, 0x9d, 0xf1, 0xa1, 0xb8, 0x15, 0x48, 0x3c,
+ 0x75, 0xd7, 0xa2, 0x7c, 0xc8, 0x8a, 0xd1, 0xb1,
+ 0x23, 0x8e, 0x5e, 0xa9, 0x86, 0xb5, 0x3e, 0x08,
+ 0x70, 0x45, 0x72, 0x3c, 0xe1, 0x61, 0x87, 0xed,
+ 0xa2, 0x2e, 0x33, 0xb2, 0xc7, 0x07, 0x09, 0xe5,
+ 0x32, 0x51, 0x02, 0x5a, 0xbd, 0xe8, 0x93, 0x96,
+ 0x45, 0xfc, 0x8c, 0x06, 0x93, 0xe9, 0x77, 0x63,
+ 0x92, 0x8f, 0x00, 0xb2, 0xe3, 0xc7, 0x5a, 0xf3,
+ 0x94, 0x2d, 0x8d, 0xda, 0xee, 0x81, 0xb5, 0x9a,
+ 0x6f, 0x1f, 0x67, 0xef, 0xda, 0x0e, 0xf8, 0x1d,
+ 0x11, 0x87, 0x3b, 0x59, 0x13, 0x7f, 0x67, 0x80,
+ 0x0b, 0x35, 0xe8, 0x1b, 0x01, 0x56, 0x3d, 0x18,
+ 0x7c, 0x4a, 0x15, 0x75, 0xa1, 0xac, 0xb9, 0x2d,
+ 0x08, 0x7b, 0x51, 0x7a, 0x88, 0x33, 0x38, 0x3f,
+ 0x05, 0xd3, 0x57, 0xef, 0x46, 0x78, 0xde, 0x0c,
+ 0x57, 0xff, 0x9f, 0x1b, 0x2d, 0xa6, 0x1d, 0xfd,
+ 0xe5, 0xd8, 0x83, 0x18, 0xbc, 0xdd, 0xe4, 0xd9,
+ 0x06, 0x1c, 0xc7, 0x5c, 0x2d, 0xe3, 0xcd, 0x47,
+ 0x40, 0xdd, 0x77, 0x39, 0xca, 0x3e, 0xf6, 0x6f,
+ 0x19, 0x30, 0x02, 0x6f, 0x47, 0xd9, 0xeb, 0xaa,
+ 0x71, 0x3b, 0x07, 0x17, 0x6f, 0x76, 0xf9, 0x53,
+ 0xe1, 0xc2, 0xe7, 0xf8, 0xf2, 0x71, 0xa6, 0xca,
+ 0x37, 0x5d, 0xbf, 0xb8, 0x3d, 0x71, 0x9b, 0x16,
+ 0x35, 0xa7, 0xd8, 0xa1, 0x38, 0x91, 0x95, 0x79,
+ 0x44, 0xb1, 0xc2, 0x9b, 0xb1, 0x01, 0x91, 0x3e,
+ 0x16, 0x6e, 0x11, 0xbd, 0x5f, 0x34, 0x18, 0x6f,
+ 0xa6, 0xc0, 0xa5, 0x55, 0xc9, 0x02, 0x6b, 0x25,
+ 0x6a, 0x68, 0x60, 0xf4, 0x86, 0x6b, 0xd6, 0xd0,
+ 0xb5, 0xbf, 0x90, 0x62, 0x70, 0x86, 0xc6, 0x14,
+ 0x91, 0x33, 0xf8, 0x28, 0x2c, 0xe6, 0xc9, 0xb3,
+ 0x62, 0x24, 0x42, 0x44, 0x3d, 0x5e, 0xca, 0x95,
+ 0x9d, 0x6c, 0x14, 0xca, 0x83, 0x89, 0xd1, 0x2c,
+ 0x40, 0x68, 0xb5, 0x03, 0xe4, 0xe3, 0xc3, 0x9b,
+ 0x63, 0x5b, 0xea, 0x24, 0x5d, 0x9d, 0x05, 0xa2,
+ 0x55, 0x8f, 0x24, 0x9c, 0x96, 0x61, 0xc0, 0x42,
+ 0x7d, 0x2e, 0x48, 0x9c, 0xa5, 0xb5, 0xdd, 0xe2,
+ 0x20, 0xa9, 0x03, 0x33, 0xf4, 0x86, 0x2a, 0xec,
+ 0x79, 0x32, 0x23, 0xc7, 0x81, 0x99, 0x7d, 0xa9,
+ 0x82, 0x66, 0xc1, 0x2c, 0x50, 0xea, 0x28, 0xb2,
+ 0xc4, 0x38, 0xe7, 0xa3, 0x79, 0xeb, 0x10, 0x6e,
+ 0xca, 0x0c, 0x7f, 0xd6, 0x00, 0x6e, 0x9b, 0xf6,
+ 0x12, 0xf3, 0xea, 0x0a, 0x45, 0x4b, 0xa3, 0xbd,
+ 0xb7, 0x6e, 0x80, 0x27, 0x99, 0x2e, 0x60, 0xde,
+ 0x01, 0xe9, 0x09, 0x4f, 0xdd, 0xeb, 0x33, 0x49,
+ 0x88, 0x39, 0x14, 0xfb, 0x17, 0xa9, 0x62, 0x1a,
+ 0xb9, 0x29, 0xd9, 0x70, 0xd1, 0x01, 0xe4, 0x5f,
+ 0x82, 0x78, 0xc1, 0x4b, 0x03, 0x2b, 0xca, 0xb0,
+ 0x2b, 0xd1, 0x56, 0x92, 0xd2, 0x1b, 0x6c, 0x5c,
+ 0x20, 0x4a, 0xbb, 0xf0, 0x77, 0xd4, 0x65, 0x55,
+ 0x3b, 0xd6, 0xed, 0xa6, 0x45, 0xe6, 0xc3, 0x06,
+ 0x5d, 0x33, 0xb1, 0x0d, 0x51, 0x8a, 0x61, 0xe1,
+ 0x5e, 0xd0, 0xf0, 0x92, 0xc3, 0x22, 0x26, 0x28,
+ 0x1a, 0x29, 0xc8, 0xa0, 0xf5, 0x0c, 0xde, 0x0a,
+ 0x8c, 0x66, 0x23, 0x6e, 0x29, 0xc2, 0xf3, 0x10,
+ 0xa3, 0x75, 0xce, 0xbd, 0xa1, 0xdc, 0x6b, 0xb9,
+ 0xa1, 0xa0, 0x1d, 0xae, 0x6c, 0x7a, 0xba, 0x8e,
+ 0xbe, 0xdc, 0x63, 0x71, 0xa7, 0xd5, 0x2a, 0xac,
+ 0xb9, 0x55, 0xf8, 0x3b, 0xd6, 0xe4, 0xf8, 0x4d,
+ 0x29, 0x49, 0xdc, 0xc1, 0x98, 0xfb, 0x77, 0xc7,
+ 0xe5, 0xcd, 0xf6, 0x04, 0x0b, 0x0f, 0x84, 0xfa,
+ 0xf8, 0x28, 0x08, 0xbf, 0x98, 0x55, 0x77, 0xf0,
+ 0xa2, 0xac, 0xf2, 0xec, 0x7e, 0xd7, 0xc0, 0xb0,
+ 0xae, 0x8a, 0x27, 0x0e, 0x95, 0x17, 0x43, 0xff,
+ 0x23, 0xe0, 0xb2, 0xdd, 0x12, 0xe9, 0xc3, 0xc8,
+ 0x28, 0xfb, 0x55, 0x98, 0xa2, 0x24, 0x61, 0xaf,
+ 0x94, 0xd5, 0x68, 0xf2, 0x92, 0x40, 0xba, 0x28,
+ 0x20, 0xc4, 0x59, 0x1f, 0x71, 0xc0, 0x88, 0xf9,
+ 0x6e, 0x09, 0x5d, 0xd9, 0x8b, 0xea, 0xe4, 0x56,
+ 0x57, 0x9e, 0xbb, 0xba, 0x36, 0xf6, 0xd9, 0xca,
+ 0x26, 0x13, 0xd1, 0xc2, 0x6e, 0xee, 0x4d, 0x8c,
+ 0x73, 0x21, 0x7a, 0xc5, 0x96, 0x2b, 0x5f, 0x31,
+ 0x47, 0xb4, 0x92, 0xe8, 0x83, 0x15, 0x97, 0xfd,
+ 0x89, 0xb6, 0x4a, 0xa7, 0xfd, 0xe8, 0x2e, 0x19,
+ 0x74, 0xd2, 0xf6, 0x77, 0x95, 0x04, 0xdc, 0x21,
+ 0x43, 0x5e, 0xb3, 0x10, 0x93, 0x50, 0x75, 0x6b,
+ 0x9f, 0xda, 0xbe, 0x1c, 0x6f, 0x36, 0x80, 0x81,
+ 0xbd, 0x40, 0xb2, 0x7e, 0xbc, 0xb9, 0x81, 0x9a,
+ 0x75, 0xd7, 0xdf, 0x8b, 0xb0, 0x7b, 0xb0, 0x5d,
+ 0xb1, 0xba, 0xb7, 0x05, 0xa4, 0xb7, 0xe3, 0x71,
+ 0x25, 0x18, 0x63, 0x39, 0x46, 0x4a, 0xd8, 0xfa,
+ 0xaa, 0x4f, 0x05, 0x2c, 0xc1, 0x27, 0x29, 0x19,
+ 0xfd, 0xe3, 0xe0, 0x25, 0xbb, 0x64, 0xaa, 0x8e,
+ 0x0e, 0xb1, 0xfc, 0xbf, 0xcc, 0x25, 0xac, 0xb5,
+ 0xf7, 0x18, 0xce, 0x4f, 0x7c, 0x21, 0x82, 0xfb,
+ 0x39, 0x3a, 0x18, 0x14, 0xb0, 0xe9, 0x42, 0x49,
+ 0x0e, 0x52, 0xd3, 0xbc, 0xa8, 0x17, 0xb2, 0xb2,
+ 0x6e, 0x90, 0xd4, 0xc9, 0xb0, 0xcc, 0x38, 0x60,
+ 0x8a, 0x6c, 0xef, 0x5e, 0xb1, 0x53, 0xaf, 0x08,
+ 0x58, 0xac, 0xc8, 0x67, 0xc9, 0x92, 0x2a, 0xed,
+ 0x43, 0xbb, 0x67, 0xd7, 0xb3, 0x3a, 0xcc, 0x51,
+ 0x93, 0x13, 0xd2, 0x8d, 0x41, 0xa5, 0xc6, 0xfe,
+ 0x6c, 0xf3, 0x59, 0x5d, 0xd5, 0xee, 0x63, 0xf0,
+ 0xa4, 0xc4, 0x06, 0x5a, 0x08, 0x35, 0x90, 0xb2,
+ 0x75, 0x78, 0x8b, 0xee, 0x7a, 0xd8, 0x75, 0xa7,
+ 0xf8, 0x8d, 0xd7, 0x37, 0x20, 0x70, 0x8c, 0x6c,
+ 0x6c, 0x0e, 0xcf, 0x1f, 0x43, 0xbb, 0xaa, 0xda,
+ 0xe6, 0xf2, 0x08, 0x55, 0x7f, 0xdc, 0x07, 0xbd,
+ 0x4e, 0xd9, 0x1f, 0x88, 0xce, 0x4c, 0x0d, 0xe8,
+ 0x42, 0x76, 0x1c, 0x70, 0xc1, 0x86, 0xbf, 0xda,
+ 0xfa, 0xfc, 0x44, 0x48, 0x34, 0xbd, 0x34, 0x18,
+ 0xbe, 0x42, 0x53, 0xa7, 0x1e, 0xaf, 0x41, 0xd7,
+ 0x18, 0x75, 0x3a, 0xd0, 0x77, 0x54, 0xca, 0x3e,
+ 0xff, 0xd5, 0x96, 0x0b, 0x03, 0x36, 0x98, 0x17,
+ 0x95, 0x72, 0x14, 0x26, 0x80, 0x35, 0x99, 0xed,
+ 0x5b, 0x2b, 0x75, 0x16, 0x92, 0x0e, 0xfc, 0xbe,
+ 0x32, 0xad, 0xa4, 0xbc, 0xf6, 0xc7, 0x3b, 0xd2,
+ 0x9e, 0x3f, 0xa1, 0x52, 0xd9, 0xad, 0xec, 0xa3,
+ 0x60, 0x20, 0xfd, 0xee, 0xee, 0x1b, 0x73, 0x95,
+ 0x21, 0xd3, 0xea, 0x8c, 0x0d, 0xa4, 0x97, 0x00,
+ 0x3d, 0xf1, 0x51, 0x38, 0x97, 0xb0, 0xf5, 0x47,
+ 0x94, 0xa8, 0x73, 0x67, 0x0b, 0x8d, 0x93, 0xbc,
+ 0xca, 0x2a, 0xe4, 0x7e, 0x64, 0x42, 0x4b, 0x74,
+ 0x23, 0xe1, 0xf0, 0x78, 0xd9, 0x55, 0x4b, 0xb5,
+ 0x23, 0x2c, 0xc6, 0xde, 0x8a, 0xae, 0x9b, 0x83,
+ 0xfa, 0x5b, 0x95, 0x10, 0xbe, 0xb3, 0x9c, 0xcf,
+ 0x4b, 0x4e, 0x1d, 0x9c, 0x0f, 0x19, 0xd5, 0xe1,
+ 0x7f, 0x58, 0xe5, 0xb8, 0x70, 0x5d, 0x9a, 0x68,
+ 0x37, 0xa7, 0xd9, 0xbf, 0x99, 0xcd, 0x13, 0x38,
+ 0x7a, 0xf2, 0x56, 0xa8, 0x49, 0x16, 0x71, 0xf1,
+ 0xf2, 0xf2, 0x2a, 0xf2, 0x53, 0xbc, 0xff, 0x54,
+ 0xb6, 0x73, 0x19, 0x9b, 0xdb, 0x7d, 0x05, 0xd8,
+ 0x10, 0x64, 0xef, 0x05, 0xf8, 0x0f, 0x01, 0x53,
+ 0xd0, 0xbe, 0x79, 0x19, 0x68, 0x4b, 0x23, 0xda,
+ 0x8d, 0x42, 0xff, 0x3e, 0xff, 0xdb, 0x7c, 0xa0,
+ 0x98, 0x50, 0x33, 0xf3, 0x89, 0x18, 0x1f, 0x47,
+ 0x65, 0x91, 0x38, 0x00, 0x3d, 0x71, 0x2b, 0x5e,
+ 0xc0, 0xa6, 0x14, 0xd3, 0x1c, 0xc7, 0x48, 0x7f,
+ 0x52, 0xde, 0x86, 0x64, 0x91, 0x6a, 0xf7, 0x9c,
+ 0x98, 0x45, 0x6b, 0x2c, 0x94, 0xa8, 0x03, 0x80,
+ 0x83, 0xdb, 0x55, 0x39, 0x1e, 0x34, 0x75, 0x86,
+ 0x22, 0x50, 0x27, 0x4a, 0x1d, 0xe2, 0x58, 0x4f,
+ 0xec, 0x97, 0x5f, 0xb0, 0x95, 0x36, 0x79, 0x2c,
+ 0xfb, 0xfc, 0xf6, 0x19, 0x28, 0x56, 0xcc, 0x76,
+ 0xeb, 0x5b, 0x13, 0xdc, 0x47, 0x09, 0xe2, 0xf7,
+ 0x30, 0x1d, 0xdf, 0xf2, 0x6e, 0xc1, 0xb2, 0x3d,
+ 0xe2, 0xd1, 0x88, 0xc9, 0x99, 0x16, 0x6c, 0x74,
+ 0xe1, 0xe1, 0x4b, 0xbc, 0x15, 0xf4, 0x57, 0xcf,
+ 0x4e, 0x47, 0x1a, 0xe1, 0x3d, 0xcb, 0xdd, 0x9c,
+ 0x50, 0xf4, 0xd6, 0x46, 0xfc, 0x62, 0x78, 0xe8,
+ 0xfe, 0x7e, 0xb6, 0xcb, 0x5c, 0x94, 0x10, 0x0f,
+ 0xa8, 0x70, 0x18, 0x73, 0x80, 0xb7, 0x77, 0xed,
+ 0x19, 0xd7, 0x86, 0x8f, 0xd8, 0xca, 0x7c, 0xeb,
+ 0x7f, 0xa7, 0xd5, 0xcc, 0x86, 0x1c, 0x5b, 0xda,
+ 0xc9, 0x8e, 0x74, 0x95, 0xeb, 0x0a, 0x2c, 0xee,
+ 0xc1, 0x92, 0x4a, 0xe9, 0x79, 0xf4, 0x4c, 0x53,
+ 0x90, 0xeb, 0xed, 0xdd, 0xc6, 0x5d, 0x6e, 0xc1,
+ 0x12, 0x87, 0xd9, 0x78, 0xb8, 0xdf, 0x06, 0x42,
+ 0x19, 0xbc, 0x56, 0x79, 0xf7, 0xd7, 0xb2, 0x64,
+ 0xa7, 0x6f, 0xf2, 0x72, 0xb2, 0xac, 0x9f, 0x2f,
+ 0x7c, 0xfc, 0x9f, 0xdc, 0xfb, 0x6a, 0x51, 0x42,
+ 0x82, 0x40, 0x02, 0x7a, 0xfd, 0x9d, 0x52, 0xa7,
+ 0x9b, 0x64, 0x7c, 0x90, 0xc2, 0x70, 0x9e, 0x06,
+ 0x0e, 0xd7, 0x0f, 0x87, 0x29, 0x9d, 0xd7, 0x98,
+ 0xd6, 0x8f, 0x4f, 0xad, 0xd3, 0xda, 0x6c, 0x51,
+ 0xd8, 0x39, 0xf8, 0x51, 0xf9, 0x8f, 0x67, 0x84,
+ 0x0b, 0x96, 0x4e, 0xbe, 0x73, 0xf8, 0xce, 0xc4,
+ 0x15, 0x72, 0x53, 0x8e, 0xc6, 0xbc, 0x13, 0x10,
+ 0x34, 0xca, 0x28, 0x94, 0xeb, 0x73, 0x6b, 0x3b,
+ 0xda, 0x93, 0xd9, 0xf5, 0xf6, 0xfa, 0x6f, 0x6c,
+ 0x0f, 0x03, 0xce, 0x43, 0x36, 0x2b, 0x84, 0x14,
+ 0x94, 0x03, 0x55, 0xfb, 0x54, 0xd3, 0xdf, 0xdd,
+ 0x03, 0x63, 0x3a, 0xe1, 0x08, 0xf3, 0xde, 0x3e,
+ 0xbc, 0x85, 0xa3, 0xff, 0x51, 0xef, 0xee, 0xa3,
+ 0xbc, 0x2c, 0xf2, 0x7e, 0x16, 0x58, 0xf1, 0x78,
+ 0x9e, 0xe6, 0x12, 0xc8, 0x3d, 0x0f, 0x5f, 0xd5,
+ 0x6f, 0x7c, 0xd0, 0x71, 0x93, 0x0e, 0x29, 0x46,
+ 0xbe, 0xee, 0xca, 0xa0, 0x4d, 0xcc, 0xea, 0x9f,
+ 0x97, 0x78, 0x60, 0x01, 0x47, 0x5e, 0x02, 0x94,
+ 0xbc, 0x28, 0x52, 0xf6, 0x2e, 0xb5, 0xd3, 0x9b,
+ 0xb9, 0xfb, 0xee, 0xf7, 0x59, 0x16, 0xef, 0xe4,
+ 0x4a, 0x66, 0x2e, 0xca, 0xe3, 0x7e, 0xde, 0x27,
+ 0xe9, 0xd6, 0xea, 0xdf, 0xde, 0xb8, 0xf8, 0xb2,
+ 0xb2, 0xdb, 0xcc, 0xbf, 0x96, 0xfa, 0x6d, 0xba,
+ 0xf7, 0x32, 0x1f, 0xb0, 0xe7, 0x01, 0xf4, 0xd4,
+ 0x29, 0xc2, 0xf4, 0xdc, 0xd1, 0x53, 0xa2, 0x74,
+ 0x25, 0x74, 0x12, 0x6e, 0x5e, 0xac, 0xcc, 0x77,
+ 0x68, 0x6a, 0xcf, 0x6e, 0x3e, 0xe4, 0x8f, 0x42,
+ 0x37, 0x66, 0xe0, 0xfc, 0x46, 0x68, 0x10, 0xa9,
+ 0x05, 0xff, 0x54, 0x53, 0xec, 0x99, 0x89, 0x7b,
+ 0x56, 0xbc, 0x55, 0xdd, 0x49, 0xb9, 0x91, 0x14,
+ 0x2f, 0x65, 0x04, 0x3f, 0x2d, 0x74, 0x4e, 0xeb,
+ 0x93, 0x5b, 0xa7, 0xf4, 0xef, 0x23, 0xcf, 0x80,
+ 0xcc, 0x5a, 0x8a, 0x33, 0x5d, 0x36, 0x19, 0xd7,
+ 0x81, 0xe7, 0x45, 0x48, 0x26, 0xdf, 0x72, 0x0e,
+ 0xec, 0x82, 0xe0, 0x60, 0x34, 0xc4, 0x46, 0x99,
+ 0xb5, 0xf0, 0xc4, 0x4a, 0x87, 0x87, 0x75, 0x2e,
+ 0x05, 0x7f, 0xa3, 0x41, 0x9b, 0x5b, 0xb0, 0xe2,
+ 0x5d, 0x30, 0x98, 0x1e, 0x41, 0xcb, 0x13, 0x61,
+ 0x32, 0x2d, 0xba, 0x8f, 0x69, 0x93, 0x1c, 0xf4,
+ 0x2f, 0xad, 0x3f, 0x3b, 0xce, 0x6d, 0xed, 0x5b,
+ 0x8b, 0xfc, 0x3d, 0x20, 0xa2, 0x14, 0x88, 0x61,
+ 0xb2, 0xaf, 0xc1, 0x45, 0x62, 0xdd, 0xd2, 0x7f,
+ 0x12, 0x89, 0x7a, 0xbf, 0x06, 0x85, 0x28, 0x8d,
+ 0xcc, 0x5c, 0x49, 0x82, 0xf8, 0x26, 0x02, 0x68,
+ 0x46, 0xa2, 0x4b, 0xf7, 0x7e, 0x38, 0x3c, 0x7a,
+ 0xac, 0xab, 0x1a, 0xb6, 0x92, 0xb2, 0x9e, 0xd8,
+ 0xc0, 0x18, 0xa6, 0x5f, 0x3d, 0xc2, 0xb8, 0x7f,
+ 0xf6, 0x19, 0xa6, 0x33, 0xc4, 0x1b, 0x4f, 0xad,
+ 0xb1, 0xc7, 0x87, 0x25, 0xc1, 0xf8, 0xf9, 0x22,
+ 0xf6, 0x00, 0x97, 0x87, 0xb1, 0x96, 0x42, 0x47,
+ 0xdf, 0x01, 0x36, 0xb1, 0xbc, 0x61, 0x4a, 0xb5,
+ 0x75, 0xc5, 0x9a, 0x16, 0xd0, 0x89, 0x91, 0x7b,
+ 0xd4, 0xa8, 0xb6, 0xf0, 0x4d, 0x95, 0xc5, 0x81,
+ 0x27, 0x9a, 0x13, 0x9b, 0xe0, 0x9f, 0xcf, 0x6e,
+ 0x98, 0xa4, 0x70, 0xa0, 0xbc, 0xec, 0xa1, 0x91,
+ 0xfc, 0xe4, 0x76, 0xf9, 0x37, 0x00, 0x21, 0xcb,
+ 0xc0, 0x55, 0x18, 0xa7, 0xef, 0xd3, 0x5d, 0x89,
+ 0xd8, 0x57, 0x7c, 0x99, 0x0a, 0x5e, 0x19, 0x96,
+ 0x1b, 0xa1, 0x62, 0x03, 0xc9, 0x59, 0xc9, 0x18,
+ 0x29, 0xba, 0x74, 0x97, 0xcf, 0xfc, 0xbb, 0x4b,
+ 0x29, 0x45, 0x46, 0x45, 0x4f, 0xa5, 0x38, 0x8a,
+ 0x23, 0xa2, 0x2e, 0x80, 0x5a, 0x5c, 0xa3, 0x5f,
+ 0x95, 0x65, 0x98, 0x84, 0x8b, 0xda, 0x67, 0x86,
+ 0x15, 0xfe, 0xc2, 0x8a, 0xfd, 0x5d, 0xa6, 0x1a,
+ 0x00, 0x00, 0x00, 0x06,
+ 0xb3, 0x26, 0x49, 0x33, 0x13, 0x05, 0x3c, 0xed,
+ 0x38, 0x76, 0xdb, 0x9d, 0x23, 0x71, 0x48, 0x18,
+ 0x1b, 0x71, 0x73, 0xbc, 0x7d, 0x04, 0x2c, 0xef,
+ 0xb4, 0xdb, 0xe9, 0x4d, 0x2e, 0x58, 0xcd, 0x21,
+ 0xa7, 0x69, 0xdb, 0x46, 0x57, 0xa1, 0x03, 0x27,
+ 0x9b, 0xa8, 0xef, 0x3a, 0x62, 0x9c, 0xa8, 0x4e,
+ 0xe8, 0x36, 0x17, 0x2a, 0x9c, 0x50, 0xe5, 0x1f,
+ 0x45, 0x58, 0x17, 0x41, 0xcf, 0x80, 0x83, 0x15,
+ 0x0b, 0x49, 0x1c, 0xb4, 0xec, 0xbb, 0xab, 0xec,
+ 0x12, 0x8e, 0x7c, 0x81, 0xa4, 0x6e, 0x62, 0xa6,
+ 0x7b, 0x57, 0x64, 0x0a, 0x0a, 0x78, 0xbe, 0x1c,
+ 0xbf, 0x7d, 0xd9, 0xd4, 0x19, 0xa1, 0x0c, 0xd8,
+ 0x68, 0x6d, 0x16, 0x62, 0x1a, 0x80, 0x81, 0x6b,
+ 0xfd, 0xb5, 0xbd, 0xc5, 0x62, 0x11, 0xd7, 0x2c,
+ 0xa7, 0x0b, 0x81, 0xf1, 0x11, 0x7d, 0x12, 0x95,
+ 0x29, 0xa7, 0x57, 0x0c, 0xf7, 0x9c, 0xf5, 0x2a,
+ 0x70, 0x28, 0xa4, 0x85, 0x38, 0xec, 0xdd, 0x3b,
+ 0x38, 0xd3, 0xd5, 0xd6, 0x2d, 0x26, 0x24, 0x65,
+ 0x95, 0xc4, 0xfb, 0x73, 0xa5, 0x25, 0xa5, 0xed,
+ 0x2c, 0x30, 0x52, 0x4e, 0xbb, 0x1d, 0x8c, 0xc8,
+ 0x2e, 0x0c, 0x19, 0xbc, 0x49, 0x77, 0xc6, 0x89,
+ 0x8f, 0xf9, 0x5f, 0xd3, 0xd3, 0x10, 0xb0, 0xba,
+ 0xe7, 0x16, 0x96, 0xce, 0xf9, 0x3c, 0x6a, 0x55,
+ 0x24, 0x56, 0xbf, 0x96, 0xe9, 0xd0, 0x75, 0xe3,
+ 0x83, 0xbb, 0x75, 0x43, 0xc6, 0x75, 0x84, 0x2b,
+ 0xaf, 0xbf, 0xc7, 0xcd, 0xb8, 0x84, 0x83, 0xb3,
+ 0x27, 0x6c, 0x29, 0xd4, 0xf0, 0xa3, 0x41, 0xc2,
+ 0xd4, 0x06, 0xe4, 0x0d, 0x46, 0x53, 0xb7, 0xe4,
+ 0xd0, 0x45, 0x85, 0x1a, 0xcf, 0x6a, 0x0a, 0x0e,
+ 0xa9, 0xc7, 0x10, 0xb8, 0x05, 0xcc, 0xed, 0x46,
+ 0x35, 0xee, 0x8c, 0x10, 0x73, 0x62, 0xf0, 0xfc,
+ 0x8d, 0x80, 0xc1, 0x4d, 0x0a, 0xc4, 0x9c, 0x51,
+ 0x67, 0x03, 0xd2, 0x6d, 0x14, 0x75, 0x2f, 0x34,
+ 0xc1, 0xc0, 0xd2, 0xc4, 0x24, 0x75, 0x81, 0xc1,
+ 0x8c, 0x2c, 0xf4, 0xde, 0x48, 0xe9, 0xce, 0x94,
+ 0x9b, 0xe7, 0xc8, 0x88, 0xe9, 0xca, 0xeb, 0xe4,
+ 0xa4, 0x15, 0xe2, 0x91, 0xfd, 0x10, 0x7d, 0x21,
+ 0xdc, 0x1f, 0x08, 0x4b, 0x11, 0x58, 0x20, 0x82,
+ 0x49, 0xf2, 0x8f, 0x4f, 0x7c, 0x7e, 0x93, 0x1b,
+ 0xa7, 0xb3, 0xbd, 0x0d, 0x82, 0x4a, 0x45, 0x70,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x21, 0x5f, 0x83, 0xb7, 0xcc, 0xb9, 0xac, 0xbc,
+ 0xd0, 0x8d, 0xb9, 0x7b, 0x0d, 0x04, 0xdc, 0x2b,
+ 0xa1, 0xcd, 0x03, 0x58, 0x33, 0xe0, 0xe9, 0x00,
+ 0x59, 0x60, 0x3f, 0x26, 0xe0, 0x7a, 0xd2, 0xaa,
+ 0xd1, 0x52, 0x33, 0x8e, 0x7a, 0x5e, 0x59, 0x84,
+ 0xbc, 0xd5, 0xf7, 0xbb, 0x4e, 0xba, 0x40, 0xb7,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x0e, 0xb1, 0xed, 0x54, 0xa2, 0x46, 0x0d, 0x51,
+ 0x23, 0x88, 0xca, 0xd5, 0x33, 0x13, 0x8d, 0x24,
+ 0x05, 0x34, 0xe9, 0x7b, 0x1e, 0x82, 0xd3, 0x3b,
+ 0xd9, 0x27, 0xd2, 0x01, 0xdf, 0xc2, 0x4e, 0xbb,
+ 0x11, 0xb3, 0x64, 0x90, 0x23, 0x69, 0x6f, 0x85,
+ 0x15, 0x0b, 0x18, 0x9e, 0x50, 0xc0, 0x0e, 0x98,
+ 0x85, 0x0a, 0xc3, 0x43, 0xa7, 0x7b, 0x36, 0x38,
+ 0x31, 0x9c, 0x34, 0x7d, 0x73, 0x10, 0x26, 0x9d,
+ 0x3b, 0x77, 0x14, 0xfa, 0x40, 0x6b, 0x8c, 0x35,
+ 0xb0, 0x21, 0xd5, 0x4d, 0x4f, 0xda, 0xda, 0x7b,
+ 0x9c, 0xe5, 0xd4, 0xba, 0x5b, 0x06, 0x71, 0x9e,
+ 0x72, 0xaa, 0xf5, 0x8c, 0x5a, 0xae, 0x7a, 0xca,
+ 0x05, 0x7a, 0xa0, 0xe2, 0xe7, 0x4e, 0x7d, 0xcf,
+ 0xd1, 0x7a, 0x08, 0x23, 0x42, 0x9d, 0xb6, 0x29,
+ 0x65, 0xb7, 0xd5, 0x63, 0xc5, 0x7b, 0x4c, 0xec,
+ 0x94, 0x2c, 0xc8, 0x65, 0xe2, 0x9c, 0x1d, 0xad,
+ 0x83, 0xca, 0xc8, 0xb4, 0xd6, 0x1a, 0xac, 0xc4,
+ 0x57, 0xf3, 0x36, 0xe6, 0xa1, 0x0b, 0x66, 0x32,
+ 0x3f, 0x58, 0x87, 0xbf, 0x35, 0x23, 0xdf, 0xca,
+ 0xde, 0xe1, 0x58, 0x50, 0x3b, 0xfa, 0xa8, 0x9d,
+ 0xc6, 0xbf, 0x59, 0xda, 0xa8, 0x2a, 0xfd, 0x2b,
+ 0x5e, 0xbb, 0x2a, 0x9c, 0xa6, 0x57, 0x2a, 0x60,
+ 0x67, 0xce, 0xe7, 0xc3, 0x27, 0xe9, 0x03, 0x9b,
+ 0x3b, 0x6e, 0xa6, 0xa1, 0xed, 0xc7, 0xfd, 0xc3,
+ 0xdf, 0x92, 0x7a, 0xad, 0xe1, 0x0c, 0x1c, 0x9f,
+ 0x2d, 0x5f, 0xf4, 0x46, 0x45, 0x0d, 0x2a, 0x39,
+ 0x98, 0xd0, 0xf9, 0xf6, 0x20, 0x2b, 0x5e, 0x07,
+ 0xc3, 0xf9, 0x7d, 0x24, 0x58, 0xc6, 0x9d, 0x3c,
+ 0x81, 0x90, 0x64, 0x39, 0x78, 0xd7, 0xa7, 0xf4,
+ 0xd6, 0x4e, 0x97, 0xe3, 0xf1, 0xc4, 0xa0, 0x8a,
+ 0x7c, 0x5b, 0xc0, 0x3f, 0xd5, 0x56, 0x82, 0xc0,
+ 0x17, 0xe2, 0x90, 0x7e, 0xab, 0x07, 0xe5, 0xbb,
+ 0x2f, 0x19, 0x01, 0x43, 0x47, 0x5a, 0x60, 0x43,
+ 0xd5, 0xe6, 0xd5, 0x26, 0x34, 0x71, 0xf4, 0xee,
+ 0xcf, 0x6e, 0x25, 0x75, 0xfb, 0xc6, 0xff, 0x37,
+ 0xed, 0xfa, 0x24, 0x9d, 0x6c, 0xda, 0x1a, 0x09,
+ 0xf7, 0x97, 0xfd, 0x5a, 0x3c, 0xd5, 0x3a, 0x06,
+ 0x67, 0x00, 0xf4, 0x58, 0x63, 0xf0, 0x4b, 0x6c,
+ 0x8a, 0x58, 0xcf, 0xd3, 0x41, 0x24, 0x1e, 0x00,
+ 0x2d, 0x0d, 0x2c, 0x02, 0x17, 0x47, 0x2b, 0xf1,
+ 0x8b, 0x63, 0x6a, 0xe5, 0x47, 0xc1, 0x77, 0x13,
+ 0x68, 0xd9, 0xf3, 0x17, 0x83, 0x5c, 0x9b, 0x0e,
+ 0xf4, 0x30, 0xb3, 0xdf, 0x40, 0x34, 0xf6, 0xaf,
+ 0x00, 0xd0, 0xda, 0x44, 0xf4, 0xaf, 0x78, 0x00,
+ 0xbc, 0x7a, 0x5c, 0xf8, 0xa5, 0xab, 0xdb, 0x12,
+ 0xdc, 0x71, 0x8b, 0x55, 0x9b, 0x74, 0xca, 0xb9,
+ 0x09, 0x0e, 0x33, 0xcc, 0x58, 0xa9, 0x55, 0x30,
+ 0x09, 0x81, 0xc4, 0x20, 0xc4, 0xda, 0x8f, 0xfd,
+ 0x67, 0xdf, 0x54, 0x08, 0x90, 0xa0, 0x62, 0xfe,
+ 0x40, 0xdb, 0xa8, 0xb2, 0xc1, 0xc5, 0x48, 0xce,
+ 0xd2, 0x24, 0x73, 0x21, 0x9c, 0x53, 0x49, 0x11,
+ 0xd4, 0x8c, 0xca, 0xab, 0xfb, 0x71, 0xbc, 0x71,
+ 0x86, 0x2f, 0x4a, 0x24, 0xeb, 0xd3, 0x76, 0xd2,
+ 0x88, 0xfd, 0x4e, 0x6f, 0xb0, 0x6e, 0xd8, 0x70,
+ 0x57, 0x87, 0xc5, 0xfe, 0xdc, 0x81, 0x3c, 0xd2,
+ 0x69, 0x7e, 0x5b, 0x1a, 0xac, 0x1c, 0xed, 0x45,
+ 0x76, 0x7b, 0x14, 0xce, 0x88, 0x40, 0x9e, 0xae,
+ 0xbb, 0x60, 0x1a, 0x93, 0x55, 0x9a, 0xae, 0x89,
+ 0x3e, 0x14, 0x3d, 0x1c, 0x39, 0x5b, 0xc3, 0x26,
+ 0xda, 0x82, 0x1d, 0x79, 0xa9, 0xed, 0x41, 0xdc,
+ 0xfb, 0xe5, 0x49, 0x14, 0x7f, 0x71, 0xc0, 0x92,
+ 0xf4, 0xf3, 0xac, 0x52, 0x2b, 0x5c, 0xc5, 0x72,
+ 0x90, 0x70, 0x66, 0x50, 0x48, 0x7b, 0xae, 0x9b,
+ 0xb5, 0x67, 0x1e, 0xcc, 0x9c, 0xcc, 0x2c, 0xe5,
+ 0x1e, 0xad, 0x87, 0xac, 0x01, 0x98, 0x52, 0x68,
+ 0x52, 0x12, 0x22, 0xfb, 0x90, 0x57, 0xdf, 0x7e,
+ 0xd4, 0x18, 0x10, 0xb5, 0xef, 0x0d, 0x4f, 0x7c,
+ 0xc6, 0x73, 0x68, 0xc9, 0x0f, 0x57, 0x3b, 0x1a,
+ 0xc2, 0xce, 0x95, 0x6c, 0x36, 0x5e, 0xd3, 0x8e,
+ 0x89, 0x3c, 0xe7, 0xb2, 0xfa, 0xe1, 0x5d, 0x36,
+ 0x85, 0xa3, 0xdf, 0x2f, 0xa3, 0xd4, 0xcc, 0x09,
+ 0x8f, 0xa5, 0x7d, 0xd6, 0x0d, 0x2c, 0x97, 0x54,
+ 0xa8, 0xad, 0xe9, 0x80, 0xad, 0x0f, 0x93, 0xf6,
+ 0x78, 0x70, 0x75, 0xc3, 0xf6, 0x80, 0xa2, 0xba,
+ 0x19, 0x36, 0xa8, 0xc6, 0x1d, 0x1a, 0xf5, 0x2a,
+ 0xb7, 0xe2, 0x1f, 0x41, 0x6b, 0xe0, 0x9d, 0x2a,
+ 0x8d, 0x64, 0xc3, 0xd3, 0xd8, 0x58, 0x29, 0x68,
+ 0xc2, 0x83, 0x99, 0x02, 0x22, 0x9f, 0x85, 0xae,
+ 0xe2, 0x97, 0xe7, 0x17, 0xc0, 0x94, 0xc8, 0xdf,
+ 0x4a, 0x23, 0xbb, 0x5d, 0xb6, 0x58, 0xdd, 0x37,
+ 0x7b, 0xf0, 0xf4, 0xff, 0x3f, 0xfd, 0x8f, 0xba,
+ 0x5e, 0x38, 0x3a, 0x48, 0x57, 0x48, 0x02, 0xed,
+ 0x54, 0x5b, 0xbe, 0x7a, 0x6b, 0x47, 0x53, 0x53,
+ 0x33, 0x53, 0xd7, 0x37, 0x06, 0x06, 0x76, 0x40,
+ 0x13, 0x5a, 0x7c, 0xe5, 0x17, 0x27, 0x9c, 0xd6,
+ 0x83, 0x03, 0x97, 0x47, 0xd2, 0x18, 0x64, 0x7c,
+ 0x86, 0xe0, 0x97, 0xb0, 0xda, 0xa2, 0x87, 0x2d,
+ 0x54, 0xb8, 0xf3, 0xe5, 0x08, 0x59, 0x87, 0x62,
+ 0x95, 0x47, 0xb8, 0x30, 0xd8, 0x11, 0x81, 0x61,
+ 0xb6, 0x50, 0x79, 0xfe, 0x7b, 0xc5, 0x9a, 0x99,
+ 0xe9, 0xc3, 0xc7, 0x38, 0x0e, 0x3e, 0x70, 0xb7,
+ 0x13, 0x8f, 0xe5, 0xd9, 0xbe, 0x25, 0x51, 0x50,
+ 0x2b, 0x69, 0x8d, 0x09, 0xae, 0x19, 0x39, 0x72,
+ 0xf2, 0x7d, 0x40, 0xf3, 0x8d, 0xea, 0x26, 0x4a,
+ 0x01, 0x26, 0xe6, 0x37, 0xd7, 0x4a, 0xe4, 0xc9,
+ 0x2a, 0x62, 0x49, 0xfa, 0x10, 0x34, 0x36, 0xd3,
+ 0xeb, 0x0d, 0x40, 0x29, 0xac, 0x71, 0x2b, 0xfc,
+ 0x7a, 0x5e, 0xac, 0xbd, 0xd7, 0x51, 0x8d, 0x6d,
+ 0x4f, 0xe9, 0x03, 0xa5, 0xae, 0x65, 0x52, 0x7c,
+ 0xd6, 0x5b, 0xb0, 0xd4, 0xe9, 0x92, 0x5c, 0xa2,
+ 0x4f, 0xd7, 0x21, 0x4d, 0xc6, 0x17, 0xc1, 0x50,
+ 0x54, 0x4e, 0x42, 0x3f, 0x45, 0x0c, 0x99, 0xce,
+ 0x51, 0xac, 0x80, 0x05, 0xd3, 0x3a, 0xcd, 0x74,
+ 0xf1, 0xbe, 0xd3, 0xb1, 0x7b, 0x72, 0x66, 0xa4,
+ 0xa3, 0xbb, 0x86, 0xda, 0x7e, 0xba, 0x80, 0xb1,
+ 0x01, 0xe1, 0x5c, 0xb7, 0x9d, 0xe9, 0xa2, 0x07,
+ 0x85, 0x2c, 0xf9, 0x12, 0x49, 0xef, 0x48, 0x06,
+ 0x19, 0xff, 0x2a, 0xf8, 0xca, 0xbc, 0xa8, 0x31,
+ 0x25, 0xd1, 0xfa, 0xa9, 0x4c, 0xbb, 0x0a, 0x03,
+ 0xa9, 0x06, 0xf6, 0x83, 0xb3, 0xf4, 0x7a, 0x97,
+ 0xc8, 0x71, 0xfd, 0x51, 0x3e, 0x51, 0x0a, 0x7a,
+ 0x25, 0xf2, 0x83, 0xb1, 0x96, 0x07, 0x57, 0x78,
+ 0x49, 0x61, 0x52, 0xa9, 0x1c, 0x2b, 0xf9, 0xda,
+ 0x76, 0xeb, 0xe0, 0x89, 0xf4, 0x65, 0x48, 0x77,
+ 0xf2, 0xd5, 0x86, 0xae, 0x71, 0x49, 0xc4, 0x06,
+ 0xe6, 0x63, 0xea, 0xde, 0xb2, 0xb5, 0xc7, 0xe8,
+ 0x24, 0x29, 0xb9, 0xe8, 0xcb, 0x48, 0x34, 0xc8,
+ 0x34, 0x64, 0xf0, 0x79, 0x99, 0x53, 0x32, 0xe4,
+ 0xb3, 0xc8, 0xf5, 0xa7, 0x2b, 0xb4, 0xb8, 0xc6,
+ 0xf7, 0x4b, 0x0d, 0x45, 0xdc, 0x6c, 0x1f, 0x79,
+ 0x95, 0x2c, 0x0b, 0x74, 0x20, 0xdf, 0x52, 0x5e,
+ 0x37, 0xc1, 0x53, 0x77, 0xb5, 0xf0, 0x98, 0x43,
+ 0x19, 0xc3, 0x99, 0x39, 0x21, 0xe5, 0xcc, 0xd9,
+ 0x7e, 0x09, 0x75, 0x92, 0x06, 0x45, 0x30, 0xd3,
+ 0x3d, 0xe3, 0xaf, 0xad, 0x57, 0x33, 0xcb, 0xe7,
+ 0x70, 0x3c, 0x52, 0x96, 0x26, 0x3f, 0x77, 0x34,
+ 0x2e, 0xfb, 0xf5, 0xa0, 0x47, 0x55, 0xb0, 0xb3,
+ 0xc9, 0x97, 0xc4, 0x32, 0x84, 0x63, 0xe8, 0x4c,
+ 0xaa, 0x2d, 0xe3, 0xff, 0xdc, 0xd2, 0x97, 0xba,
+ 0xaa, 0xac, 0xd7, 0xae, 0x64, 0x6e, 0x44, 0xb5,
+ 0xc0, 0xf1, 0x60, 0x44, 0xdf, 0x38, 0xfa, 0xbd,
+ 0x29, 0x6a, 0x47, 0xb3, 0xa8, 0x38, 0xa9, 0x13,
+ 0x98, 0x2f, 0xb2, 0xe3, 0x70, 0xc0, 0x78, 0xed,
+ 0xb0, 0x42, 0xc8, 0x4d, 0xb3, 0x4c, 0xe3, 0x6b,
+ 0x46, 0xcc, 0xb7, 0x64, 0x60, 0xa6, 0x90, 0xcc,
+ 0x86, 0xc3, 0x02, 0x45, 0x7d, 0xd1, 0xcd, 0xe1,
+ 0x97, 0xec, 0x80, 0x75, 0xe8, 0x2b, 0x39, 0x3d,
+ 0x54, 0x20, 0x75, 0x13, 0x4e, 0x2a, 0x17, 0xee,
+ 0x70, 0xa5, 0xe1, 0x87, 0x07, 0x5d, 0x03, 0xae,
+ 0x3c, 0x85, 0x3c, 0xff, 0x60, 0x72, 0x9b, 0xa4,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x4d, 0xe1, 0xf6, 0x96, 0x5b, 0xda, 0xbc, 0x67,
+ 0x6c, 0x5a, 0x4d, 0xc7, 0xc3, 0x5f, 0x97, 0xf8,
+ 0x2c, 0xb0, 0xe3, 0x1c, 0x68, 0xd0, 0x4f, 0x1d,
+ 0xad, 0x96, 0x31, 0x4f, 0xf0, 0x9e, 0x6b, 0x3d,
+ 0xe9, 0x6a, 0xee, 0xe3, 0x00, 0xd1, 0xf6, 0x8b,
+ 0xf1, 0xbc, 0xa9, 0xfc, 0x58, 0xe4, 0x03, 0x23,
+ 0x36, 0xcd, 0x81, 0x9a, 0xaf, 0x57, 0x87, 0x44,
+ 0xe5, 0x0d, 0x13, 0x57, 0xa0, 0xe4, 0x28, 0x67,
+ 0x04, 0xd3, 0x41, 0xaa, 0x0a, 0x33, 0x7b, 0x19,
+ 0xfe, 0x4b, 0xc4, 0x3c, 0x2e, 0x79, 0x96, 0x4d,
+ 0x4f, 0x35, 0x10, 0x89, 0xf2, 0xe0, 0xe4, 0x1c,
+ 0x7c, 0x43, 0xae, 0x0d, 0x49, 0xe7, 0xf4, 0x04,
+ 0xb0, 0xf7, 0x5b, 0xe8, 0x0e, 0xa3, 0xaf, 0x09,
+ 0x8c, 0x97, 0x52, 0x42, 0x0a, 0x8a, 0xc0, 0xea,
+ 0x2b, 0xbb, 0x1f, 0x4e, 0xeb, 0xa0, 0x52, 0x38,
+ 0xae, 0xf0, 0xd8, 0xce, 0x63, 0xf0, 0xc6, 0xe5,
+ 0xe4, 0x04, 0x1d, 0x95, 0x39, 0x8a, 0x6f, 0x7f,
+ 0x3e, 0x0e, 0xe9, 0x7c, 0xc1, 0x59, 0x18, 0x49,
+ 0xd4, 0xed, 0x23, 0x63, 0x38, 0xb1, 0x47, 0xab,
+ 0xde, 0x9f, 0x51, 0xef, 0x9f, 0xd4, 0xe1, 0xc1,
+};
+
+typedef struct { const uint8_t *val; size_t len; } hashsig_tc_bn_t;
+typedef struct { hashsig_tc_bn_t key, msg, sig; } hashsig_tc_t;
+
+static const hashsig_tc_t hashsig_tc[] = {
+ { { tc1_key, sizeof(tc1_key) },
+ { tc1_msg, sizeof(tc1_msg) },
+ { tc1_sig, sizeof(tc1_sig) } },
+ { { tc2_key, sizeof(tc2_key) },
+ { tc2_msg, sizeof(tc2_msg) },
+ { tc2_sig, sizeof(tc2_sig) } },
+};
diff --git a/tests/test-pbkdf2.c b/tests/test-pbkdf2.c
index f3072a7..603a833 100644
--- a/tests/test-pbkdf2.c
+++ b/tests/test-pbkdf2.c
@@ -196,7 +196,7 @@ static int _test_pbkdf2(hal_core_t *core,
pbkdf2_tc_##_n_##_DK, sizeof(pbkdf2_tc_##_n_##_DK), \
pbkdf2_tc_##_n_##_count, #_n_)
-int main (int argc, char *argv[])
+int main(void)
{
hal_core_t *core = hal_core_find(SHA1_NAME, NULL);
int ok = 1;
diff --git a/tests/test-rpc_hashsig.c b/tests/test-rpc_hashsig.c
new file mode 100644
index 0000000..00728c3
--- /dev/null
+++ b/tests/test-rpc_hashsig.c
@@ -0,0 +1,594 @@
+/*
+ * test-rpc_hashsig.c
+ * ------------------
+ * Test code for RPC interface to Cryptech public key operations.
+ *
+ * Copyright (c) 2018, 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.
+ */
+
+/* Parts of this may eventually get folded into test-rpc_pkey.c,
+ * but for now I'd rather do it stand-alone.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <hal.h>
+#include <hashsig.h>
+#include "test-hashsig.h"
+
+#include <sys/time.h>
+/* not included in my glibc, sigh... */
+void timersub(struct timeval *a, struct timeval *b, struct timeval *res)
+{
+ res->tv_sec = a->tv_sec - b->tv_sec;
+ res->tv_usec = a->tv_usec - b->tv_usec;
+ if (res->tv_usec < 0) {
+ res->tv_usec += 1000000;
+ --res->tv_sec;
+ }
+ if (res->tv_usec > 1000000) {
+ res->tv_usec -= 1000000;
+ ++res->tv_sec;
+ }
+}
+
+static int debug = 0;
+static int info = 0;
+
+#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0)
+
+static int test_hashsig_testvec_local(const hashsig_tc_t * const tc, hal_key_flags_t flags)
+{
+ hal_error_t err;
+
+ assert(tc != NULL);
+
+ printf("Starting local hashsig test vector test\n");
+
+ uint8_t tc_keybuf[hal_hashsig_key_t_size];
+ hal_hashsig_key_t *tc_key = NULL;
+
+ if ((err = hal_hashsig_key_load_public_xdr(&tc_key,
+ tc_keybuf, sizeof(tc_keybuf),
+ tc->key.val, tc->key.len)) != HAL_OK)
+ lose("Could not load public key from test vector: %s\n", hal_error_string(err));
+
+ if ((err = hal_hashsig_verify(NULL, tc_key, tc->msg.val, tc->msg.len, tc->sig.val, tc->sig.len)) != HAL_OK)
+ lose("Verify failed: %s\n", hal_error_string(err));
+
+ printf("OK\n");
+ return 1;
+
+fail:
+ return 0;
+}
+
+static int test_hashsig_testvec_remote(const hashsig_tc_t * const tc, hal_key_flags_t flags)
+{
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ const hal_session_handle_t session = {HAL_HANDLE_NONE};
+ hal_pkey_handle_t public_key = {HAL_HANDLE_NONE};
+ hal_error_t err;
+ size_t len;
+
+ assert(tc != NULL);
+
+ {
+ flags |= HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
+
+ printf("Starting remote hashsig test vector test, flags 0x%lx\n", (unsigned long) flags);
+
+ uint8_t tc_keybuf[hal_hashsig_key_t_size];
+ hal_hashsig_key_t *tc_key = NULL;
+
+ if ((err = hal_hashsig_key_load_public_xdr(&tc_key,
+ tc_keybuf, sizeof(tc_keybuf),
+ tc->key.val, tc->key.len)) != HAL_OK)
+ lose("Could not load public key from test vector: %s\n", hal_error_string(err));
+
+ hal_uuid_t public_name;
+
+ uint8_t public_der[hal_hashsig_public_key_to_der_len(tc_key)];
+
+ if ((err = hal_hashsig_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));
+
+ assert(len == sizeof(public_der));
+
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, &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_verify(public_key, hal_hash_handle_none,
+ tc->msg.val, tc->msg.len, tc->sig.val, tc->sig.len)) != HAL_OK)
+ lose("Could not verify: %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 (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 void hexdump(const char * const label, const uint8_t * const buf, const size_t len)
+{
+ printf("%-11s ", label);
+
+ for (size_t i = 0; i < len; ++i) {
+ printf("%02x", buf[i]);
+ if ((i & 0x0f) == 0x0f) {
+ printf("\n");
+ if (i < len - 1)
+ printf(" ");
+ }
+ }
+ if ((len & 0x0f) != 0)
+ printf("\n");
+}
+
+static inline size_t lms_type_to_h(const lms_algorithm_t lms_type)
+{
+ switch (lms_type) {
+ case lms_sha256_n32_h5: return 5;
+ case lms_sha256_n32_h10: return 10;
+ case lms_sha256_n32_h15: return 15;
+ case lms_sha256_n32_h20: return 20;
+ case lms_sha256_n32_h25: return 25;
+ default: return 0;
+ }
+}
+
+static inline size_t lmots_type_to_w(const lmots_algorithm_t lmots_type)
+{
+ switch (lmots_type) {
+ case lmots_sha256_n32_w1: return 1;
+ case lmots_sha256_n32_w2: return 2;
+ case lmots_sha256_n32_w4: return 4;
+ case lmots_sha256_n32_w8: return 8;
+ default: return 0;
+ }
+}
+
+static inline size_t lmots_type_to_p(const lmots_algorithm_t lmots_type)
+{
+ switch (lmots_type) {
+ case lmots_sha256_n32_w1: return 265;
+ case lmots_sha256_n32_w2: return 133;
+ case lmots_sha256_n32_w4: return 67;
+ case lmots_sha256_n32_w8: return 34;
+ default: return 0;
+ }
+}
+
+#include <xdr_internal.h>
+
+static hal_error_t dump_hss_signature(const uint8_t * const sig, const size_t len)
+{
+ const uint8_t *sigptr = sig;
+ const uint8_t * const siglim = sig + len;
+ hal_error_t err;
+
+ hexdump("Nspk", sigptr, 4);
+ uint32_t Nspk;
+ if ((err = hal_xdr_decode_int(&sigptr, siglim, &Nspk)) != HAL_OK) return err;
+
+ for (size_t i = 0; i < Nspk + 1; ++i) {
+ printf("--------------------------------------------\nsig[%lu]\n", i);
+ hexdump("q", sigptr, 4); sigptr += 4;
+
+ {
+ hexdump("lmots type", sigptr, 4);
+ uint32_t lmots_type;
+ if ((err = hal_xdr_decode_int(&sigptr, siglim, &lmots_type)) != HAL_OK) return err;
+ hexdump("C", sigptr, 32); sigptr += 32;
+ size_t p = lmots_type_to_p((const lmots_algorithm_t)lmots_type);
+ for (size_t j = 0; j < p; ++j) {
+ char label[16];
+ sprintf(label, "y[%lu]", j);
+ hexdump(label, sigptr, 32); sigptr += 32;
+ }
+ }
+
+ hexdump("lms type", sigptr, 4);
+ uint32_t lms_type;
+ if ((err = hal_xdr_decode_int(&sigptr, siglim, &lms_type)) != HAL_OK) return err;
+ size_t h = lms_type_to_h((const lms_algorithm_t)lms_type);
+ for (size_t j = 0; j < h; ++j) {
+ char label[16];
+ sprintf(label, "path[%lu]", j);
+ hexdump(label, sigptr, 32); sigptr += 32;
+ }
+
+ if (i == Nspk)
+ break;
+
+ printf("--------------------------------------------\npubkey[%lu]\n", i + 1);
+ hexdump("lms type", sigptr, 4); sigptr += 4;
+ hexdump("lmots type", sigptr, 4); sigptr += 4;
+ hexdump("I", sigptr, 16); sigptr += 16;
+ hexdump("T[1]", sigptr, 32); sigptr += 32;
+ }
+
+ if (sigptr < siglim) {
+ printf("--------------------------------------------\nextra\n");
+ hexdump("", sigptr, siglim - sigptr);
+ }
+
+ return HAL_OK;
+}
+
+static int test_hashsig_sign(const size_t L,
+ const lms_algorithm_t lms_type,
+ const lmots_algorithm_t lmots_type,
+ size_t iterations,
+ int save, int keep)
+{
+ 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;
+
+ {
+ char save_name[16];
+ if (save) {
+ sprintf(save_name, "L%d.lms%d.ots%d", (int)L, (int)lms_type, (int)lmots_type);
+ FILE *fp;
+ if ((fp = fopen(save_name, "wb")) == NULL)
+ lose("Error opening %s: %s\n", save_name, strerror(errno));
+ size_t len1;
+ if ((len1 = fwrite(tc1_msg, 1, sizeof(tc1_msg), fp)) != sizeof(tc1_msg))
+ lose("Wrote %lu bytes to %s, expected %lu\n", len1, save_name, sizeof(tc1_msg));
+ if (fclose(fp) != 0)
+ lose("Error closing %s: %s\n", save_name, strerror(errno));
+ }
+
+ hal_key_flags_t flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN;
+
+ printf("Starting hashsig key test: L %lu, lms type %u (h=%lu), lmots type %u (w=%lu)\n",
+ L, lms_type, lms_type_to_h(lms_type), lmots_type, lmots_type_to_w(lmots_type));
+
+ if (info)
+ printf("Info: signature length %lu, lmots private key length %lu\n",
+ hal_hashsig_signature_len(L, lms_type, lmots_type),
+ hal_hashsig_lmots_private_key_len(lmots_type));
+
+ hal_uuid_t private_name, public_name;
+ struct timeval tv_start, tv_end, tv_diff;
+
+ size_t h = lms_type_to_h(lms_type);
+
+ if (info)
+ gettimeofday(&tv_start, NULL);
+ if ((err = hal_rpc_pkey_generate_hashsig(client, session, &private_key, &private_name,
+ L, lms_type, lmots_type, flags)) != HAL_OK)
+ lose("Could not generate hashsig private key: %s\n", hal_error_string(err));
+ if (info) {
+ gettimeofday(&tv_end, NULL);
+ timersub(&tv_end, &tv_start, &tv_diff);
+ long per_key = (tv_diff.tv_sec * 1000000 + tv_diff.tv_usec) / (L * (1 << h));
+ printf("Info: %ldm%ld.%03lds to generate key (%ld.%03lds per lmots key)\n",
+ tv_diff.tv_sec / 60, tv_diff.tv_sec % 60, tv_diff.tv_usec / 1000,
+ per_key / 1000000, (per_key % 1000000) / 1000);
+ }
+
+ uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)];
+
+ 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 private key: %s\n", hal_error_string(err));
+
+ assert(len == sizeof(public_der));
+
+ if ((err = hal_rpc_pkey_load(client, session, &public_key, &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 (save) {
+ char fn[strlen(save_name) + 5];
+ sprintf(fn, "%s.pub", save_name);
+ FILE *fp;
+ if ((fp = fopen(fn, "wb")) == NULL)
+ lose("Error opening %s: %s\n", fn, strerror(errno));
+ uint8_t pub[60];
+ if ((err = hal_hashsig_public_key_der_to_xdr(public_der, sizeof(public_der), pub, &len, sizeof(pub))) != HAL_OK)
+ lose("Could not XDR encode public key: %s\n", hal_error_string(err));
+ size_t len1;
+ if ((len1 = fwrite(pub, 1, len, fp)) != len)
+ lose("Wrote %lu bytes to %s, expected %lu\n", len1, fn, len);
+ if (fclose(fp) != 0)
+ lose("Error closing %s: %s\n", fn, strerror(errno));
+ }
+
+ if (iterations > 0) {
+ uint8_t sig[hal_hashsig_signature_len(L, lms_type, lmots_type)];
+
+ if (info)
+ gettimeofday(&tv_start, NULL);
+ int i;
+ for (i = 0; i < iterations; ++i) {
+ if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none,
+ tc1_msg, sizeof(tc1_msg), sig, &len, sizeof(sig))) == HAL_OK) {
+ assert(len == sizeof(sig));
+ if (debug) {
+ printf("Debug: received signature:\n");
+ dump_hss_signature(sig, len);
+ }
+ }
+ else {
+ if (i == (1 << (L * h)) && err == HAL_ERROR_HASHSIG_KEY_EXHAUSTED)
+ break;
+ else
+ lose("Could not sign (%d): %s\n", i, hal_error_string(err));
+ }
+ if (save) {
+ char fn[strlen(save_name) + 16];
+ sprintf(fn, "%s.%d.sig", save_name, i);
+ FILE *fp;
+ if ((fp = fopen(fn, "wb")) == NULL)
+ lose("Error opening %s: %s\n", fn, strerror(errno));
+ size_t len1;
+ if ((len1 = fwrite(sig, 1, len, fp)) != len)
+ lose("Wrote %lu bytes to %s, expected %lu\n", len1, fn, len);
+ if (fclose(fp) != 0)
+ lose("Error closing %s: %s\n", fn, strerror(errno));
+ }
+ }
+ if (info) {
+ gettimeofday(&tv_end, NULL);
+ timersub(&tv_end, &tv_start, &tv_diff);
+ long per_sig = (tv_diff.tv_sec * 1000000 + tv_diff.tv_usec) / i;
+ printf("Info: %ldm%ld.%03lds to generate %d signatures (%ld.%03lds per signature)\n",
+ tv_diff.tv_sec / 60, tv_diff.tv_sec % 60, tv_diff.tv_usec / 1000, i,
+ per_sig / 1000000, (per_sig % 1000000) / 1000);
+ }
+
+ if (info)
+ gettimeofday(&tv_start, NULL);
+ if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none,
+ tc1_msg, sizeof(tc1_msg), sig, len)) != HAL_OK)
+ lose("Could not verify: %s\n", hal_error_string(err));
+ if (info) {
+ gettimeofday(&tv_end, NULL);
+ timersub(&tv_end, &tv_start, &tv_diff);
+ printf("Info: %ldm%ld.%03lds to verify 1 signature\n",
+ tv_diff.tv_sec / 60, tv_diff.tv_sec % 60, tv_diff.tv_usec / 1000);
+ }
+ }
+
+ if (!keep) {
+ 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 read_sig(char *fn)
+{
+ {
+ FILE *fp;
+ if ((fp = fopen(fn, "rb")) == NULL)
+ lose("Error opening %s: %s\n", fn, strerror(errno));
+
+ struct stat statbuf;
+ if (stat(fn, &statbuf) != 0)
+ lose("Error statting %s: %s\n", fn, strerror(errno));
+
+ uint8_t sig[statbuf.st_size];
+ size_t len;
+ if ((len = fread(sig, 1, sizeof(sig), fp)) != sizeof(sig))
+ lose("Read %lu bytes from %s, expected %lu\n", len, fn, sizeof(sig));
+
+ if (fclose(fp) != 0)
+ lose("Error closing %s: %s\n", fn, strerror(errno));
+
+ hal_error_t err;
+ if ((err = dump_hss_signature(sig, len)) != HAL_OK)
+ lose("Error parsing signature: %s\n", hal_error_string(err));
+ }
+
+ return 1;
+fail:
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
+ char *pin = "fnord";
+ int do_default = 1;
+ int do_testvec = 0;
+ size_t iterations = 1;
+ size_t L_lo = 0, L_hi = 0;
+ size_t lms_lo = 5, lms_hi = 0;
+ size_t lmots_lo = 3, lmots_hi = 0;
+ int save = 0, keep = 0;
+ char *p;
+ hal_error_t err;
+ int ok = 1;
+
+char usage[] = "\
+Usage: %s [-d] [-i] [-p pin] [-t] [-L n] [-l n] [-o n] [-n n] [-s] [-r file]\n\
+ -d: enable debugging - hexdump signatures\n\
+ -i: enable informational messages - runtimes and signature lengths\n\
+ -p: user PIN\n\
+ -t: verify test vectors\n\
+ -L: number of levels in the HSS scheme (1..8)\n\
+ -l: LMS type (5..9)\n\
+ -o: LM-OTS type (1..4)\n\
+ -n: number of signatures to generate (0..'max')\n\
+ -s: save generated public key and signatures\n\
+ -k: keep (don't delete) the generated keys on the hsm\n\
+ -r: read and pretty-print a saved signature file\n\
+Numeric arguments can be a single number or a range, e.g. '1..4'\n";
+
+ int opt;
+ while ((opt = getopt(argc, argv, "ditp:L:l:o:n:skr:h?")) != -1) {
+ switch (opt) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'i':
+ info = 1;
+ break;
+ case 't':
+ do_testvec = 1;
+ do_default = 0;
+ break;
+ case 'p':
+ pin = optarg;
+ break;
+ case 'n':
+ if (strcmp(optarg, "max") == 0)
+ iterations = (size_t)-1;
+ else
+ iterations = (size_t)atoi(optarg);
+ do_default = 0;
+ break;
+ case 'L':
+ if ((p = strtok(optarg, ".")) != NULL)
+ L_lo = (size_t)atoi(p);
+ if ((p = strtok(NULL, ".")) != NULL)
+ L_hi = (size_t)atoi(p);
+ do_default = 0;
+ break;
+ case 'l':
+ if ((p = strtok(optarg, ".")) != NULL)
+ lms_lo = (size_t)atoi(p);
+ if ((p = strtok(NULL, ".")) != NULL)
+ lms_hi = (size_t)atoi(p);
+ do_default = 0;
+ break;
+ case 'o':
+ if ((p = strtok(optarg, ".")) != NULL)
+ lmots_lo = (size_t)atoi(p);
+ if ((p = strtok(NULL, ".")) != NULL)
+ lmots_hi = (size_t)atoi(p);
+ do_default = 0;
+ break;
+ case's':
+ save = 1;
+ break;
+ case 'k':
+ keep = 1;
+ break;
+ case 'r':
+ ok &= read_sig(optarg);
+ do_default = 0;
+ break;
+ case 'h':
+ case '?':
+ fprintf(stdout, usage, argv[0]);
+ exit(EXIT_SUCCESS);
+ default:
+ fprintf(stderr, usage, argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (do_default) {
+ do_testvec = 1;
+ L_lo = 1;
+ }
+
+ if (L_hi < L_lo) L_hi = L_lo;
+ if (lms_hi < lms_lo) lms_hi = lms_lo;
+ if (lmots_hi < lmots_lo) lmots_hi = lmots_lo;
+
+ 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));
+
+ if (do_testvec) {
+ for (int i = 0; i < (sizeof(hashsig_tc)/sizeof(*hashsig_tc)); i++)
+ ok &= test_hashsig_testvec_local(&hashsig_tc[i], 0);
+
+ for (int i = 0; i < (sizeof(hashsig_tc)/sizeof(*hashsig_tc)); i++)
+ for (int j = 0; j < 2; j++)
+ ok &= test_hashsig_testvec_remote(&hashsig_tc[i], j * HAL_KEY_FLAG_TOKEN);
+ }
+
+ /* signing/performance tests: run with -i */
+ /* A single test would be of the form '-L 2 -l 5 -o 3 -n 1' */
+ /* A range test of just keygen would be of the form '-o 1..4 -n 0' */
+ /* A test to key exhaustion would be of the form '-n max' */
+ if (L_lo > 0) {
+ for (size_t L = L_lo; L <= L_hi; ++L) {
+ for (lms_algorithm_t lms_type = lms_lo; lms_type <= lms_hi; ++lms_type) {
+ for (lmots_algorithm_t lmots_type = lmots_lo; lmots_type <= lmots_hi; ++lmots_type) {
+ ok &= test_hashsig_sign(L, lms_type, lmots_type, iterations, save, keep);
+ }
+ }
+ }
+ }
+
+ if ((err = hal_rpc_logout(client)) != HAL_OK)
+ printf("Warning: Trouble logging out of HSM: %s\n", hal_error_string(err));
+
+ 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-rsa.c b/tests/test-rsa.c
index 57037c0..176ba03 100644
--- a/tests/test-rsa.c
+++ b/tests/test-rsa.c
@@ -56,12 +56,21 @@ static int test_modexp(hal_core_t *core,
const rsa_tc_bn_t * const exp, /* Exponent */
const rsa_tc_bn_t * const val) /* Expected result */
{
- uint8_t result[tc->n.len];
+ uint8_t result[tc->n.len], C[tc->n.len], F[tc->n.len];
printf("%s test for %lu-bit RSA key\n", kind, (unsigned long) tc->size);
- if (hal_modexp(core, msg->val, msg->len, exp->val, exp->len,
- tc->n.val, tc->n.len, result, sizeof(result)) != HAL_OK)
+ hal_modexp_arg_t args = {
+ .core = core,
+ .msg = msg->val, .msg_len = msg->len,
+ .exp = exp->val, .exp_len = exp->len,
+ .mod = tc->n.val, .mod_len = tc->n.len,
+ .result = result, .result_len = sizeof(result),
+ .coeff = C, .coeff_len = sizeof(C),
+ .mont = F, .mont_len = sizeof(F)
+ };
+
+ if (hal_modexp(1, &args) != HAL_OK)
return printf("ModExp failed\n"), 0;
if (memcmp(result, val->val, val->len))
@@ -98,7 +107,7 @@ static int test_decrypt(hal_core_t *core,
uint8_t result[tc->n.len];
- if ((err = hal_rsa_decrypt(core, key, tc->m.val, tc->m.len, result, sizeof(result))) != HAL_OK)
+ if ((err = hal_rsa_decrypt(core, NULL, key, tc->m.val, tc->m.len, result, sizeof(result))) != HAL_OK)
printf("RSA CRT failed: %s\n", hal_error_string(err));
const int mismatch = (err == HAL_OK && memcmp(result, tc->s.val, tc->s.len) != 0);
@@ -165,7 +174,7 @@ static int test_gen(hal_core_t *core,
uint8_t result[tc->n.len];
- if ((err = hal_rsa_decrypt(core, key1, tc->m.val, tc->m.len, result, sizeof(result))) != HAL_OK)
+ if ((err = hal_rsa_decrypt(core, NULL, key1, tc->m.val, tc->m.len, result, sizeof(result))) != HAL_OK)
printf("RSA CRT failed: %s\n", hal_error_string(err));
snprintf(fn, sizeof(fn), "test-rsa-sig-%04lu.der", (unsigned long) tc->size);
@@ -296,7 +305,7 @@ static int test_rsa(hal_core_t *core, const rsa_tc_t * const tc)
return ok;
}
-int main(int argc, char *argv[])
+int main(void)
{
hal_core_t *core = hal_core_find(MODEXPS6_NAME, NULL);
if (core == NULL)
@@ -314,7 +323,7 @@ int main(int argc, char *argv[])
/* Normal test */
- for (int i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++)
+ for (size_t i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++)
if (!test_rsa(core, &rsa_tc[i]))
return 1;
diff --git a/tests/test-trng.c b/tests/test-trng.c
index f570752..45dec56 100644
--- a/tests/test-trng.c
+++ b/tests/test-trng.c
@@ -43,6 +43,7 @@
#include <sys/time.h>
#include <hal.h>
+#include <hal_internal.h>
#include <verilog_constants.h>
#ifndef WAIT_FOR_CSPRNG_VALID
diff --git a/tests/test-xdr.c b/tests/test-xdr.c
new file mode 100644
index 0000000..eedf48d
--- /dev/null
+++ b/tests/test-xdr.c
@@ -0,0 +1,111 @@
+/*
+ * xdr.c
+ * -----
+ * Serialization/deserialization routines, using XDR (RFC 4506) encoding.
+ * These functions are not part of the public libhal API.
+ *
+ * Copyright (c) 2016-2018, 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 <stdint.h>
+#include <stddef.h> /* ptrdiff_t */
+#include <string.h> /* memcpy, memset */
+
+#include "hal.h"
+#include "hal_internal.h" /* htonl/ntohl */
+#include "xdr_internal.h"
+
+static void hexdump(uint8_t *buf, uint32_t len)
+{
+ for (uint32_t i = 0; i < len; ++i)
+ printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' ');
+ if ((len & 0x07) != 0)
+ printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t i;
+ uint8_t buf[256] = {0};
+ uint8_t *bufptr = buf;
+ const uint8_t *readptr;
+ uint8_t *limit = buf + sizeof(buf);
+ hal_error_t ret;
+ uint8_t alphabet[] = "abcdefghijklmnopqrstuvwxyz";
+ uint8_t readbuf[256] = {0};
+
+ printf("hal_xdr_encode_int: work to failure\n");
+ for (i = 1; i < 100; ++i) {
+ if ((ret = hal_xdr_encode_int(&bufptr, limit, i)) != HAL_OK) {
+ printf("%d: %s\n", i, hal_error_string(ret));
+ break;
+ }
+ }
+ hexdump(buf, ((uint8_t *)bufptr - buf));
+
+ printf("\nhal_xdr_decode_int:\n");
+ readptr = buf;
+ while (readptr < bufptr) {
+ if ((ret = hal_xdr_decode_int(&readptr, limit, &i)) != HAL_OK) {
+ printf("%s\n", hal_error_string(ret));
+ break;
+ }
+ printf("%u ", i);
+ }
+ printf("\n");
+
+ printf("\nhal_xdr_encode_variable_opaque: work to failure\n");
+ memset(buf, 0, sizeof(buf));
+ bufptr = buf;
+ for (i = 1; ; ++i) {
+ if ((ret = hal_xdr_encode_variable_opaque(&bufptr, limit, alphabet, i)) != HAL_OK) {
+ printf("%d: %s\n", i, hal_error_string(ret));
+ break;
+ }
+ }
+ hexdump(buf, ((uint8_t *)bufptr - buf));
+
+ printf("\nhal_xdr_decode_variable_opaque:\n");
+ readptr = buf;
+ while (readptr < bufptr) {
+ size_t len = bufptr - readptr;
+ if ((ret = hal_xdr_decode_variable_opaque(&readptr, limit, readbuf, &len)) != HAL_OK) {
+ printf("%s\n", hal_error_string(ret));
+ break;
+ }
+ printf("%lu: ", len);
+ for (size_t j = 0; j < len; ++j)
+ putchar(readbuf[j]);
+ putchar('\n');
+ memset(readbuf, 0, sizeof(readbuf));
+ }
+
+ return 0;
+}
diff --git a/tests/time-keygen.py b/tests/time-keygen.py
new file mode 100755
index 0000000..b7311ba
--- /dev/null
+++ b/tests/time-keygen.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+"""
+Time libhal RSA key generation
+"""
+
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+from datetime import datetime, timedelta
+
+from cryptech.libhal import *
+
+parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter)
+parser.add_argument("-i", "--iterations", default = 100, type = int, help = "iterations")
+parser.add_argument("-p", "--pin", default = "fnord", help = "user PIN")
+parser.add_argument("-t", "--token", action = "store_true", help = "store key on token")
+parser.add_argument("-k", "--keylen", default = 2048, type = int, help = "key length")
+args = parser.parse_args()
+
+hsm = HSM()
+hsm.login(HAL_USER_NORMAL, args.pin)
+
+flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | (HAL_KEY_FLAG_TOKEN if args.token else 0)
+sum = timedelta()
+
+for n in xrange(1, args.iterations + 1):
+
+ t0 = datetime.now()
+
+ k = hsm.pkey_generate_rsa(args.keylen, flags)
+
+ t1 = datetime.now()
+
+ k.delete()
+
+ sum += t1 - t0
+
+ print "{:4d} this {} mean {}".format(n, t1 - t0, sum / n)
diff --git a/unit-tests.py b/unit-tests.py
index a3e4282..514aace 100644
--- a/unit-tests.py
+++ b/unit-tests.py
@@ -220,17 +220,618 @@ class TestDigest(TestCase):
Test digest/HMAC functions.
"""
- # Should use NIST test vectors, this is just a placeholder.
+ def v(*bytes):
+ return "".join(chr(b) for b in bytes)
+
+ # NIST sample messages.
+
+ # "abc"
+ nist_512_single = v(
+ 0x61, 0x62, 0x63
+ )
+
+ nist_sha1_single_digest = v(
+ 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71,
+ 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
+ )
+
+ nist_sha256_single_digest = v(
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+ )
+
+ # "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ nist_512_double = v(
+ 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66,
+ 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
+ 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71
+ )
+
+ nist_sha1_double_digest = v(
+ 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae, 0x4a, 0xa1,
+ 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1
+ )
+
+ nist_sha256_double_digest = v(
+ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
+ 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+ )
+
+ # "abc"
+ nist_1024_single = v(
+ 0x61, 0x62, 0x63
+ )
+
+ nist_sha512_224_single_digest = v(
+ 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54, 0xda, 0xae, 0x75, 0x30,
+ 0x46, 0x08, 0x42, 0xe2, 0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4,
+ 0x3e, 0x89, 0x24, 0xaa
+ )
+
+ nist_sha512_256_single_digest = v(
+ 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, 0x9b, 0x2e, 0x29, 0xb7,
+ 0x6b, 0x4c, 0x7d, 0xab, 0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46,
+ 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23
+ )
+
+ nist_sha384_single_digest = v(
+ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69,
+ 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+ 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b,
+ 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7
+ )
+
+ nist_sha512_single_digest = v(
+ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49,
+ 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f,
+ 0xa5, 0x4c, 0xa4, 0x9f
+ )
+
+ # "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ # "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+ nist_1024_double = v(
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x62, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x6f, 0x70, 0x71, 0x72, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x6e, 0x6f, 0x70, 0x71,
+ 0x72, 0x73, 0x74, 0x75
+ )
+
+ nist_sha512_224_double_digest = v(
+ 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23, 0x30, 0x81, 0x92, 0x64,
+ 0x0b, 0x0c, 0x45, 0x33, 0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72,
+ 0x68, 0x67, 0x4a, 0xf9
+ )
+
+ nist_sha512_256_double_digest = v(
+ 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8, 0x40, 0xda, 0x39, 0x88,
+ 0x12, 0x1d, 0x31, 0xbe, 0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14,
+ 0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a
+ )
+
+ nist_sha384_double_digest = v(
+ 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, 0x3d, 0x19, 0x2f, 0xc7,
+ 0x82, 0xcd, 0x1b, 0x47, 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2,
+ 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, 0xfc, 0xc7, 0xc7, 0x1a,
+ 0x55, 0x7e, 0x2d, 0xb9, 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39
+ )
+
+ nist_sha512_double_digest = v(
+ 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7, 0x28,
+ 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
+ 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50, 0x1d, 0x28, 0x9e,
+ 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
+ 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b,
+ 0x87, 0x4b, 0xe9, 0x09
+ )
+
+ # HMAC-SHA-1 test cases from RFC 2202.
+
+ hmac_sha1_tc_1_key = v(
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ )
+
+ # "Hi There"
+ hmac_sha1_tc_1_data = v(
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+ )
+
+ hmac_sha1_tc_1_result_sha1 = v(
+ 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b, 0xc0, 0xb6,
+ 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00
+ )
+
+ # "Jefe"
+ hmac_sha1_tc_2_key = v(
+ 0x4a, 0x65, 0x66, 0x65
+ )
+
+ # "what do ya want for nothing?"
+ hmac_sha1_tc_2_data = v(
+ 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77,
+ 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f
+ )
+
+ hmac_sha1_tc_2_result_sha1 = v(
+ 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74, 0x16, 0xd5,
+ 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79
+ )
+
+ hmac_sha1_tc_3_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ hmac_sha1_tc_3_data = v(
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ )
+
+ hmac_sha1_tc_3_result_sha1 = v(
+ 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, 0x91, 0xa3, 0x9a, 0xf4,
+ 0x8a, 0xa1, 0x7b, 0x4f, 0x63, 0xf1, 0x75, 0xd3
+ )
+
+ hmac_sha1_tc_4_key = v(
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19
+ )
+
+ hmac_sha1_tc_4_data = v(
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ )
+
+ hmac_sha1_tc_4_result_sha1 = v(
+ 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, 0xbc, 0x84, 0x14, 0xf9,
+ 0xbf, 0x50, 0xc8, 0x6c, 0x2d, 0x72, 0x35, 0xda
+ )
+
+ hmac_sha1_tc_5_key = v(
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+ )
+
+ # "Test With Truncation"
+ hmac_sha1_tc_5_data = v(
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72,
+ 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e
+ )
+
+ hmac_sha1_tc_5_result_sha1 = v(
+ 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2, 0x7b, 0xe1,
+ 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04
+ )
+
+ hmac_sha1_tc_6_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ # "Test Using Larger Than Block-Size Key - Hash Key First"
+ hmac_sha1_tc_6_data = v(
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65,
+ 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74
+ )
+
+ hmac_sha1_tc_6_result_sha1 = v(
+ 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, 0x95, 0x70, 0x56, 0x37,
+ 0xce, 0x8a, 0x3b, 0x55, 0xed, 0x40, 0x21, 0x12
+ )
+
+ hmac_sha1_tc_7_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ # "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ hmac_sha1_tc_7_data = v(
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65,
+ 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72,
+ 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x4f, 0x6e, 0x65, 0x20, 0x42, 0x6c,
+ 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61
+ )
+
+ hmac_sha1_tc_7_result_sha1 = v(
+ 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, 0x6b, 0xba, 0xa7,
+ 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91
+ )
+
+ # HMAC-SHA-2 test cases from RFC 4231.
+
+ hmac_sha2_tc_1_key = v(
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ )
+
+ # "Hi There"
+ hmac_sha2_tc_1_data = v(
+ 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
+ )
+
+ hmac_sha2_tc_1_result_sha256 = v(
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce,
+ 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+ )
+
+ hmac_sha2_tc_1_result_sha384 = v(
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4,
+ 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9,
+ 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
+ )
+
+ hmac_sha2_tc_1_result_sha512 = v(
+ 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24,
+ 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
+ 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7,
+ 0xd6, 0xb8, 0xa7, 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4,
+ 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20,
+ 0x3a, 0x12, 0x68, 0x54
+ )
+
+ # "Jefe"
+ hmac_sha2_tc_2_key = v(
+ 0x4a, 0x65, 0x66, 0x65
+ )
+
+ # "what do ya want for nothing?"
+ hmac_sha2_tc_2_data = v(
+ 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77,
+ 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
+ 0x69, 0x6e, 0x67, 0x3f
+ )
+
+ hmac_sha2_tc_2_result_sha256 = v(
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26,
+ 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ )
+
+ hmac_sha2_tc_2_result_sha384 = v(
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2,
+ 0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca,
+ 0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
+ )
+
+ hmac_sha2_tc_2_result_sha512 = v(
+ 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7,
+ 0x3b, 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
+ 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75,
+ 0xc0, 0x5a, 0x99, 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd,
+ 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a,
+ 0x38, 0xbc, 0xe7, 0x37
+ )
+
+ hmac_sha2_tc_3_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ hmac_sha2_tc_3_data = v(
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ )
+
+ hmac_sha2_tc_3_result_sha256 = v(
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb,
+ 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+ )
+
+ hmac_sha2_tc_3_result_sha384 = v(
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+ 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+ 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
+ )
+
+ hmac_sha2_tc_3_result_sha512 = v(
+ 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75,
+ 0x6c, 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36,
+ 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82,
+ 0x79, 0xa7, 0x22, 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07,
+ 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59,
+ 0xe1, 0x32, 0x92, 0xfb
+ )
+
+ hmac_sha2_tc_4_key = v(
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19
+ )
+
+ hmac_sha2_tc_4_data = v(
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ )
+
+ hmac_sha2_tc_4_result_sha256 = v(
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98,
+ 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+ )
+
+ hmac_sha2_tc_4_result_sha384 = v(
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62,
+ 0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23,
+ 0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
+ )
+
+ hmac_sha2_tc_4_result_sha512 = v(
+ 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5,
+ 0xf6, 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d,
+ 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1,
+ 0x1a, 0xa2, 0x5e, 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63,
+ 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb,
+ 0x10, 0xa2, 0x98, 0xdd
+ )
+
+ # Skipping HMAC-SHA-2 test case 5.
+
+ hmac_sha2_tc_6_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ # "Test Using Larger Than Block-Size Key - Hash Key First"
+ hmac_sha2_tc_6_data = v(
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65,
+ 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
+ 0x20, 0x46, 0x69, 0x72, 0x73, 0x74
+ )
+
+ hmac_sha2_tc_6_result_sha256 = v(
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa,
+ 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ )
+
+ hmac_sha2_tc_6_result_sha384 = v(
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+ 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+ 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
+ )
+
+ hmac_sha2_tc_6_result_sha512 = v(
+ 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1,
+ 0xdd, 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1,
+ 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37,
+ 0xe0, 0x5f, 0x25, 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52,
+ 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98,
+ 0x5d, 0x78, 0x65, 0x98
+ )
+
+ hmac_sha2_tc_7_key = v(
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ )
+
+ # "This is a test using a larger than block-size key and a larger than block-size data."
+ # " The key needs to be hashed before being used by the HMAC algorithm."
+ hmac_sha2_tc_7_data = v(
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65,
+ 0x73, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
+ 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62,
+ 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65,
+ 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67,
+ 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
+ 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65,
+ 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73,
+ 0x68, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
+ 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c,
+ 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e
+ )
+
+ hmac_sha2_tc_7_result_sha256 = v(
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc,
+ 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+ )
+
+ hmac_sha2_tc_7_result_sha384 = v(
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+ 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+ 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
+ )
+
+ hmac_sha2_tc_7_result_sha512 = v(
+ 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9,
+ 0x6e, 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86,
+ 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac,
+ 0x3c, 0x49, 0x82, 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15,
+ 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40,
+ 0xfa, 0x8c, 0x6a, 0x58
+ )
+
+ def t(self, alg, data, expect, key = None):
+ h = hsm.hash_initialize(alg, key = key, mixed_mode = False)
+ h.update(data)
+ result = h.finalize()
+ self.assertEqual(result, expect)
+
+ def test_nist_sha1_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.nist_512_single, self.nist_sha1_single_digest)
+
+ def test_nist_sha1_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.nist_512_double, self.nist_sha1_double_digest)
+
+ def test_nist_sha256_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.nist_512_single, self.nist_sha256_single_digest)
- def test_basic_hash(self):
- h = hsm.hash_initialize(HAL_DIGEST_ALGORITHM_SHA256)
- h.update("Hi, Mom")
- h.finalize()
+ def test_nist_sha256_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.nist_512_double, self.nist_sha256_double_digest)
+
+ def test_nist_sha512_224_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512_224, self.nist_1024_single, self.nist_sha512_224_single_digest)
+
+ def test_nist_sha512_224_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512_224, self.nist_1024_double, self.nist_sha512_224_double_digest)
+
+ def test_nist_sha512_256_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512_256, self.nist_1024_single, self.nist_sha512_256_single_digest)
+
+ def test_nist_sha512_256_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512_256, self.nist_1024_double, self.nist_sha512_256_double_digest)
+
+ def test_nist_sha384_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.nist_1024_single, self.nist_sha384_single_digest)
+
+ def test_nist_sha384_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.nist_1024_double, self.nist_sha384_double_digest)
+
+ def test_nist_sha512_single(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.nist_1024_single, self.nist_sha512_single_digest)
+
+ def test_nist_sha512_double(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.nist_1024_double, self.nist_sha512_double_digest)
+
+
+ def test_hmac_sha1_tc_1(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_1_data, self.hmac_sha1_tc_1_result_sha1, self.hmac_sha1_tc_1_key)
+
+ def test_hmac_sha1_tc_2(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_2_data, self.hmac_sha1_tc_2_result_sha1, self.hmac_sha1_tc_2_key)
+
+ def test_hmac_sha1_tc_3(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_3_data, self.hmac_sha1_tc_3_result_sha1, self.hmac_sha1_tc_3_key)
+
+ def test_hmac_sha1_tc_4(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_4_data, self.hmac_sha1_tc_4_result_sha1, self.hmac_sha1_tc_4_key)
+
+ def test_hmac_sha1_tc_5(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_5_data, self.hmac_sha1_tc_5_result_sha1, self.hmac_sha1_tc_5_key)
+
+ def test_hmac_sha1_tc_6(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_6_data, self.hmac_sha1_tc_6_result_sha1, self.hmac_sha1_tc_6_key)
+
+ def test_hmac_sha1_tc_7(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA1, self.hmac_sha1_tc_7_data, self.hmac_sha1_tc_7_result_sha1, self.hmac_sha1_tc_7_key)
+
+
+ def test_hmac_sha256_tc_1(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_1_data, self.hmac_sha2_tc_1_result_sha256, self.hmac_sha2_tc_1_key)
+
+ def test_hmac_sha256_tc_2(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_2_data, self.hmac_sha2_tc_2_result_sha256, self.hmac_sha2_tc_2_key)
+
+ def test_hmac_sha256_tc_3(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_3_data, self.hmac_sha2_tc_3_result_sha256, self.hmac_sha2_tc_3_key)
+
+ def test_hmac_sha256_tc_4(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_4_data, self.hmac_sha2_tc_4_result_sha256, self.hmac_sha2_tc_4_key)
+
+ def test_hmac_sha256_tc_6(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_6_data, self.hmac_sha2_tc_6_result_sha256, self.hmac_sha2_tc_6_key)
+
+ def test_hmac_sha256_tc_7(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA256, self.hmac_sha2_tc_7_data, self.hmac_sha2_tc_7_result_sha256, self.hmac_sha2_tc_7_key)
+
+
+ def test_hmac_sha384_tc_1(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_1_data, self.hmac_sha2_tc_1_result_sha384, self.hmac_sha2_tc_1_key)
+
+ def test_hmac_sha384_tc_2(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_2_data, self.hmac_sha2_tc_2_result_sha384, self.hmac_sha2_tc_2_key)
+
+ def test_hmac_sha384_tc_3(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_3_data, self.hmac_sha2_tc_3_result_sha384, self.hmac_sha2_tc_3_key)
+
+ def test_hmac_sha384_tc_4(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_4_data, self.hmac_sha2_tc_4_result_sha384, self.hmac_sha2_tc_4_key)
+
+ def test_hmac_sha384_tc_6(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_6_data, self.hmac_sha2_tc_6_result_sha384, self.hmac_sha2_tc_6_key)
+
+ def test_hmac_sha384_tc_7(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA384, self.hmac_sha2_tc_7_data, self.hmac_sha2_tc_7_result_sha384, self.hmac_sha2_tc_7_key)
+
+
+ def test_hmac_sha512_tc_1(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_1_data, self.hmac_sha2_tc_1_result_sha512, self.hmac_sha2_tc_1_key)
+
+ def test_hmac_sha512_tc_2(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_2_data, self.hmac_sha2_tc_2_result_sha512, self.hmac_sha2_tc_2_key)
+
+ def test_hmac_sha512_tc_3(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_3_data, self.hmac_sha2_tc_3_result_sha512, self.hmac_sha2_tc_3_key)
+
+ def test_hmac_sha512_tc_4(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_4_data, self.hmac_sha2_tc_4_result_sha512, self.hmac_sha2_tc_4_key)
+
+ def test_hmac_sha512_tc_6(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_6_data, self.hmac_sha2_tc_6_result_sha512, self.hmac_sha2_tc_6_key)
+
+ def test_hmac_sha512_tc_7(self):
+ self.t(HAL_DIGEST_ALGORITHM_SHA512, self.hmac_sha2_tc_7_data, self.hmac_sha2_tc_7_result_sha512, self.hmac_sha2_tc_7_key)
- 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
@@ -599,17 +1200,20 @@ class TestPKeyMatch(TestCaseLoggedIn):
tags.extend(PreloadedKey.db)
self.assertEqual(len(tags), len(uuids))
+ n = 0
self.assertEqual(uuids, set(k.uuid for n, k in self.match(mask = mask,
flags = flags,
uuids = uuids)))
for keytype in set(HALKeyType.index.itervalues()) - {HAL_KEY_TYPE_NONE}:
+ n = 0
for n, k in self.match(mask = mask, 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}:
+ n = 0
for n, k in self.match(mask = mask, flags = flags, uuids = uuids, curve = curve):
self.assertEqual(k.key_curve, curve)
self.assertEqual(k.get_attributes({1}).pop(1), str(curve))
@@ -618,6 +1222,7 @@ class TestPKeyMatch(TestCaseLoggedIn):
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)):
+ n = 0
for n, k in self.match(mask = mask, flags = flags, uuids = uuids,
attributes = {1 : str(keylen)}):
self.assertEqual(keylen, int(k.get_attributes({1}).pop(1)))
@@ -626,6 +1231,7 @@ class TestPKeyMatch(TestCaseLoggedIn):
self.assertEqual(n, sum(1 for t1, t2 in tags
if not isinstance(t2, Enum) and t2 == keylen))
+ n = 0
for n, k in self.match(mask = mask, flags = flags, uuids = uuids,
type = HAL_KEY_TYPE_RSA_PUBLIC, attributes = {1 : "2048"}):
self.assertEqual(k.key_type, HAL_KEY_TYPE_RSA_PUBLIC)
@@ -652,7 +1258,7 @@ class TestPKeyAttribute(TestCaseLoggedIn):
try:
with hsm.pkey_open(uuid) as pkey:
pkey.delete()
- except:
+ except Exception as e:
logger.debug("Problem deleting key %s: %s", uuid, e)
def load_and_fill(self, flags, n_keys = 1, n_attrs = 2, n_fill = 0):
@@ -666,17 +1272,40 @@ class TestPKeyAttribute(TestCaseLoggedIn):
for j in xrange(n_attrs)))
pinwheel()
+ # These sizes work with a 4096-byte keystore block; if you tweak
+ # the undelrying block size, you may need to tweak these tests too.
+
+ def test_attribute_svelt_volatile_many(self):
+ self.load_and_fill(0, n_attrs = 64)
+
def test_attribute_bloat_volatile_many(self):
- self.load_and_fill(0, n_attrs = 128) # 192
+ self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh")
+ with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG):
+ self.load_and_fill(0, n_attrs = 128)
+
+ def test_attribute_svelt_volatile_big(self):
+ self.load_and_fill(0, n_attrs = 6, n_fill = 256)
def test_attribute_bloat_volatile_big(self):
- self.load_and_fill(0, n_attrs = 6, n_fill = 512)
+ self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh")
+ with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG):
+ self.load_and_fill(0, n_attrs = 6, n_fill = 512)
+
+ def test_attribute_svelt_token_many(self):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 64)
def test_attribute_bloat_token_many(self):
- self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128)
+ self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh")
+ with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128)
+
+ def test_attribute_svelt_token_big(self):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 6, n_fill = 256)
def test_attribute_bloat_token_big(self):
- self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 4, n_fill = 512) # [16, 1024]
+ self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh")
+ with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG):
+ self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 6, n_fill = 512)
@unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package")
@@ -1011,6 +1640,10 @@ class AESKeyWrapWithPadding(object):
step = -1 if start > stop else 1
return xrange(start, stop + step, step)
+ @staticmethod
+ def _xor(R0, t):
+ return pack(">Q", unpack(">Q", R0)[0] ^ t)
+
def wrap(self, Q):
"RFC 5649 section 4.1."
m = len(Q) # Plaintext length
@@ -1027,9 +1660,7 @@ class AESKeyWrapWithPadding(object):
for j in self._start_stop(0, 5):
for i in self._start_stop(1, n):
R[0], R[i] = self._encrypt(R[0], R[i])
- W0, W1 = unpack(">LL", R[0])
- W1 ^= n * j + i
- R[0] = pack(">LL", W0, W1)
+ R[0] = self._xor(R[0], n * j + i)
assert len(R) == (n + 1) and all(len(r) == 8 for r in R)
return "".join(R)
@@ -1046,9 +1677,7 @@ class AESKeyWrapWithPadding(object):
# RFC 3394 section 2.2.2 steps (1), (2), and part of (3)
for j in self._start_stop(5, 0):
for i in self._start_stop(n, 1):
- W0, W1 = unpack(">LL", R[0])
- W1 ^= n * j + i
- R[0] = pack(">LL", W0, W1)
+ R[0] = self._xor(R[0], n * j + i)
R[0], R[i] = self._decrypt(R[0], R[i])
magic, m = unpack(">LL", R[0])
if magic != 0xa65959a6:
diff --git a/utils/cores.c b/utils/cores.c
index b055dea..1126e85 100644
--- a/utils/cores.c
+++ b/utils/cores.c
@@ -42,7 +42,7 @@
#include <hal.h>
#include <verilog_constants.h>
-int main(int argc, char *argv[])
+int main(void)
{
hal_core_t *core;
const hal_core_info_t *info;
diff --git a/verilog_constants.h b/verilog_constants.h
index c9bb566..1b00b96 100644
--- a/verilog_constants.h
+++ b/verilog_constants.h
@@ -222,23 +222,38 @@
#define MODEXPS6_ADDR_MESSAGE (MODEXPS6_ADDR_OPERANDS + 1 * MODEXPS6_OPERAND_WORDS)
#define MODEXPS6_ADDR_EXPONENT (MODEXPS6_ADDR_OPERANDS + 2 * MODEXPS6_OPERAND_WORDS)
#define MODEXPS6_ADDR_RESULT (MODEXPS6_ADDR_OPERANDS + 3 * MODEXPS6_OPERAND_WORDS)
+#define MODEXPS6_MODE_CONSTANT_TIME (0)
+#define MODEXPS6_MODE_FAST_PUBLIC (1)
/*
* ModExpA7 core. MODEXPA7_OPERAND_BITS is size in bits of largest
* supported modulus.
+ *
+ * I prefer the way Pavel wrote the constants for this in his sample
+ * code to what I've done here, but let's get the thing working before
+ * worrying about the yaks' pedicures.
*/
-#define MODEXPA7_OPERAND_BITS (4096)
-#define MODEXPA7_OPERAND_WORDS (MODEXPA7_OPERAND_BITS / 32)
-#define MODEXPA7_ADDR_REGISTERS (0 * MODEXPA7_OPERAND_WORDS)
-#define MODEXPA7_ADDR_OPERANDS (4 * MODEXPA7_OPERAND_WORDS)
-#define MODEXPA7_ADDR_MODE (MODEXPA7_ADDR_REGISTERS + 0x10)
-#define MODEXPA7_ADDR_MODULUS_WIDTH (MODEXPA7_ADDR_REGISTERS + 0x11)
-#define MODEXPA7_ADDR_EXPONENT_WIDTH (MODEXPA7_ADDR_REGISTERS + 0x12)
-#define MODEXPA7_ADDR_MODULUS (MODEXPA7_ADDR_OPERANDS + 0 * MODEXPA7_OPERAND_WORDS)
-#define MODEXPA7_ADDR_MESSAGE (MODEXPA7_ADDR_OPERANDS + 1 * MODEXPA7_OPERAND_WORDS)
-#define MODEXPA7_ADDR_EXPONENT (MODEXPA7_ADDR_OPERANDS + 2 * MODEXPA7_OPERAND_WORDS)
-#define MODEXPA7_ADDR_RESULT (MODEXPA7_ADDR_OPERANDS + 3 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_OPERAND_BITS (4096)
+#define MODEXPA7_OPERAND_BYTES (MODEXPA7_OPERAND_BITS / 8)
+#define MODEXPA7_OPERAND_WORDS (MODEXPA7_OPERAND_BITS / 32)
+#define MODEXPA7_ADDR_REGISTERS (0 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_OPERANDS (8 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MODE (MODEXPA7_ADDR_REGISTERS + 0x10)
+#define MODEXPA7_ADDR_MODULUS_BITS (MODEXPA7_ADDR_REGISTERS + 0x11)
+#define MODEXPA7_ADDR_EXPONENT_BITS (MODEXPA7_ADDR_REGISTERS + 0x12)
+#define MODEXPA7_ADDR_BUFFER_BITS (MODEXPA7_ADDR_REGISTERS + 0x13)
+#define MODEXPA7_ADDR_ARRAY_BITS (MODEXPA7_ADDR_REGISTERS + 0x14)
+#define MODEXPA7_ADDR_MODULUS (MODEXPA7_ADDR_OPERANDS + 0 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MESSAGE (MODEXPA7_ADDR_OPERANDS + 1 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_EXPONENT (MODEXPA7_ADDR_OPERANDS + 2 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_RESULT (MODEXPA7_ADDR_OPERANDS + 3 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MODULUS_COEFF_OUT (MODEXPA7_ADDR_OPERANDS + 4 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MODULUS_COEFF_IN (MODEXPA7_ADDR_OPERANDS + 5 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MONTGOMERY_FACTOR_OUT (MODEXPA7_ADDR_OPERANDS + 6 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_ADDR_MONTGOMERY_FACTOR_IN (MODEXPA7_ADDR_OPERANDS + 7 * MODEXPA7_OPERAND_WORDS)
+#define MODEXPA7_MODE_CRT (1 << 1)
+#define MODEXPA7_MODE_PLAIN (0 << 1)
/*
* ECDSA P-256 point multiplier core. ECDSA256_OPERAND_BITS is size
diff --git a/xdr.c b/xdr.c
index 0f172fb..9a958ac 100644
--- a/xdr.c
+++ b/xdr.c
@@ -2,8 +2,9 @@
* xdr.c
* -----
* Serialization/deserialization routines, using XDR (RFC 4506) encoding.
+ * These functions are not part of the public libhal API.
*
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -34,10 +35,11 @@
#include <stdio.h>
#include <stdint.h>
+#include <stddef.h> /* ptrdiff_t */
#include <string.h> /* memcpy, memset */
#include "hal.h"
-#include "hal_internal.h"
+#include "hal_internal.h" /* htonl/ntohl */
#include "xdr_internal.h"
/* encode/decode_int. This covers int, unsigned int, enum, and bool types,
@@ -52,7 +54,7 @@ hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, const uint8_t * const li
return HAL_ERROR_BAD_ARGUMENTS;
/* buffer overflow check */
- if (limit - *outbuf < sizeof(value))
+ if (limit - *outbuf < (ptrdiff_t)sizeof(value))
return HAL_ERROR_XDR_BUFFER_OVERFLOW;
**(uint32_t **)outbuf = htonl(value);
@@ -60,55 +62,50 @@ hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, const uint8_t * const li
return HAL_OK;
}
-hal_error_t hal_xdr_decode_int(const uint8_t ** const inbuf, const uint8_t * const limit, uint32_t *value)
+/* decode an integer value without advancing the input pointer */
+hal_error_t hal_xdr_decode_int_peek(const uint8_t ** const inbuf, const uint8_t * const limit, uint32_t *value)
{
/* arg checks */
if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
/* buffer overflow check */
- if (limit - *inbuf < sizeof(*value))
+ if (limit - *inbuf < (ptrdiff_t)sizeof(*value))
return HAL_ERROR_XDR_BUFFER_OVERFLOW;
*value = ntohl(**(uint32_t **)inbuf);
- *inbuf += sizeof(*value);
return HAL_OK;
}
-/* Undo the last decode_int - roll back the input pointer.
- */
-hal_error_t hal_xdr_undecode_int(const uint8_t ** const inbuf)
+/* decode an integer value the regular way */
+hal_error_t hal_xdr_decode_int(const uint8_t ** const inbuf, const uint8_t * const limit, uint32_t *value)
{
- if (inbuf == NULL || *inbuf == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
+ hal_error_t err;
- *inbuf -= sizeof(uint32_t);
- return HAL_OK;
+ if ((err = hal_xdr_decode_int_peek(inbuf, limit, value)) == HAL_OK)
+ *inbuf += sizeof(*value);
+
+ return err;
}
-/* encode/decode_buffer. This covers variable-length string and opaque types.
- * The data is preceded by a 4-byte length word (encoded as above), and padded
- * to a multiple of 4 bytes as necessary.
+/* encode/decode_fixed_opaque. This covers fixed-length string and opaque types.
+ * The data is padded to a multiple of 4 bytes as necessary.
*/
-hal_error_t hal_xdr_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, const uint8_t *value, const uint32_t len)
+hal_error_t hal_xdr_encode_fixed_opaque(uint8_t ** const outbuf, const uint8_t * const limit, const uint8_t * const value, const size_t len)
{
- hal_error_t ret;
+ if (len == 0)
+ return HAL_OK;
/* arg checks */
- if (outbuf == NULL || *outbuf == NULL || limit == NULL ||
- (value == NULL && len != 0))
+ if (outbuf == NULL || *outbuf == NULL || limit == NULL || value == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
/* buffer overflow check */
- if ((limit - *outbuf) < (((len + 3) & ~3) + sizeof(len)))
+ if (limit - *outbuf < (ptrdiff_t)((len + 3) & ~3))
return HAL_ERROR_XDR_BUFFER_OVERFLOW;
- /* encode length */
- if ((ret = hal_xdr_encode_int(outbuf, limit, len)) != HAL_OK)
- return ret;
-
- /* write the string or opaque data */
+ /* write the data */
memcpy(*outbuf, value, len);
*outbuf += len;
@@ -122,139 +119,101 @@ hal_error_t hal_xdr_encode_buffer(uint8_t **outbuf, const uint8_t * const limit,
return HAL_OK;
}
-/* This version returns a pointer to the data in the input buffer.
- * It is used in the rpc server.
- */
-hal_error_t hal_xdr_decode_buffer_in_place(const uint8_t **inbuf, const uint8_t * const limit, const uint8_t ** const value, uint32_t * const len)
+hal_error_t hal_xdr_decode_fixed_opaque_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, const uint8_t ** const value, const size_t len)
{
- hal_error_t ret;
- uint32_t xdr_len;
- const uint8_t *orig_inbuf = *inbuf;
-
/* arg checks */
- if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL || len == NULL)
+ if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
- /* decode the length */
- if ((ret = hal_xdr_decode_int(inbuf, limit, &xdr_len)) != HAL_OK)
- return ret;
-
- /* input and output buffer overflow checks vs decoded length */
-
- /* decoded length is past the end of the input buffer;
- * we're probably out of sync, but nothing we can do now
- */
- if (limit - *inbuf < xdr_len) {
- /* undo read of length */
- *inbuf = orig_inbuf;
+ /* buffer overflow check */
+ if (limit - *inbuf < (ptrdiff_t)len)
return HAL_ERROR_XDR_BUFFER_OVERFLOW;
- }
- /* return a pointer to the string or opaque data */
+ /* return a pointer to the data */
*value = *inbuf;
- *len = xdr_len;
/* update the buffer pointer, skipping any padding bytes */
- *inbuf += (xdr_len + 3) & ~3;
+ *inbuf += ((len + 3) & ~3);
return HAL_OK;
}
-/* This version copies the data to the user-supplied buffer.
- * It is used in the rpc client.
- */
-hal_error_t hal_xdr_decode_buffer(const uint8_t **inbuf, const uint8_t * const limit, uint8_t * const value, uint32_t * const len)
+hal_error_t hal_xdr_decode_fixed_opaque(const uint8_t ** const inbuf, const uint8_t * const limit, uint8_t * const value, const size_t len)
{
- if (inbuf == NULL || value == NULL || len == NULL)
- return HAL_ERROR_BAD_ARGUMENTS;
+ const uint8_t *p;
+ hal_error_t err;
- hal_error_t ret;
- const uint8_t *vptr;
- const uint8_t *orig_inbuf = *inbuf;
- uint32_t xdr_len;
+ /* get and advance the input data pointer */
+ if ((err = hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, &p, len)) == HAL_OK)
+ /* read the data */
+ memcpy(value, p, len);
+
+ return err;
+}
- if ((ret = hal_xdr_decode_buffer_in_place(inbuf, limit, &vptr, &xdr_len)) != HAL_OK)
- return ret;
+/* encode/decode_variable_opaque. This covers variable-length string and opaque types.
+ * The data is preceded by a 4-byte length word (encoded as above), and padded
+ * to a multiple of 4 bytes as necessary.
+ */
- if (*len < xdr_len) {
- /* user buffer is too small, undo read of length */
- *inbuf = orig_inbuf;
- ret = HAL_ERROR_XDR_BUFFER_OVERFLOW;
- }
- else {
- memcpy(value, vptr, xdr_len);
- }
+hal_error_t hal_xdr_encode_variable_opaque(uint8_t ** const outbuf, const uint8_t * const limit, const uint8_t * const value, const size_t len)
+{
+ hal_error_t err;
- *len = xdr_len;
+ /* encode length */
+ if ((err = hal_xdr_encode_int(outbuf, limit, (uint32_t)len)) == HAL_OK) {
+ /* encode data */
+ if ((err = hal_xdr_encode_fixed_opaque(outbuf, limit, value, len)) != HAL_OK)
+ /* undo write of length */
+ *outbuf -= 4;
+ }
- return ret;
+ return err;
}
-/* ---------------------------------------------------------------- */
-
-#ifdef TEST
-static void hexdump(uint8_t *buf, uint32_t len)
+/* This version returns a pointer to the data in the input buffer.
+ * It is used in the rpc server.
+ */
+hal_error_t hal_xdr_decode_variable_opaque_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, const uint8_t ** const value, size_t * const len)
{
- for (uint32_t i = 0; i < len; ++i)
- printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' ');
- if ((len & 0x07) != 0)
- printf("\n");
+ hal_error_t err;
+ uint32_t xdr_len;
+
+ /* arg checks */
+ if (len == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ /* read length */
+ if ((err = hal_xdr_decode_int(inbuf, limit, &xdr_len)) == HAL_OK) {
+ /* get the data pointer */
+ if ((err = hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, value, xdr_len)) == HAL_OK)
+ *len = xdr_len;
+ else
+ /* undo read of length */
+ *inbuf -= 4;
+ }
+
+ return err;
}
-int main(int argc, char *argv[])
+/* This version copies the data to the user-supplied buffer.
+ * It is used in the rpc client.
+ */
+hal_error_t hal_xdr_decode_variable_opaque(const uint8_t ** const inbuf, const uint8_t * const limit, uint8_t * const value, size_t * const len)
{
- uint32_t i;
- uint8_t buf[64] = {0};
- uint8_t *bufptr = buf, *readptr;
- uint8_t *limit = buf + sizeof(buf);
- hal_error_t ret;
- uint8_t alphabet[] = "abcdefghijklmnopqrstuvwxyz";
- uint8_t readbuf[64] = {0};
-
- printf("hal_xdr_encode_int: work to failure\n");
- for (i = 1; i < 100; ++i) {
- if ((ret = hal_xdr_encode_int(&bufptr, limit, i)) != HAL_OK) {
- printf("%d: %s\n", i, hal_error_string(ret));
- break;
- }
- }
- hexdump(buf, ((uint8_t *)bufptr - buf));
-
- printf("\nhal_xdr_decode_int:\n");
- readptr = buf;
- while (readptr < bufptr) {
- if ((ret = hal_xdr_decode_int(&readptr, limit, &i)) != HAL_OK) {
- printf("%s\n", hal_error_string(ret));
- break;
- }
- printf("%u ", i);
- }
- printf("\n");
-
- printf("\nhal_xdr_encode_buffer: work to failure\n");
- memset(buf, 0, sizeof(buf));
- bufptr = buf;
- for (i = 1; i < 10; ++i) {
- if ((ret = hal_xdr_encode_buffer(&bufptr, limit, alphabet, i)) != HAL_OK) {
- printf("%d: %s\n", i, hal_error_string(ret));
- break;
- }
- }
- hexdump(buf, ((uint8_t *)bufptr - buf));
-
- printf("\nhal_xdr_decode_buffer:\n");
- readptr = buf;
- i = sizeof(readbuf);
- while (readptr < bufptr) {
- if ((ret = hal_xdr_decode_buffer(&readptr, limit, readbuf, &i)) != HAL_OK) {
- printf("%s\n", hal_error_string(ret));
- break;
- }
- printf("%u: ", i); for (int j = 0; j < i; ++j) putchar(readbuf[j]); putchar('\n');
- i = sizeof(readbuf);
- memset(readbuf, 0, sizeof(readbuf));
+ hal_error_t err;
+ size_t xdr_len;
+ const uint8_t *p;
+
+ /* read data pointer and length */
+ if ((err = hal_xdr_decode_variable_opaque_ptr(inbuf, limit, &p, &xdr_len)) == HAL_OK) {
+ /* user buffer overflow check */
+ if (*len < xdr_len)
+ return HAL_ERROR_XDR_BUFFER_OVERFLOW;
+ /* read the data */
+ memcpy(value, p, xdr_len);
+ *len = xdr_len;
}
- return 0;
+ return err;
}
-#endif
diff --git a/xdr_internal.h b/xdr_internal.h
index 9d02fd3..aa3a1e9 100644
--- a/xdr_internal.h
+++ b/xdr_internal.h
@@ -2,8 +2,9 @@
* xdr_internal.h
* --------------
* Serialization/deserialization routines, using XDR (RFC 4506) encoding.
+ * These functions are not part of the public libhal API.
*
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -35,10 +36,6 @@
#ifndef _XDR_INTERNAL_H
#define _XDR_INTERNAL_H
- /*
- * RPC serialization/deserialization routines, using XDR (RFC 4506) encoding.
- */
-
hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf,
const uint8_t * const limit,
const uint32_t value);
@@ -47,22 +44,35 @@ hal_error_t hal_xdr_decode_int(const uint8_t ** const inbuf,
const uint8_t * const limit,
uint32_t * const value);
-hal_error_t hal_xdr_undecode_int(const uint8_t ** const inbuf);
+hal_error_t hal_xdr_decode_int_peek(const uint8_t ** const inbuf,
+ const uint8_t * const limit,
+ uint32_t * const value);
+
+hal_error_t hal_xdr_encode_fixed_opaque(uint8_t ** const outbuf,
+ const uint8_t * const limit,
+ const uint8_t * const value, const size_t len);
-hal_error_t hal_xdr_encode_buffer(uint8_t ** const outbuf,
- const uint8_t * const limit,
- const uint8_t * const value,
- const uint32_t len);
+hal_error_t hal_xdr_decode_fixed_opaque(const uint8_t ** const inbuf,
+ const uint8_t * const limit,
+ uint8_t * const value, const size_t len);
-hal_error_t hal_xdr_decode_buffer_in_place(const uint8_t ** const inbuf,
+hal_error_t hal_xdr_decode_fixed_opaque_ptr(const uint8_t ** const inbuf,
+ const uint8_t * const limit,
+ const uint8_t ** const vptr, const size_t len);
+
+hal_error_t hal_xdr_encode_variable_opaque(uint8_t ** const outbuf,
const uint8_t * const limit,
- const uint8_t ** const vptr,
- uint32_t * const len);
+ const uint8_t * const value,
+ const size_t len);
-hal_error_t hal_xdr_decode_buffer(const uint8_t ** const inbuf,
- const uint8_t * const limit,
- uint8_t * const value,
- uint32_t * const len);
+hal_error_t hal_xdr_decode_variable_opaque(const uint8_t ** const inbuf,
+ const uint8_t * const limit,
+ uint8_t * const value,
+ size_t * const len);
+hal_error_t hal_xdr_decode_variable_opaque_ptr(const uint8_t ** const inbuf,
+ const uint8_t * const limit,
+ const uint8_t ** const vptr,
+ size_t * const len);
#endif /* _XDR_INTERNAL_H*/