aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--asn1.c183
-rw-r--r--asn1_internal.h15
-rw-r--r--ecdsa.c1
-rw-r--r--hal.h20
-rw-r--r--hal_internal.h35
-rw-r--r--hash.c2
-rw-r--r--hashsig.c2122
-rw-r--r--hashsig.h118
-rw-r--r--ks.c16
-rw-r--r--ks.h4
-rw-r--r--ks_volatile.c8
-rw-r--r--locks.c5
-rw-r--r--pbkdf2.c2
-rw-r--r--rpc_api.c23
-rw-r--r--rpc_client.c144
-rw-r--r--rpc_pkey.c206
-rw-r--r--rpc_server.c529
-rw-r--r--tests/Makefile4
-rw-r--r--tests/test-hashsig.h925
-rw-r--r--tests/test-rpc_hashsig.c594
-rw-r--r--tests/test-xdr.c111
-rw-r--r--xdr.c222
-rw-r--r--xdr_internal.h44
24 files changed, 4792 insertions, 547 deletions
diff --git a/Makefile b/Makefile
index 59236af..6934f95 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ 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
LIB = libhal.a
@@ -93,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
@@ -220,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}
@@ -272,6 +273,7 @@ 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/asn1.c b/asn1.c
index 8d7f6f6..d57ec96 100644
--- a/asn1.c
+++ b/asn1.c
@@ -60,12 +60,36 @@
* Algorithm OIDs used in SPKI and PKCS #8.
*/
+/*
+ * From RFC 5480 New ASN.1 Modules for the Public Key Infrastructure Using X.509 (PKIX)
+ *
+ * rsaEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1)
+ * pkcs-1(1) 1 }
+ */
const uint8_t hal_asn1_oid_rsaEncryption[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
const size_t hal_asn1_oid_rsaEncryption_len = sizeof(hal_asn1_oid_rsaEncryption);
+/*
+ * From RFC 5480 Elliptic Curve Cryptography Subject Public Key Information
+ *
+ * id-ecPublicKey OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
+ */
const uint8_t hal_asn1_oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 };
const size_t hal_asn1_oid_ecPublicKey_len = sizeof(hal_asn1_oid_ecPublicKey);
+/*
+ * From RFC 5649 Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm
+ *
+ * aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16)
+ * us(840) organization(1) gov(101) csor(3)
+ * nistAlgorithm(4) 1 }
+ *
+ * id-aes128-wrap-pad OBJECT IDENTIFIER ::= { aes 8 }
+ *
+ * id-aes256-wrap-pad OBJECT IDENTIFIER ::= { aes 48 }
+ */
#if KEK_LENGTH == (bitsToBytes(128))
const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x08 };
const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
@@ -77,6 +101,15 @@ const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
#endif
/*
+ * From draft-housley-cms-mts-hash-sig Use of the Hash-based Merkle Tree Signature (MTS) Algorithm in the Cryptographic Message Syntax (CMS)
+ *
+ * id-alg-mts-hashsig OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ * us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) alg(3) 17 }
+ */
+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.
*
* Sets *der_len to the size of of the ASN.1 header (tag and length
@@ -174,6 +207,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;
+
+ hal_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;
+
+ hal_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).
*/
@@ -483,6 +598,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).
*/
@@ -787,6 +964,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 3de8bd6..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,
diff --git a/ecdsa.c b/ecdsa.c
index 6d518fa..5991d21 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -711,6 +711,7 @@ static hal_error_t point_scalar_multiply(const fp_int * const k,
point_double (M[1], M[1], curve);
point_add (M[bit], P, M[bit], curve);
+ hal_task_yield_maybe();
}
/*
diff --git a/hal.h b/hal.h
index 5ae2381..b544900 100644
--- a/hal.h
+++ b/hal.h
@@ -163,6 +163,8 @@
DEFINE_HAL_ERROR(HAL_ERROR_NOT_IMPLEMENTED, "Not implemented") \
DEFINE_HAL_ERROR(HAL_ERROR_CORE_REASSIGNED, "Core has been reassigned since last use") \
DEFINE_HAL_ERROR(HAL_ERROR_ASSERTION_FAILED, "Assertion failed") \
+ DEFINE_HAL_ERROR(HAL_ERROR_HASHSIG_KEY_EXHAUSTED, "Key exhausted") \
+ DEFINE_HAL_ERROR(HAL_ERROR_NOT_READY, "Not ready for this operation") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -428,7 +430,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 {
@@ -809,6 +815,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 742b67b..94546c3 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -61,7 +61,7 @@
} while (0)
/*
- * 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>
@@ -75,10 +75,18 @@ 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
/*
@@ -130,17 +138,17 @@ static inline hal_error_t hal_io_wait_valid2(const hal_core_t *core1, const hal_
/*
* 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.
@@ -160,6 +168,7 @@ extern void hal_ks_unlock(void);
extern void hal_rsa_bf_lock(void);
extern void hal_rsa_bf_unlock(void);
extern void hal_task_yield(void);
+extern void hal_task_yield_maybe(void);
/*
* Thread sleep. Currently used only for bad-PIN delays.
@@ -296,6 +305,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);
@@ -643,9 +661,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,
@@ -662,7 +681,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/hash.c b/hash.c
index cb9eb1f..2a63900 100644
--- a/hash.c
+++ b/hash.c
@@ -447,7 +447,7 @@ hal_error_t hal_hash_initialize(hal_core_t *core,
hal_core_free(core);
/* A dynamically allocated core that can't restore state isn't going to work. */
- if (!state->descriptor->can_restore_state && (flags & STATE_FLAG_FREE_CORE) != 0)
+ if (!descriptor->can_restore_state && (flags & STATE_FLAG_FREE_CORE) != 0)
return HAL_ERROR_BAD_ARGUMENTS;
if (state_buffer == NULL && (state = alloc_static_hash_state()) == NULL)
diff --git a/hashsig.c b/hashsig.c
new file mode 100644
index 0000000..4060818
--- /dev/null
+++ b/hashsig.c
@@ -0,0 +1,2122 @@
+/*
+ * 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
+ */
+
+static inline hal_error_t hal_asn1_encode_size_t(const size_t n, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_uint32((const uint32_t)n, der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_size_t(size_t *np, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ /* trust the compiler to optimize out the unused code path */
+ if (sizeof(size_t) == sizeof(uint32_t)) {
+ return hal_asn1_decode_uint32((uint32_t *)np, der, der_len, der_max);
+ }
+ else {
+ uint32_t n;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_uint32(&n, der, der_len, der_max)) == HAL_OK)
+ *np = (size_t)n;
+
+ return err;
+ }
+}
+
+static inline hal_error_t hal_asn1_encode_lms_algorithm(const lms_algorithm_t type, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_uint32((const uint32_t)type, der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_lms_algorithm(lms_algorithm_t *type, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ uint32_t n;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_uint32(&n, der, der_len, der_max)) == HAL_OK)
+ *type = (lms_algorithm_t)n;
+
+ return err;
+}
+
+static inline hal_error_t hal_asn1_encode_lmots_algorithm(const lmots_algorithm_t type, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_uint32((const uint32_t)type, der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_lmots_algorithm(lmots_algorithm_t *type, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ uint32_t n;
+ hal_error_t err;
+
+ if ((err = hal_asn1_decode_uint32(&n, der, der_len, der_max)) == HAL_OK)
+ *type = (lmots_algorithm_t)n;
+
+ return err;
+}
+
+static inline hal_error_t hal_asn1_encode_uuid(const hal_uuid_t * const data, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(hal_uuid_t), der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_uuid(hal_uuid_t *data, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_decode_octet_string((uint8_t *)data, sizeof(hal_uuid_t), der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_encode_bytestring16(const bytestring16 * const data, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(bytestring16), der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_bytestring16(bytestring16 *data, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_decode_octet_string((uint8_t *)data, sizeof(bytestring16), der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_encode_bytestring32(const bytestring32 * const data, uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ return hal_asn1_encode_octet_string((const uint8_t * const)data, sizeof(bytestring32), der, der_len, der_max);
+}
+
+static inline hal_error_t hal_asn1_decode_bytestring32(bytestring32 *data, const uint8_t * const der, size_t *der_len, const size_t der_max)
+{
+ return 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])));
+ hal_task_yield_maybe();
+ }
+
+ /* 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])));
+ hal_task_yield_maybe();
+ }
+
+ 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));
+ hal_task_yield_maybe();
+ }
+
+ /* 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 int restart_in_progress = 0;
+
+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 */
+
+ if (restart_in_progress)
+ return HAL_ERROR_NOT_READY;
+
+ /* 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 (restart_in_progress)
+ return HAL_ERROR_NOT_READY;
+
+ 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 (restart_in_progress)
+ return HAL_ERROR_NOT_READY;
+
+ 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;
+
+ restart_in_progress = 1;
+
+ /* 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;
+ }
+ }
+
+ restart_in_progress = 0;
+ 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
index 2b3c1c1..a682cd2 100644
--- a/ks.c
+++ b/ks.c
@@ -514,6 +514,10 @@ static inline int acceptable_key_type(const hal_key_type_t type)
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;
@@ -1019,6 +1023,18 @@ hal_error_t hal_ks_rewrite_der(hal_ks_t *ks,
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
diff --git a/ks.h b/ks.h
index 559e46f..0649bcd 100644
--- a/ks.h
+++ b/ks.h
@@ -58,7 +58,7 @@
* the UUID generation code (by definition -- it's not a version 4 UUID).
*/
-const hal_uuid_t hal_ks_pin_uuid;
+extern const hal_uuid_t hal_ks_pin_uuid;
/*
* Known block states.
@@ -426,6 +426,8 @@ extern hal_error_t hal_ks_block_update(hal_ks_t *ks,
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_ */
/*
diff --git a/ks_volatile.c b/ks_volatile.c
index 55fd6a5..10fff9a 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -42,10 +42,6 @@
#include "hal_internal.h"
#include "ks.h"
-#ifndef STATIC_KS_VOLATILE_SLOTS
-#define STATIC_KS_VOLATILE_SLOTS HAL_STATIC_PKEY_STATE_BLOCKS
-#endif
-
#ifndef KS_VOLATILE_CACHE_SIZE
#define KS_VOLATILE_CACHE_SIZE 4
#endif
@@ -257,8 +253,8 @@ static hal_error_t ks_volatile_init(hal_ks_t *ks, const int alloc)
hal_error_t err;
if (alloc &&
- (err = hal_ks_alloc_common(ks, STATIC_KS_VOLATILE_SLOTS, KS_VOLATILE_CACHE_SIZE,
- &mem, sizeof(*db->keys) * STATIC_KS_VOLATILE_SLOTS)) != HAL_OK)
+ (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 (alloc)
diff --git a/locks.c b/locks.c
index 968ae98..7411143 100644
--- a/locks.c
+++ b/locks.c
@@ -103,6 +103,11 @@ WEAK_FUNCTION void hal_task_yield(void)
return;
}
+WEAK_FUNCTION void hal_task_yield_maybe(void)
+{
+ return;
+}
+
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/pbkdf2.c b/pbkdf2.c
index e9dc03b..be9e672 100644
--- a/pbkdf2.c
+++ b/pbkdf2.c
@@ -139,6 +139,8 @@ hal_error_t hal_pbkdf2(hal_core_t *core,
for (iteration = 2; iteration <= iterations_desired; iteration++) {
+ hal_task_yield_maybe();
+
if ((err = do_hmac(core, descriptor, password, password_length,
mac, descriptor->digest_length,
0, mac, sizeof(mac))) != HAL_OK)
diff --git a/rpc_api.c b/rpc_api.c
index 1dc8869..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);
diff --git a/rpc_client.c b/rpc_client.c
index afa05ac..e97289e 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
@@ -36,6 +36,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
@@ -137,7 +138,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;
@@ -150,7 +151,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;
@@ -168,7 +169,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));
@@ -203,7 +204,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));
@@ -296,7 +297,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;
@@ -311,8 +311,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;
}
@@ -356,7 +356,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));
@@ -380,7 +380,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));
@@ -395,7 +395,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;
@@ -409,7 +409,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;
@@ -425,27 +425,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;
}
@@ -462,7 +460,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));
@@ -486,14 +484,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));
@@ -503,7 +501,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;
}
@@ -521,7 +519,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));
@@ -537,7 +535,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;
}
@@ -675,12 +711,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,
@@ -689,7 +724,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;
@@ -703,8 +737,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;
}
@@ -717,7 +751,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;
@@ -725,7 +758,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));
@@ -733,8 +766,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;
}
@@ -754,8 +787,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));
@@ -800,12 +833,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));
@@ -818,8 +851,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;
}
@@ -851,7 +884,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));
@@ -902,10 +935,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;
}
}
@@ -936,13 +969,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;
}
@@ -959,15 +989,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));
@@ -977,7 +1007,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;
}
@@ -1102,6 +1132,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,
@@ -1124,6 +1155,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_pkey.c b/rpc_pkey.c
index 6ef520e..e1521af 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -38,6 +38,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
@@ -521,6 +522,68 @@ static hal_error_t pkey_local_generate_ec(const hal_client_handle_t client,
}
/*
+ * 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)
+{
+ hal_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;
+}
+
+/*
* Discard key handle, leaving key intact.
*/
@@ -539,6 +602,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)
{
@@ -552,6 +616,21 @@ static hal_error_t pkey_local_delete(const hal_pkey_handle_t pkey)
if ((err = check_writable(slot->client, slot->flags)) != HAL_OK)
return err;
+ 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)
@@ -633,9 +712,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;
@@ -645,6 +730,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;
@@ -658,6 +744,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;
}
@@ -681,10 +772,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;
@@ -694,6 +787,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)
@@ -712,6 +806,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;
@@ -812,6 +911,44 @@ static hal_error_t pkey_local_sign_ecdsa(hal_pkey_slot_t *slot,
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;
+
+ hal_assert(signature != NULL && signature_len != NULL);
+ hal_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,
@@ -828,13 +965,20 @@ static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey,
const hal_hash_handle_t hash,
const uint8_t * const input, const size_t input_len,
uint8_t * signature, size_t *signature_len, const size_t signature_max);
+ 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;
@@ -843,8 +987,7 @@ 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;
@@ -957,6 +1100,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;
+
+ hal_assert(signature != NULL && signature_len > 0);
+ hal_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,
@@ -972,15 +1149,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;
@@ -989,8 +1173,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;
@@ -1314,6 +1497,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 4a5fa4c..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 > (uint32_t)(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 > (uint32_t)(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 > (uint32_t)(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 > (uint32_t)(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 > (uint32_t)(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));
@@ -660,16 +581,16 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit
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 (size_t 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));
@@ -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));
@@ -761,26 +678,24 @@ static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * con
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 (size_t 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;
}
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/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-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-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/xdr.c b/xdr.c
index e7c81b2..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
@@ -38,7 +39,7 @@
#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,
@@ -61,7 +62,8 @@ 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)
@@ -72,44 +74,38 @@ hal_error_t hal_xdr_decode_int(const uint8_t ** const inbuf, const uint8_t * con
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 < (ptrdiff_t)(((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;
@@ -123,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 < (ptrdiff_t)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*/