diff options
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | cryptech/libhal.py | 35 | ||||
-rwxr-xr-x | cryptech_muxd | 12 | ||||
-rw-r--r-- | hal.h | 133 | ||||
-rw-r--r-- | hal_internal.h | 4 | ||||
-rw-r--r-- | hal_io_fmc.c | 72 | ||||
-rw-r--r-- | hashsig.c | 1135 | ||||
-rw-r--r-- | hashsig.h | 118 | ||||
-rw-r--r-- | mkm.c | 72 | ||||
-rw-r--r-- | rpc_api.c | 13 | ||||
-rw-r--r-- | rpc_client.c | 73 | ||||
-rw-r--r-- | rpc_client_daemon.c | 1 | ||||
-rw-r--r-- | rpc_misc.c | 2 | ||||
-rw-r--r-- | rpc_pkey.c | 212 | ||||
-rw-r--r-- | rpc_server.c | 48 | ||||
-rw-r--r-- | tests/Makefile | 16 | ||||
-rwxr-xr-x | tests/parallel-signatures.py | 63 | ||||
-rw-r--r-- | tests/test-rpc_hashsig.c | 524 | ||||
-rw-r--r-- | tests/test-xdr.c | 4 | ||||
-rw-r--r-- | unit-tests.py | 76 | ||||
-rw-r--r-- | utils/Makefile | 16 | ||||
-rw-r--r-- | utils/pkey-export.c | 187 | ||||
-rw-r--r-- | utils/pkey-import.c | 168 | ||||
-rw-r--r-- | utils/pkey.c | 1215 | ||||
-rw-r--r-- | uuid.c | 28 | ||||
-rw-r--r-- | xdr.c | 44 | ||||
-rw-r--r-- | xdr_internal.h | 2 |
27 files changed, 3035 insertions, 1252 deletions
@@ -1,4 +1,4 @@ -# Copyright (c) 2015-2017, NORDUnet A/S +# Copyright (c) 2015-2018, NORDUnet A/S # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -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 = 1280 +STATIC_KS_VOLATILE_SLOTS = 4352 LIB = libhal.a @@ -207,6 +207,8 @@ ifndef CRYPTECH_ROOT CRYPTECH_ROOT := $(abspath ../..) endif +LIBHAL_SRC ?= ${CRYPTECH_ROOT}/sw/libhal +LIBHAL_BLD ?= ${LIBHAL_SRC} LIBTFM_SRC ?= ${CRYPTECH_ROOT}/sw/thirdparty/libtfm LIBTFM_BLD ?= ${LIBTFM_SRC} @@ -221,7 +223,7 @@ 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${LIBHAL_SRC} CFLAGS += -I${LIBTFM_BLD} # Enable software hash cores everywhere for now. In theory, there might be situations @@ -239,6 +241,7 @@ CFLAGS += -DHAL_ENABLE_SOFTWARE_HASH_CORES=1 #export CFLAGS export RPC_MODE +export LIBHAL_SRC LIBHAL_BLD LIBTFM_BLD all: ${LIB} ${MAKE} -C tests $@ CFLAGS='${CFLAGS}' @@ -273,7 +276,6 @@ 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 >$@ @@ -283,8 +285,8 @@ test: all clean: rm -f *.o ${LIB} - ${MAKE} -C tests $@ CFLAGS='${CFLAGS}' - ${MAKE} -C utils $@ CFLAGS='${CFLAGS}' + ${MAKE} -C tests $@ + ${MAKE} -C utils $@ distclean: clean rm -f TAGS diff --git a/cryptech/libhal.py b/cryptech/libhal.py index 273a8a0..647dbd6 100644 --- a/cryptech/libhal.py +++ b/cryptech/libhal.py @@ -190,6 +190,7 @@ RPCFunc.define(''' RPC_FUNC_PKEY_GET_ATTRIBUTES, RPC_FUNC_PKEY_EXPORT, RPC_FUNC_PKEY_IMPORT, + RPC_FUNC_PKEY_GENERATE_HASHSIG, ''') class HALDigestAlgorithm(Enum): pass @@ -212,7 +213,11 @@ HALKeyType.define(''' 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 ''') class HALCurve(Enum): pass @@ -233,6 +238,28 @@ HALUser.define(''' HAL_USER_WHEEL ''') +class HALLmotsAlgorithm(Enum): pass + +HALLmotsAlgorithm.define(''' + HAL_LMOTS_RESERVED = 0, + HAL_LMOTS_SHA256_N32_W1 = 1, + HAL_LMOTS_SHA256_N32_W2 = 2, + HAL_LMOTS_SHA256_N32_W4 = 3, + HAL_LMOTS_SHA256_N32_W8 = 4 +''') + +class HALLmsAlgorithm(Enum): pass + +HALLmsAlgorithm.define(''' + HAL_LMS_RESERVED = 0, + HAL_LMS_SHA256_N32_H5 = 5, + HAL_LMS_SHA256_N32_H10 = 6, + HAL_LMS_SHA256_N32_H15 = 7, + HAL_LMS_SHA256_N32_H20 = 8, + HAL_LMS_SHA256_N32_H25 = 9 +''') + + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE = (1 << 0) HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT = (1 << 1) HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT = (1 << 2) @@ -585,6 +612,12 @@ class HSM(object): logger.debug("Generated EC pkey %s", pkey.uuid) return pkey + def pkey_generate_hashsig(self, L, lms, lmots, flags = 0, client = 0, session = 0): + with self.rpc(RPC_FUNC_PKEY_GENERATE_HASHSIG, session, L, lms, lmots, flags, client = client) as r: + pkey = PKey(self, r.unpack_uint(), UUID(bytes = r.unpack_bytes())) + logger.debug("Generated hashsig pkey %s", pkey.uuid) + return pkey + def pkey_close(self, pkey): try: logger.debug("Closing pkey %s", pkey.uuid) diff --git a/cryptech_muxd b/cryptech_muxd index 1aecb1e..ff40048 100755 --- a/cryptech_muxd +++ b/cryptech_muxd @@ -128,8 +128,16 @@ class SerialIOStream(tornado.iostream.BaseIOStream): def write_to_fd(self, data): return self.serial.write(data) - def read_from_fd(self): - return self.serial.read(self.read_chunk_size) or None + if tornado.version > "5": + # .. versionchanged:: 5.0 + # Interface redesigned to take a buffer and return a number + # of bytes instead of a freshly-allocated object. + def read_from_fd(self, buf): + buf[:] = self.serial.read(len(buf)) + return len(buf) or None + else: + def read_from_fd(self): + return self.serial.read(self.read_chunk_size) or None class PFUnixServer(tornado.tcpserver.TCPServer): @@ -55,7 +55,13 @@ * Should the versions be here even if the names should be? */ -#define NOVENA_BOARD_NAME "PVT1 " +#define ALPHA_BOARD_NAME "ALPHA " +#define ALPHA_BOARD_VERSION "0.20" + +#define FMC_INTERFACE_NAME "fmc " +#define FMC_INTERFACE_VERSION "0.20" + +#define NOVENA_BOARD_NAME "PVT1 " #define NOVENA_BOARD_VERSION "0.10" #define EIM_INTERFACE_NAME "eim " @@ -67,26 +73,29 @@ #define TRNG_NAME "trng " #define TRNG_VERSION "0.51" -#define AVALANCHE_ENTROPY_NAME "extnoise" +#define AVALANCHE_ENTROPY_NAME "extnoise" #define AVALANCHE_ENTROPY_VERSION "0.10" #define ROSC_ENTROPY_NAME "rosc ent" #define ROSC_ENTROPY_VERSION "0.10" +#define RNG_MIXER_NAME "rngmixer" +#define RNG_MIXER_VERSION "0.50" + #define CSPRNG_NAME "csprng " #define CSPRNG_VERSION "0.50" #define SHA1_NAME "sha1 " -#define SHA1_VERSION "0.50" +#define SHA1_VERSION "0.60" #define SHA256_NAME "sha2-256" -#define SHA256_VERSION "1.80" +#define SHA256_VERSION "1.82" #define SHA512_NAME "sha2-512" -#define SHA512_VERSION "0.80" +#define SHA512_VERSION "0.81" #define AES_CORE_NAME "aes " -#define AES_CORE_VERSION "0.80" +#define AES_CORE_VERSION "0.70" #define CHACHA_NAME "chacha " #define CHACHA_VERSION "0.80" @@ -98,16 +107,19 @@ #define MODEXPS6_VERSION "0.10" #define MODEXPA7_NAME "modexpa7" -#define MODEXPA7_VERSION "0.10" +#define MODEXPA7_VERSION "0.25" #define MKMIF_NAME "mkmif " #define MKMIF_VERSION "0.10" #define ECDSA256_NAME "ecdsa256" -#define ECDSA256_VERSION "0.11" +#define ECDSA256_VERSION "0.20" #define ECDSA384_NAME "ecdsa384" -#define ECDSA384_VERSION "0.11" +#define ECDSA384_VERSION "0.20" + +#define KEYWRAP_NAME "key wrap" +#define KEYWRAP_VERSION "0.70" #define KEYWRAP_NAME "key wrap" #define KEYWRAP_VERSION "0.70" @@ -820,16 +832,16 @@ 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; +typedef enum hal_lmots_algorithm_type hal_lmots_algorithm_t; +typedef enum hal_lms_algorithm_type hal_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_lms_algorithm_t lms_type, + const hal_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); @@ -909,6 +921,101 @@ extern hal_error_t hal_rpc_server_close(void); extern hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen); +/* + * Hash-Based Signatures. + * + * This really ought to be up with RSA and ECDSA, but it has forward + * references to hal_key_flags_t and hal_uuid_t. + */ + +enum hal_lmots_algorithm_type { + HAL_LMOTS_RESERVED = 0, + HAL_LMOTS_SHA256_N32_W1 = 1, + HAL_LMOTS_SHA256_N32_W2 = 2, + HAL_LMOTS_SHA256_N32_W4 = 3, + HAL_LMOTS_SHA256_N32_W8 = 4 +}; + +enum hal_lms_algorithm_type { + HAL_LMS_RESERVED = 0, + HAL_LMS_SHA256_N32_H5 = 5, + HAL_LMS_SHA256_N32_H10 = 6, + HAL_LMS_SHA256_N32_H15 = 7, + HAL_LMS_SHA256_N32_H20 = 8, + HAL_LMS_SHA256_N32_H25 = 9 +}; + +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_, + void *keybuf, const size_t keybuf_len, + const size_t hss_levels, + const hal_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, + const hal_key_flags_t flags); + +extern hal_error_t hal_hashsig_delete(const hal_uuid_t * const name); + +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 *sig, size_t *sig_len, const size_t sig_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 sig, const size_t sig_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 hal_lms_algorithm_t lms_type, + const hal_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 hal_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type); + +extern size_t hal_hashsig_lmots_private_key_len(const hal_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); + +extern hal_error_t hal_hashsig_export(const hal_uuid_t * const name, + uint8_t *der, size_t *der_len, const size_t der_max); + +extern hal_error_t hal_hashsig_import(const uint8_t *der, const size_t der_len, + const hal_key_flags_t flags); + #endif /* _HAL_H_ */ /* diff --git a/hal_internal.h b/hal_internal.h index 94546c3..15f4c79 100644 --- a/hal_internal.h +++ b/hal_internal.h @@ -310,8 +310,8 @@ typedef struct { 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_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, const hal_key_flags_t flags); hal_error_t (*close)(const hal_pkey_handle_t pkey); diff --git a/hal_io_fmc.c b/hal_io_fmc.c index 07f9352..590532b 100644 --- a/hal_io_fmc.c +++ b/hal_io_fmc.c @@ -53,32 +53,17 @@ #define HAL_IO_FMC_DEBUG 0 #endif -static int debug = 0; static int inited = 0; -static inline hal_error_t init(void) -{ - if (!inited) { - fmc_init(); - inited = 1; - } - return HAL_OK; -} +#if HAL_IO_FMC_DEBUG -/* Translate cryptech register number to FMC address. - */ -static inline hal_addr_t fmc_offset(hal_addr_t offset) -{ - return offset << 2; -} +static int debug = 0; void hal_io_set_debug(int onoff) { debug = onoff; } -#if HAL_IO_FMC_DEBUG - static inline void dump(const char *label, const hal_addr_t offset, const uint8_t * const buf, const size_t len) { if (debug) { @@ -95,56 +80,89 @@ static inline void dump(const char *label, const hal_addr_t offset, const uint8_ #endif -hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_t *buf, size_t len) +/* + * Translate cryptech register number to FMC address. + */ +static inline hal_addr_t fmc_offset(hal_addr_t offset) +{ + return offset << 2; +} + +/* + * Minimal version of memcpy, where we know the addresses and length are + * word-aligned. + */ +static inline void fmc_fpga_memcpy(uint32_t *dst, uint32_t *src, size_t nword) { - hal_error_t err; + while (nword >= 4) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + nword -= 4; + } + while (nword > 0) { + *dst++ = *src++; + nword--; + } +} +hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_t *buf, size_t len) +{ if (core == NULL) return HAL_ERROR_CORE_NOT_FOUND; if (len % 4 != 0) return HAL_ERROR_IO_BAD_COUNT; - if ((err = init()) != HAL_OK) - return err; + if (!inited) { + fmc_init(); + inited = 1; + } dump("write ", offset + hal_core_base(core), buf, len); offset = fmc_offset(offset + hal_core_base(core)); +<<<<<<< HEAD + fmc_fpga_memcpy((uint32_t *)fmc_fpga_addr(offset), (uint32_t *)buf, len/4); +======= for (; len > 0; offset += 4, buf += 4, len -= 4) { uint32_t val; val = htonl(*(uint32_t *)buf); if (fmc_write_32(offset, val) != 0) return HAL_ERROR_IO_TIMEOUT; } +>>>>>>> e4fa00258cd920d4ea91b024ee007f5b44bac196 return HAL_OK; } hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf, size_t len) { - uint8_t *rbuf = buf; - int rlen = len; - hal_error_t err; - if (core == NULL) return HAL_ERROR_CORE_NOT_FOUND; if (len % 4 != 0) return HAL_ERROR_IO_BAD_COUNT; - if ((err = init()) != HAL_OK) - return err; + if (!inited) { + fmc_init(); + inited = 1; + } dump("read ", offset + hal_core_base(core), buf, len); offset = fmc_offset(offset + hal_core_base(core)); +<<<<<<< HEAD + fmc_fpga_memcpy((uint32_t *)buf, (uint32_t *)fmc_fpga_addr(offset), len/4); +======= for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) { uint32_t val; if (fmc_read_32(offset, &val) != 0) return HAL_ERROR_IO_TIMEOUT; *(uint32_t *)rbuf = ntohl(val); } +>>>>>>> e4fa00258cd920d4ea91b024ee007f5b44bac196 return HAL_OK; } @@ -1,7 +1,7 @@ /* * hashsig.c * --------- - * Implementation of draft-mcgrew-hash-sigs-10.txt + * Implementation of draft-mcgrew-hash-sigs-15.txt * * Copyright (c) 2018, NORDUnet A/S All rights reserved. * @@ -33,13 +33,11 @@ */ #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 @@ -48,7 +46,7 @@ typedef struct { uint8_t bytes[16]; } bytestring16; #define u32str(X) htonl(X) #define u16str(X) htons(X) -#define u8str(X) (X & 0xff) +#define u8str(X) ((X) & 0xff) #define check(op) do { hal_error_t _err = (op); if (_err != HAL_OK) return _err; } while (0) @@ -73,19 +71,19 @@ static inline hal_error_t hal_xdr_decode_bytestring32(const uint8_t ** const inb 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) +static inline hal_error_t hal_xdr_encode_uuid(uint8_t ** const outbuf, const uint8_t * const limit, const hal_uuid_t *value) { - return hal_xdr_encode_fixed_opaque(outbuf, limit, (const uint8_t *)value, sizeof(bytestring16)); + return hal_xdr_encode_fixed_opaque(outbuf, limit, (const uint8_t *)value, sizeof(hal_uuid_t)); } -static inline hal_error_t hal_xdr_decode_bytestring16_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring16 **value) +static inline hal_error_t hal_xdr_decode_uuid_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, hal_uuid_t **value) { - return hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, (const uint8_t ** const)value, sizeof(bytestring16)); + return hal_xdr_decode_fixed_opaque_ptr(inbuf, limit, (const uint8_t ** const)value, sizeof(hal_uuid_t)); } -static inline hal_error_t hal_xdr_decode_bytestring16(const uint8_t ** const inbuf, const uint8_t * const limit, bytestring16 * const value) +static inline hal_error_t hal_xdr_decode_uuid(const uint8_t ** const inbuf, const uint8_t * const limit, hal_uuid_t * const value) { - return hal_xdr_decode_fixed_opaque(inbuf, limit, (uint8_t * const)value, sizeof(bytestring16)); + return hal_xdr_decode_fixed_opaque(inbuf, limit, (uint8_t * const)value, sizeof(hal_uuid_t)); } /* ---------------------------------------------------------------- */ @@ -116,34 +114,34 @@ static inline hal_error_t hal_asn1_decode_size_t(size_t *np, const uint8_t * con } } -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) +static inline hal_error_t hal_asn1_encode_lms_algorithm(const hal_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) +static inline hal_error_t hal_asn1_decode_lms_algorithm(hal_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; + *type = (hal_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) +static inline hal_error_t hal_asn1_encode_lmots_algorithm(const hal_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) +static inline hal_error_t hal_asn1_decode_lmots_algorithm(hal_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; + *type = (hal_lmots_algorithm_t)n; return err; } @@ -158,16 +156,6 @@ static inline hal_error_t hal_asn1_decode_uuid(hal_uuid_t *data, const uint8_t * 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); @@ -185,44 +173,46 @@ static inline hal_error_t hal_asn1_decode_bytestring32(bytestring32 *data, const */ typedef const struct lmots_parameter_set { - lmots_algorithm_t type; - size_t n, w, p, ls; + hal_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 }, + { HAL_LMOTS_SHA256_N32_W1, 32, 1, 265, 7 }, + { HAL_LMOTS_SHA256_N32_W2, 32, 2, 133, 6 }, + { HAL_LMOTS_SHA256_N32_W4, 32, 4, 67, 4 }, + { HAL_LMOTS_SHA256_N32_W8, 32, 8, 34, 0 }, }; typedef struct lmots_key { hal_key_type_t type; lmots_parameter_t *lmots; - bytestring16 I; + hal_uuid_t 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) +static inline lmots_parameter_t *lmots_select_parameter_set(const hal_lmots_algorithm_t lmots_type) { - if (lmots_type < lmots_sha256_n32_w1 || lmots_type > lmots_sha256_n32_w8) + if (lmots_type < HAL_LMOTS_SHA256_N32_W1 || lmots_type > HAL_LMOTS_SHA256_N32_W8) return NULL; else - return &lmots_parameters[lmots_type - lmots_sha256_n32_w1]; + return &lmots_parameters[lmots_type - HAL_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); + return 2 * sizeof(uint32_t) + sizeof(hal_uuid_t) + (lmots->p * lmots->n); } +#if 0 /* currently unused */ 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; + return 2 * sizeof(uint32_t) + sizeof(hal_uuid_t) + lmots->n; } +#endif static inline size_t lmots_signature_len(lmots_parameter_t * const lmots) { @@ -235,31 +225,44 @@ static inline size_t lmots_signature_len(lmots_parameter_t * const lmots) * public key components (x and K). * Let the caller worry about storage. */ -static hal_error_t lmots_generate(lmots_key_t * const key) +static hal_error_t lmots_generate(lmots_key_t * const key, bytestring32 *seed) { 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 -// } + /* generate the private key */ - for (size_t i = 0; i < p; ++i) - check(hal_rpc_get_random(&key->x[i], n)); + if (seed == NULL) { + /* fill x[] with random goodness */ + 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 + else { + /* use the pseudorandom key generation scheme */ + for (size_t i = 0; i < p; ++i) { + uint8_t statebuf[512]; + hal_hash_state_t *state = NULL; + uint32_t l; + uint16_t s; + uint8_t b; -// 4. compute the string K as follows: + /* x_q[i] = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED) */ + 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(0xff); check(hal_hash_update(state, (const uint8_t *)&b, sizeof(b))); + check(hal_hash_update(state, (const uint8_t *)seed, sizeof(bytestring32))); + check(hal_hash_finalize(state, (uint8_t *)&key->x[i], sizeof(bytestring32))); + } + } + + /* generate the public key */ uint8_t statebuf[512]; hal_hash_state_t *state = NULL; @@ -268,32 +271,21 @@ static hal_error_t lmots_generate(lmots_key_t * const key) 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 ) { + y[i] = key->x[i]; for (size_t j = 0; j < (1U << w) - 1; ++j) { - -// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) + /* y[i] = H(I || u32str(q) || u16str(i) || u8str(j) || y[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(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))); + check(hal_hash_update(state, (const uint8_t *)&y[i], sizeof(y[i]))); + check(hal_hash_finalize(state, (uint8_t *)&y[i], sizeof(y[i]))); } - -// y[i] = tmp - memcpy(&y[i], &tmp, sizeof(tmp)); -// } } -// K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) + /* 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))); @@ -342,13 +334,6 @@ static hal_error_t lmots_sign(lmots_key_t *key, 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; @@ -356,15 +341,9 @@ static hal_error_t lmots_sign(lmots_key_t *key, 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 */ @@ -372,7 +351,7 @@ static hal_error_t lmots_sign(lmots_key_t *key, uint16_t s; uint8_t b; -// Q = H(I || u32str(q) || u16str(D_MESG) || C || message) + /* 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))); @@ -386,35 +365,22 @@ static hal_error_t lmots_sign(lmots_key_t *key, 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 ) { + y[i] = key->x[i]; for (size_t j = 0; j < (size_t)a; ++j) { - -// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) + /* y[i] = H(I || u32str(q) || u16str(i) || u8str(j) || y[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(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))); -// } + check(hal_hash_update(state, (const uint8_t *)&y[i], sizeof(y[i]))); + check(hal_hash_finalize(state, (uint8_t *)&y[i], sizeof(y[i]))); } - -// y[i] = tmp - memcpy(&y[i], &tmp, sizeof(tmp)); } -// 6. return u32str(type) || C || y[0] || ... || y[p-1] + /* sig = 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)); @@ -440,45 +406,26 @@ static hal_error_t lmots_public_key_candidate(const lmots_key_t * const key, * 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) + if ((hal_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 */ @@ -486,7 +433,7 @@ static hal_error_t lmots_public_key_candidate(const lmots_key_t * const key, uint16_t s; uint8_t b; -// Q = H(I || u32str(q) || u16str(D_MESG) || C || message) + /* 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))); @@ -500,36 +447,22 @@ static hal_error_t lmots_public_key_candidate(const lmots_key_t * const key, 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 ) { + z[i] = y[i]; for (size_t j = (size_t)a; j < (1U << w) - 1; ++j) { - -// tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) + /* z[i] = H(I || u32str(q) || u16str(i) || u8str(j) || z[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(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))); -// } + check(hal_hash_update(state, (const uint8_t *)&z[i], sizeof(z[i]))); + check(hal_hash_finalize(state, (uint8_t *)&z[i], sizeof(z[i]))); } - -// z[i] = tmp - memcpy(&z[i], &tmp, sizeof(tmp)); -// } } -// Kc = H(I || u32str(q) || u16str(D_PBLC) || z[0] || z[1] || ... || z[p-1]) + /* Kc = H(I || u32str(q) || u16str(D_PBLC) || z[] */ 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))); @@ -538,7 +471,6 @@ static hal_error_t lmots_public_key_candidate(const lmots_key_t * const key, 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; } @@ -549,17 +481,15 @@ static hal_error_t lmots_private_key_to_der(const lmots_key_t * const key, 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] + /* u32str(lmots_type) || I || u32str(q) || K || x[] */ /* K is not an integral part of the private key, but we store it to speed up restart */ - /* - * Calculate data length. - */ + /* 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_uuid(&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) { @@ -574,9 +504,7 @@ static hal_error_t lmots_private_key_to_der(const lmots_key_t * const key, if (der == NULL) return HAL_OK; - /* - * Encode data. - */ + /* Encode data. */ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)); @@ -584,7 +512,7 @@ static hal_error_t lmots_private_key_to_der(const lmots_key_t * const key, 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_uuid(&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) { @@ -627,12 +555,12 @@ static hal_error_t lmots_private_key_from_der(lmots_key_t *key, const uint8_t *d = privkey + hlen; size_t len; - // u32str(lmots_type) || I || u32str(q) || K || x[0] || x[1] || ... || x[p-1] + /* u32str(lmots_type) || I || u32str(q) || K || x[] */ - lmots_algorithm_t lmots_type; + hal_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_uuid(&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) { @@ -655,15 +583,15 @@ static hal_error_t lmots_private_key_from_der(lmots_key_t *key, */ typedef const struct lms_parameter_set { - lms_algorithm_t type; - size_t m, h; + hal_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 }, + { HAL_LMS_SHA256_N32_H5, 32, 5 }, + { HAL_LMS_SHA256_N32_H10, 32, 10 }, + { HAL_LMS_SHA256_N32_H15, 32, 15 }, + { HAL_LMS_SHA256_N32_H20, 32, 20 }, + { HAL_LMS_SHA256_N32_H25, 32, 25 }, }; typedef struct lms_key { @@ -671,8 +599,9 @@ typedef struct lms_key { size_t level; lms_parameter_t *lms; lmots_parameter_t *lmots; - bytestring16 I; + hal_uuid_t I; size_t q; /* index of next lmots signing key */ + size_t q_end; hal_uuid_t *lmots_keys; /* private key components */ bytestring32 *T; /* public key components */ bytestring32 T1; /* copy of T[1] */ @@ -682,12 +611,12 @@ typedef struct lms_key { size_t signature_len; } lms_key_t; -static inline lms_parameter_t *lms_select_parameter_set(const lms_algorithm_t lms_type) +static inline lms_parameter_t *lms_select_parameter_set(const hal_lms_algorithm_t lms_type) { - if (lms_type < lms_sha256_n32_h5 || lms_type > lms_sha256_n32_h25) + if (lms_type < HAL_LMS_SHA256_N32_H5 || lms_type > HAL_LMS_SHA256_N32_H25) return NULL; else - return &lms_parameters[lms_type - lms_sha256_n32_h5]; + return &lms_parameters[lms_type - HAL_LMS_SHA256_N32_H5]; } static inline size_t lms_public_key_len(lms_parameter_t * const lms) @@ -703,46 +632,68 @@ static inline size_t lms_signature_len(lms_parameter_t * const lms, lmots_parame } #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) +static hal_error_t lms_compute_T_leaf(lms_key_t *key, lmots_key_t *lmots_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; + /* compute T[r] = H(I || u32str(r) || u16str(D_LEAF) || K) */ + size_t r = (1U << key->lms->h) + lmots_key->q; + uint8_t statebuf[512]; + hal_hash_state_t *state = NULL; + 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))); + uint32_t l = u32str(r); check(hal_hash_update(state, (const uint8_t *)&l, sizeof(l))); + uint16_t 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]))); + + return HAL_OK; +} + +static hal_error_t lms_compute_T_intr(lms_key_t *key) +{ + /* generate the rest of T[r] = H(I || u32str(r) || u16str(D_INTR) || T[2*r] || T[2*r+1]) */ + for (size_t r = (1U << key->lms->h) - 1; r > 0; --r) { + uint8_t statebuf[512]; + hal_hash_state_t *state = NULL; + 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))); + uint32_t l = u32str(r); check(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))); + 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(); + } - check(hal_uuid_gen((hal_uuid_t *)&key->I)); - key->q = 0; + return HAL_OK; +} +static hal_error_t lms_generate_lmots(lms_key_t *key, size_t q, bytestring32 *seed) +{ bytestring32 x[key->lmots->p]; lmots_key_t lmots_key = { .type = HAL_KEY_TYPE_HASHSIG_LMOTS, .lmots = key->lmots, + .I = key->I, + .q = q, .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; + /* generate the lmots private and public key components */ + check(lmots_generate(&lmots_key, seed)); - 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)); + /* Note: we have to generate all the lmots keys, even if q > 0 or + * q_end < 2^h, because we need them to calculate T[]. + * We just don't need to store the ones that are out of range. + */ + if (q >= key->q && q < key->q_end) { /* store the lmots key */ + hal_ks_t *ks = (key->level == 0) ? hal_ks_token : hal_ks_volatile; + 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) + }; 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))); @@ -753,42 +704,53 @@ static hal_error_t lms_generate(lms_key_t *key) if (err != HAL_OK) return err; /* record the lmots keystore name */ - memcpy(&key->lmots_keys[q], &slot.name, sizeof(slot.name)); + key->lmots_keys[q] = slot.name; + } + else + memset(&x, 0, sizeof(x)); - /* 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]))); + /* compute T[r] = H(I || u32str(r) || u16str(D_LEAF) || K) */ + check(lms_compute_T_leaf(key, &lmots_key)); + + return HAL_OK; +} + +/* 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, bytestring32 *seed) +{ + 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; + + hal_uuid_t I_0 = {{0}}; + if (hal_uuid_cmp(&key->I, &I_0) == 0) + check(hal_uuid_gen(&key->I)); + + /* private key - array of lmots key names */ + for (size_t q = 0; q < (1U << key->lms->h); ++q) { + check(lms_generate_lmots(key, q, seed)); 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(); - } + check(lms_compute_T_intr(key)); - memcpy(&key->T1, &key->T[1], sizeof(key->T1)); + key->T1 = key->T[1]; /* 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] + + /* 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_uuid(&pubkey, publim, &key->I)); check(hal_xdr_encode_bytestring32(&pubkey, publim, &key->T1)); return HAL_OK; @@ -796,18 +758,21 @@ static hal_error_t lms_generate(lms_key_t *key) 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; + hal_pkey_slot_t slot = {{0}}; + hal_uuid_t uuid_0 = {{0}}; /* 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(); + if (hal_uuid_cmp(&key->lmots_keys[i], &uuid_0) != 0) { + slot.name = key->lmots_keys[i]; + (void)hal_ks_delete(ks, &slot); + hal_task_yield_maybe(); + } } /* delete the lms key */ - memcpy(&slot.name, &key->I, sizeof(slot.name)); + slot.name = key->I; return hal_ks_delete(ks, &slot); } @@ -821,7 +786,7 @@ static hal_error_t lms_sign(lms_key_t * const key, 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)) + if (key->q >= key->q_end) return HAL_ERROR_HASHSIG_KEY_EXHAUSTED; if (sig_max < lms_signature_len(key->lms, key->lmots)) @@ -834,9 +799,9 @@ static hal_error_t lms_sign(lms_key_t * const key, 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)); + hal_pkey_slot_t slot = { + .name = key->lmots_keys[key->q] + }; lmots_key_t lmots_key; memset(&lmots_key, 0, sizeof(lmots_key)); @@ -851,7 +816,7 @@ static hal_error_t lms_sign(lms_key_t * const key, check(lmots_private_key_from_der(&lmots_key, der, der_len)); memset(&der, 0, sizeof(der)); - //? check lmots_type and I vs. lms key? + /* check lmots_type and I vs. lms key? */ /* generate the lmots signature */ size_t lmots_sig_len; @@ -873,7 +838,7 @@ static hal_error_t lms_sign(lms_key_t * const key, 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)); + slot.name = key->I; check(hal_ks_rewrite_der(ks, &slot, der, der_len)); return HAL_OK; @@ -899,34 +864,9 @@ static hal_error_t lms_verify(const lms_key_t * const 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); } @@ -935,100 +875,54 @@ static hal_error_t lms_public_key_candidate(const lms_key_t * const key, 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) + if ((hal_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) + if ((hal_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, + .I = key->I, .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) + /* 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))); @@ -1037,15 +931,8 @@ static hal_error_t lms_public_key_candidate(const lms_key_t * const key, 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 -// } + /* odd nodes: tmp = H(I || u32str(node_num/2) || u16str(D_INTR) || path[i] || tmp) */ + /* even nodes: tmp = H(I || u32str(node_num/2) || u16str(D_INTR) || tmp || path[i]) */ 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))); @@ -1062,8 +949,7 @@ static hal_error_t lms_public_key_candidate(const lms_key_t * const key, check(hal_hash_finalize(state, (uint8_t *)&tmp, sizeof(tmp))); } -// Tc = tmp - memcpy(Tc, &tmp, sizeof(*Tc)); + *Tc = tmp; return HAL_OK; } @@ -1075,18 +961,17 @@ static hal_error_t lms_private_key_to_der(const lms_key_t * const key, 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 || q_end */ - // u32str(lms_type) || u32str(lmots_type) || I || q + /* Calculate data length. */ 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_uuid(&key->I, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_size_t(key->q, NULL, &len, 0)); vlen += len; + check(hal_asn1_encode_size_t(key->q_end, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0)); @@ -1096,9 +981,7 @@ static hal_error_t lms_private_key_to_der(const lms_key_t * const key, if (der == NULL) return HAL_OK; - /* - * Encode data. - */ + /* Encode data. */ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)); @@ -1107,8 +990,9 @@ static hal_error_t lms_private_key_to_der(const lms_key_t * const key, 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_uuid(&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_size_t(key->q_end, 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); @@ -1126,6 +1010,8 @@ static hal_error_t lms_private_key_from_der(lms_key_t *key, if (key == NULL || der == NULL) return HAL_ERROR_BAD_ARGUMENTS; + memset(key, 0, sizeof(*key)); + key->type = HAL_KEY_TYPE_HASHSIG_LMS; size_t hlen, vlen, alg_oid_len, curve_oid_len, privkey_len; @@ -1146,16 +1032,17 @@ static hal_error_t lms_private_key_from_der(lms_key_t *key, const uint8_t *d = privkey + hlen; size_t n; - // u32str(lms_type) || u32str(lmots_type) || I || q + /* u32str(lms_type) || u32str(lmots_type) || I || q || q_end */ - lms_algorithm_t lms_type; + hal_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; + hal_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_uuid(&key->I, d, &n, vlen)); d += n; vlen -= n; check(hal_asn1_decode_size_t(&key->q, d, &n, vlen)); d += n; vlen -= n; + check(hal_asn1_decode_size_t(&key->q_end, d, &n, vlen)); d += n; vlen -= n; if (d != privkey + privkey_len) return HAL_ERROR_ASN1_PARSE_FAILED; @@ -1183,8 +1070,10 @@ struct hal_hashsig_key { size_t L; lms_parameter_t *lms; lmots_parameter_t *lmots; - bytestring16 I; + hal_uuid_t I; + size_t q_start, q_end; bytestring32 T1; + bytestring32 seed; lms_key_t *lms_keys; }; @@ -1192,11 +1081,23 @@ const size_t hal_hashsig_key_t_size = sizeof(hss_key_t); static hss_key_t *hss_keys = NULL; +static hss_key_t *hss_find(hal_uuid_t *I) +{ + for (hss_key_t *key = hss_keys; key != NULL; key = key->next) { + if (memcmp(&key->I, I, sizeof(*I)) == 0) + return key; + } + + return NULL; +} + +#if 0 /* currently unused */ 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); } +#endif static inline size_t hss_signature_len(const size_t L, lms_parameter_t * const lms, lmots_parameter_t * const lmots) { @@ -1205,8 +1106,8 @@ static inline size_t hss_signature_len(const size_t L, lms_parameter_t * const l } size_t hal_hashsig_signature_len(const size_t L, - const lms_algorithm_t lms_type, - const lmots_algorithm_t lmots_type) + const hal_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type) { lms_parameter_t * const lms = lms_select_parameter_set(lms_type); if (lms == NULL) @@ -1219,7 +1120,7 @@ size_t hal_hashsig_signature_len(const size_t L, return hss_signature_len(L, lms, lmots); } -size_t hal_hashsig_lmots_private_key_len(const lmots_algorithm_t lmots_type) +size_t hal_hashsig_lmots_private_key_len(const hal_lmots_algorithm_t lmots_type) { lmots_parameter_t * const lmots = lmots_select_parameter_set(lmots_type); if (lmots == NULL) @@ -1241,25 +1142,18 @@ static inline void *gnaw(uint8_t **mem, size_t *len, const size_t 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) +static hal_error_t hss_alloc(hal_hashsig_key_t **key_) { - if (key_ == NULL) + if (key_ == NULL || *key_ == NULL || + (*key_)->type != HAL_KEY_TYPE_HASHSIG_PRIVATE || + (*key_)->L == 0 || (*key_)->L > 8 || + (*key_)->lms == NULL || (*key_)->lmots == 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; + size_t L = (*key_)->L; + lms_parameter_t *lms = (*key_)->lms; + lmots_parameter_t *lmots = (*key_)->lmots; + size_t h2 = (1U << lms->h); /* 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 @@ -1294,114 +1188,163 @@ static hal_error_t hss_alloc(hal_hashsig_key_t **key_, memset(mem, 0, len); /* allocate the key that will stay in working memory */ - hss_key_t *key = gnaw(&mem, &len, sizeof(hss_key_t)); + hss_key_t *key = gnaw(&mem, &len, sizeof(*key)); + + /* initialize it from the transitory key */ + *key = **key_; *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 */ + /* add the in-memory key 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->lmots_keys = 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; + lms_key->q_end = h2; } 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) +static hal_error_t hss_generate(hss_key_t **key_, const hal_key_flags_t flags) { - /* hss_alloc does most of the checks */ - - if (restart_in_progress) - return HAL_ERROR_NOT_READY; + /* Hashsig keys can only be used for signing, so it makes sense to check + * that now, rather than waiting until the user tries to sign. + * + * Also, the top-level tree must be stored in the token (flash) keystore. + * I experimented with allowing keys to be stored in the volatile + * keystore, but that had some ugly consequences around the fact that + * volatile keys are automatically deleted when the user logs out. I'm + * also not sure there's a good use case for volatile hashsig keys. + */ + if (!(flags & HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) || + !(flags & HAL_KEY_FLAG_TOKEN)) + return HAL_ERROR_FORBIDDEN; - /* check flash keystore for space to store the root tree */ - lms_parameter_t *lms = lms_select_parameter_set(lms_type); - if (lms == NULL) + if (key_ == NULL || *key_ == NULL || (*key_)->lms == NULL) return HAL_ERROR_BAD_ARGUMENTS; + + /* hss_alloc does most of the sanity checks */ + + /* check flash keystore for space to store the root tree: + * 2^h lmots keys + 1 lms key + 1 hss key + */ size_t available; check(hal_ks_available(hal_ks_token, &available)); - if (available < (1U << lms->h) + 2) + if (available < (*key_)->q_end - (*key_)->q_start + 2) return HAL_ERROR_NO_KEY_INDEX_SLOTS; - check(hss_alloc(key_, L, lms_type, lmots_type)); + check(hss_alloc(key_)); hss_key_t *key = *key_; + hal_error_t err; /* generate the lms trees */ - for (size_t i = 0; i < L; ++i) { + for (size_t i = 0; i < key->L; ++i) { lms_key_t * lms_key = &key->lms_keys[i]; + bytestring32 *seed = NULL; + + if (i == 0) { + lms_key->I = key->I; + lms_key->q = key->q_start; + lms_key->q_end = key->q_end; + + /* If we're called from import, seed will be filled in. + * If called from key_gen, seed will be 0, and we may need to + * generate it. + */ + bytestring32 seed_0 = {{0}}; + if (memcmp(&key->seed, &seed_0, sizeof(seed_0)) != 0) { + seed = &key->seed; + } + else if (flags & HAL_KEY_FLAG_EXPORTABLE) { + seed = &key->seed; + if ((err = hal_rpc_get_random(seed, sizeof(*seed))) != HAL_OK) + goto err_out; + } + } - check(lms_generate(lms_key)); + if ((err = lms_generate(lms_key, seed)) != HAL_OK) + goto err_out; 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))); + if ((err = 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))) != HAL_OK) + goto err_out; /* store the lms key */ + hal_ks_t *ks = (i == 0) ? hal_ks_token : hal_ks_volatile; hal_pkey_slot_t slot = { .type = HAL_KEY_TYPE_HASHSIG_LMS, - .curve = HAL_CURVE_NONE, + .name = lms_key->I, .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)); + if ((err = lms_private_key_to_der(lms_key, der, &der_len, sizeof(der))) != HAL_OK || + (err = hal_ks_store(ks, &slot, der, der_len)) != HAL_OK) + goto err_out; } - memcpy(&key->I, &key->lms_keys[0].I, sizeof(key->I)); - memcpy(&key->T1, &key->lms_keys[0].T1, sizeof(key->T1)); + key->I = key->lms_keys[0].I; + key->T1 = key->lms_keys[0].T1; /* pkey_local_generate_hashsig stores the key */ return HAL_OK; + +err_out: + (void)hal_free_static_memory(key); + return err; } -/* caller will delete the hss key from the keystore */ -hal_error_t hal_hashsig_key_delete(const hal_hashsig_key_t * const key) -{ +/* called from pkey_local_generate_hashsig + * caller will store the key + */ +hal_error_t hal_hashsig_key_gen(hal_core_t *core, + hal_hashsig_key_t **key_, + void *keybuf, const size_t keybuf_len, + const size_t L, + const hal_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, + const hal_key_flags_t flags) +{ + if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hss_key_t)) + return HAL_ERROR_BAD_ARGUMENTS; + 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])); + hss_key_t *key = *key_ = keybuf; + memset(key, 0, sizeof(*key)); + key->type = HAL_KEY_TYPE_HASHSIG_PRIVATE; + key->L = L; + key->lms = lms_select_parameter_set(lms_type); + key->lmots = lmots_select_parameter_set(lmots_type); + key->q_end = (1U << key->lms->h); - /* XXX free memory, if supported */ - (void)hal_free_static_memory(key); + return hss_generate(key_, flags); +} - /* remove from global hss_keys linked list */ - /* XXX or mark it unused, for possible re-use */ +static void hss_delete(hss_key_t *key) +{ + /* remove key from global hss_keys linked list */ if (hss_keys == key) { hss_keys = key->next; } @@ -1414,6 +1357,41 @@ hal_error_t hal_hashsig_key_delete(const hal_hashsig_key_t * const key) } } + /* delete the lms trees and their lmots keys */ + for (size_t level = 0; level < key->L; ++level) + (void)lms_delete(&key->lms_keys[level]); + + /* free memory, if possible */ + (void)hal_free_static_memory(key); +} + +/* caller will delete the hss key from the keystore */ +hal_error_t hal_hashsig_delete(const hal_uuid_t * const name) +{ + if (restart_in_progress) + return HAL_ERROR_NOT_READY; + + hal_pkey_slot_t slot = { .name = *name }; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + size_t der_len; + check(hal_ks_fetch(hal_ks_token, &slot, der, &der_len, sizeof(der))); + + hal_hashsig_key_t keybuf, *key; + check(hal_hashsig_private_key_from_der(&key, &keybuf, sizeof(keybuf), der, der_len)); + + /* hal_hashsig_private_key_from_der returns the key in the list of + * active hashsig keys, so we don't need this temporary key. + */ + memset(der, 0, sizeof(der)); + memset(&keybuf, 0, sizeof(keybuf)); + + /* OTOH, if we found the key in the keystore, but not in the list of + * active hashsig keys, that's Bad. + */ + if (key == &keybuf) + return HAL_ERROR_KEY_NOT_FOUND; + + hss_delete(key); return HAL_OK; } @@ -1431,24 +1409,10 @@ hal_error_t hal_hashsig_sign(hal_core_t *core, 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) { + /* if the signing key is exhausted, try to regenerate it */ + if (key->lms_keys[key->L-1].q >= key->lms_keys[key->L-1].q_end) { size_t d; - for (d = key->L-1; d > 0 && key->lms_keys[d-1].q >= h2; --d) { + for (d = key->L-1; d > 0 && key->lms_keys[d-1].q >= key->lms_keys[d-1].q_end; --d) { } if (d == 0) return HAL_ERROR_HASHSIG_KEY_EXHAUSTED; @@ -1461,36 +1425,26 @@ hal_error_t hal_hashsig_sign(hal_core_t *core, * any additional memory. */ check(lms_delete(lms_key)); - check(lms_generate(lms_key)); + lms_key->q = 0; + check(lms_generate(lms_key, NULL)); 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 + .name = lms_key->I, + .flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | (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)); + check(hal_ks_store(hal_ks_volatile, &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]. - + /* sig = 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)); @@ -1517,19 +1471,10 @@ hal_error_t hal_hashsig_verify(hal_core_t *core, 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) + if (key == NULL || (key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE && 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 + /* sig = u32str(Nspk) || signed_pub_key[0] || ... || signed_pub_key[Nspk-1] || sig[Nspk] */ const uint8_t *sigptr = sig; const uint8_t * const siglim = sig + sig_len; @@ -1539,22 +1484,13 @@ hal_error_t hal_hashsig_verify(hal_core_t *core, 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 + .lmots = key->lmots, + .I = key->I, + .T1 = key->T1 }; - 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; @@ -1567,7 +1503,7 @@ hal_error_t hal_hashsig_verify(hal_core_t *core, /* 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); + lmots_parameter_t *lmots = lmots_select_parameter_set((hal_lmots_algorithm_t)lmots_type); if (lmots == NULL) return HAL_ERROR_INVALID_SIGNATURE; /* skip over ots_signature */ @@ -1575,7 +1511,7 @@ hal_error_t hal_hashsig_verify(hal_core_t *core, /* 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); + lms_parameter_t *lms = lms_select_parameter_set((hal_lms_algorithm_t)lms_type); if (lms == NULL) return HAL_ERROR_INVALID_SIGNATURE; /* skip over the path elements of the lms signature */ @@ -1587,14 +1523,14 @@ hal_error_t hal_hashsig_verify(hal_core_t *core, /* 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); + pub.lms = lms_select_parameter_set((hal_lms_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); + pub.lmots = lmots_select_parameter_set((hal_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_uuid(&sigptr, siglim, &pub.I)); check(hal_xdr_decode_bytestring32(&sigptr, siglim, &pub.T1)); } @@ -1608,17 +1544,18 @@ hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key, if (key == NULL || key->type != HAL_KEY_TYPE_HASHSIG_PRIVATE) return HAL_ERROR_BAD_ARGUMENTS; - /* - * Calculate data length. - */ + /* 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_uuid(&key->I, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_bytestring32(&key->T1, NULL, &len, 0)); vlen += len; + check(hal_asn1_encode_bytestring32(&key->seed, NULL, &len, 0)); vlen += len; + check(hal_asn1_encode_size_t(key->q_start, NULL, &len, 0)); vlen += len; + check(hal_asn1_encode_size_t(key->q_end, NULL, &len, 0)); vlen += len; check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen, 0)); @@ -1628,9 +1565,7 @@ hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key, if (der == NULL) return HAL_OK; - /* - * Encode data. - */ + /* Encode data. */ check(hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)); @@ -1640,8 +1575,11 @@ hal_error_t hal_hashsig_private_key_to_der(const hal_hashsig_key_t * const key, 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_uuid(&key->I, d, &len, vlen)); d += len; vlen -= len; check(hal_asn1_encode_bytestring32(&key->T1, d, &len, vlen)); d += len; vlen -= len; + check(hal_asn1_encode_bytestring32(&key->seed, d, &len, vlen)); d += len; vlen -= len; + check(hal_asn1_encode_size_t(key->q_start, d, &len, vlen)); d += len; vlen -= len; + check(hal_asn1_encode_size_t(key->q_end, 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); @@ -1688,14 +1626,17 @@ hal_error_t hal_hashsig_private_key_from_der(hal_hashsig_key_t **key_, size_t n; check(hal_asn1_decode_size_t(&key->L, d, &n, vlen)); d += n; vlen -= n; - lms_algorithm_t lms_type; + hal_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; + hal_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_uuid(&key->I, d, &n, vlen)); d += n; vlen -= n; check(hal_asn1_decode_bytestring32(&key->T1, d, &n, vlen)); d += n; vlen -= n; + check(hal_asn1_decode_bytestring32(&key->seed, d, &n, vlen)); d += n; vlen -= n; + check(hal_asn1_decode_size_t(&key->q_start, d, &n, vlen)); d += n; vlen -= n; + check(hal_asn1_decode_size_t(&key->q_end, d, &n, vlen)); d += n; vlen -= n; if (d != privkey + privkey_len) return HAL_ERROR_ASN1_PARSE_FAILED; @@ -1705,11 +1646,9 @@ hal_error_t hal_hashsig_private_key_from_der(hal_hashsig_key_t **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; - } - } + hss_key_t *hss_key = hss_find(&key->I); + if (hss_key != NULL) + *key_ = hss_key; return HAL_OK; } @@ -1721,14 +1660,14 @@ hal_error_t hal_hashsig_public_key_to_der(const hal_hashsig_key_t * const key, key->type != HAL_KEY_TYPE_HASHSIG_PUBLIC)) return HAL_ERROR_BAD_ARGUMENTS; - // L || u32str(lms_type) || u32str(lmots_type) || I || T[1] + /* 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_uuid(&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)); @@ -1741,7 +1680,7 @@ hal_error_t hal_hashsig_public_key_to_der(const hal_hashsig_key_t * const key, 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_uuid(&key->I, d, &len, dlen)); d += len; dlen -= len; check(hal_asn1_encode_bytestring32(&key->T1, d, &len, dlen)); d += len; dlen -= len; } @@ -1787,17 +1726,17 @@ hal_error_t hal_hashsig_public_key_from_der(hal_hashsig_key_t **key_, 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] + /* L || u32str(lms_type) || u32str(lmots_type) || I || T[1] */ - lms_algorithm_t lms_type; - lmots_algorithm_t lmots_type; + hal_lms_algorithm_t lms_type; + hal_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_uuid(&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) @@ -1810,13 +1749,13 @@ hal_error_t hal_hashsig_public_key_from_der(hal_hashsig_key_t **key_, 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 hal_lms_algorithm_t lms_type, + const hal_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) || + I == NULL || I_len != sizeof(hal_uuid_t) || T1 == NULL || T1_len != sizeof(bytestring32)) return HAL_ERROR_BAD_ARGUMENTS; @@ -1851,17 +1790,17 @@ hal_error_t hal_hashsig_key_load_public_xdr(hal_hashsig_key_t **key_, /* L || u32str(lms_type) || u32str(lmots_type) || I || T[1] */ uint32_t L, lms_type, lmots_type; - bytestring16 *I; + hal_uuid_t *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_uuid_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)I, sizeof(hal_uuid_t), (const uint8_t * const)T1, sizeof(bytestring32)); } @@ -1887,18 +1826,18 @@ hal_error_t hal_hashsig_public_key_der_to_xdr(const uint8_t * const der, const s 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] + /* 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; + hal_lms_algorithm_t lms_type; + hal_lmots_algorithm_t lmots_type; + hal_uuid_t 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_uuid(&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) @@ -1910,7 +1849,7 @@ hal_error_t hal_hashsig_public_key_der_to_xdr(const uint8_t * const der, const s 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_uuid(&xdrptr, xdrlim, &I)); check(hal_xdr_encode_bytestring32(&xdrptr, xdrlim, &T1)); if (xdr_len != NULL) @@ -1927,7 +1866,7 @@ hal_error_t hal_hashsig_ks_init(void) const hal_session_handle_t session = { HAL_HANDLE_NONE }; hal_uuid_t prev_name = {{0}}; unsigned len; - hal_pkey_slot_t slot = {0}; + hal_pkey_slot_t slot = {{0}}; uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; @@ -1941,36 +1880,47 @@ hal_error_t hal_hashsig_ks_init(void) 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); + memset(der, 0, sizeof(der)); + memset(&keybuf, 0, sizeof(keybuf)); + key = NULL; continue; } /* Make sure we have the lms key */ - hal_pkey_slot_t lms_slot = {0}; + hal_pkey_slot_t lms_slot = { + .name = key->I + }; 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 || + /* check that key isn't exhausted */ + lms_key.q >= lms_key.q_end || /* optimistically allocate the full hss key structure */ - hss_alloc(&key, key->L, key->lms->type, key->lmots->type) != HAL_OK) { + hss_alloc(&key) != HAL_OK) { (void)hal_ks_delete(hal_ks_token, &slot); (void)hal_ks_delete(hal_ks_token, &lms_slot); + memset(der, 0, sizeof(der)); + memset(&lms_key, 0, sizeof(lms_key)); + memset(&keybuf, 0, sizeof(keybuf)); + key = NULL; 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].I = lms_key.I; key->lms_keys[0].q = lms_key.q; + key->lms_keys[0].q_end = key->q_end; - prev_name = slot.name; + prev_name = key->name = slot.name; + memset(der, 0, sizeof(der)); + memset(&lms_key, 0, sizeof(lms_key)); + memset(&keybuf, 0, sizeof(keybuf)); + key = NULL; + hal_task_yield_maybe(); } /* Delete orphaned lms keys */ @@ -1978,17 +1928,13 @@ hal_error_t hal_hashsig_ks_init(void) 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) { + if (hss_find(&slot.name) == NULL) { (void)hal_ks_delete(hal_ks_token, &slot); continue; } prev_name = slot.name; + hal_task_yield_maybe(); } /* Find all lmots keys */ @@ -2006,35 +1952,31 @@ hal_error_t hal_hashsig_ks_init(void) 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); + memset(&lmots_key, 0, sizeof(lmots_key)); 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; - } + hss_key_t *hss_key = hss_find(&lmots_key.I); if (hss_key == NULL) { /* delete orphaned key */ (void)hal_ks_delete(hal_ks_token, &slot); + memset(&lmots_key, 0, sizeof(lmots_key)); 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)); + hss_key->lms_keys[0].lmots_keys[lmots_key.q] = 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])); + if (lms_compute_T_leaf(&hss_key->lms_keys[0], &lmots_key) != HAL_OK) { + (void)hal_ks_delete(hal_ks_token, &slot); + memset(&lmots_key, 0, sizeof(lmots_key)); + continue; + } prev_name = slot.name; + memset(&lmots_key, 0, sizeof(lmots_key)); + hal_task_yield_maybe(); } /* After all keys have been read, scan for completeness. */ @@ -2043,69 +1985,49 @@ hal_error_t hal_hashsig_ks_init(void) 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; + lms_key_t *lms_key = hss_key->lms_keys; + for (size_t q = 0; q < (1U << hss_key->lms->h); ++q) { + if (hal_uuid_cmp(&lms_key->lmots_keys[q], &uuid_0) == 0) { + bytestring32 seed_0 = {{0}}; + if (memcmp(&hss_key->seed, &seed_0, sizeof(seed_0)) == 0) { + /* lms key is incomplete, give up on it */ + fail = 1; + break; + } + else { + /* This key was generated with the pseudo-random method, + * and can be regenerated. + */ + check(lms_generate_lmots(lms_key, q, &hss_key->seed)); + hal_task_yield_maybe(); + } } } 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 */ + hss_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); + hal_task_yield_maybe(); 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) + lms_compute_T_intr(lms_key); + if (memcmp(&lms_key->T[1], &hss_key->T1, sizeof(lms_key->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) + lms_key = &hss_key->lms_keys[i]; + if (lms_generate(lms_key, NULL) != 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)); + slot.name = lms_key->I; 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 */ @@ -2113,10 +2035,99 @@ hal_error_t hal_hashsig_ks_init(void) (const uint8_t * const)lms_key->pubkey, lms_key->pubkey_len, lms_key->signature, NULL, lms_key->signature_len) != HAL_OK) goto fail; + hal_task_yield_maybe(); } } restart_in_progress = 0; return HAL_OK; } + +hal_error_t hal_hashsig_export(const hal_uuid_t * const name, uint8_t *der, size_t *der_len, const size_t der_max) +{ + hal_error_t err; + hal_hashsig_key_t keybuf, *tmp_key = &keybuf, *hss_key; + + if ((err = hal_hashsig_private_key_from_der(&hss_key, &keybuf, sizeof(keybuf), der, *der_len)) != HAL_OK) + goto err_out; + if (hss_key == tmp_key) { + err = HAL_ERROR_KEY_NOT_FOUND; /* or IMPOSSIBLE? */ + goto err_out; + } + + /* adjust hss_key->end and tmp_key->start */ + size_t new_end = (hss_key->lms_keys[0].q + hss_key->lms_keys[0].q_end) / 2; + if (new_end == hss_key->lms_keys[0].q) { + err = HAL_ERROR_HASHSIG_KEY_EXHAUSTED; + goto err_out; + } + hss_key->q_end = hss_key->lms_keys[0].q_end = tmp_key->q_start = new_end; + + /* store updated hss_key */ + hal_pkey_slot_t slot = { + .type = HAL_KEY_TYPE_HASHSIG_PRIVATE, + .name = *name, + .flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN | HAL_KEY_FLAG_EXPORTABLE + }; + if ((err = hal_hashsig_private_key_to_der(hss_key, der, der_len, der_max)) != HAL_OK || + (err = hal_ks_rewrite_der(hal_ks_token, &slot, der, *der_len)) != HAL_OK) + goto err_out; + + /* store updated lms_key */ + lms_key_t *lms_key = &hss_key->lms_keys[0]; + uint8_t lms_der[HAL_KS_WRAPPED_KEYSIZE]; + size_t lms_der_len; + if ((err = lms_private_key_to_der(lms_key, lms_der, &lms_der_len, sizeof(lms_der))) != HAL_OK) + goto err_out; + + hal_pkey_slot_t lms_slot = { + .type = HAL_KEY_TYPE_HASHSIG_LMS, + .name = lms_key->I, + .flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN + }; + if ((err = hal_ks_rewrite_der(hal_ks_token, &lms_slot, lms_der, lms_der_len)) != HAL_OK) + goto err_out; + + /* re-encode tmp_key to der */ + if ((err = hal_hashsig_private_key_to_der(tmp_key, der, der_len, der_max)) != HAL_OK) + goto err_out; + + /* delete unused lmots keys? */ + +err_out: + memset(&keybuf, 0, sizeof(keybuf)); + hss_key = NULL; + return err; +} + +hal_error_t hal_hashsig_import(const uint8_t *der, const size_t der_len, + const hal_key_flags_t flags) +{ + if (restart_in_progress) + return HAL_ERROR_NOT_READY; + + hss_key_t keybuf, *key; + hal_error_t err; + + if ((err = hal_hashsig_private_key_from_der(&key, &keybuf, sizeof(keybuf), der, der_len)) != HAL_OK) + goto err_out; + + /* If the key already exists, it could be that the user is attempting to + * return an exported key to its origin, and we could consolidate them, + * but then we have to deal with the possibility of disjoint partitions of + * the keyspace (or worse, overlapping or duplicate partitions, which is + * always an error). In any case, it's easier just to disallow it. + */ + if (hss_find(&key->I) != NULL) { + err = HAL_ERROR_KEY_NAME_IN_USE; + goto err_out; + } + + err = hss_generate(&key, flags); + +err_out: + memset(&keybuf, 0, sizeof(keybuf)); + key = NULL; + return err; +} #endif diff --git a/hashsig.h b/hashsig.h deleted file mode 100644 index 3753496..0000000 --- a/hashsig.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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_ */ @@ -3,7 +3,7 @@ * ----- * Master Key Memory functions. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2019, 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 @@ -49,22 +49,12 @@ * Master Key. */ -#define HAL_OK CMIS_HAL_OK -#include "stm-init.h" -#include "stm-keystore.h" -#undef HAL_OK - -#define HAL_OK LIBHAL_OK #include "hal.h" #include "hal_internal.h" -#undef HAL_OK #include <string.h> -static int volatile_init = 0; -static hal_core_t *core = NULL; - #define MKM_VOLATILE_STATUS_ADDRESS 0 #define MKM_VOLATILE_SCLK_DIV 0x20 #define MKM_FLASH_STATUS_ADDRESS (KEYSTORE_SECTOR_SIZE * (KEYSTORE_NUM_SECTORS - 1)) @@ -81,33 +71,39 @@ static hal_core_t *core = NULL; static hal_error_t hal_mkm_volatile_init(void) { + static int volatile_init = 0; + if (volatile_init) - return LIBHAL_OK; + return HAL_OK; hal_error_t err; uint32_t status; + hal_core_t *core = NULL; - if ((core = hal_core_find(MKMIF_NAME, NULL)) == NULL) - return HAL_ERROR_CORE_NOT_FOUND; - - if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != LIBHAL_OK || - (err = hal_mkmif_init(core)) != LIBHAL_OK || - (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) + if ((err = hal_core_alloc(MKMIF_NAME, &core, NULL)) != HAL_OK) return err; + if ((err = hal_mkmif_set_clockspeed(core, MKM_VOLATILE_SCLK_DIV)) != HAL_OK || + (err = hal_mkmif_init(core)) != HAL_OK || + (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != HAL_OK) + goto out; + if (status != MKM_STATUS_SET && status != MKM_STATUS_NOT_SET) { /* * XXX Something is a bit fishy here. If we just write the status word, it reads back wrong sometimes, * while if we write the full buf too it is consistently right afterwards. */ uint8_t buf[KEK_LENGTH] = {0}; - if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) - return err; + if ((err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != HAL_OK || + (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != HAL_OK) + goto out; } volatile_init = 1; - return LIBHAL_OK; + +out: + hal_core_free(core); + return err; } hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len) @@ -118,8 +114,8 @@ hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len) if (len && len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_read_word(core, MKM_VOLATILE_STATUS_ADDRESS, &status)) != LIBHAL_OK) + if ((err = hal_mkm_volatile_init()) != HAL_OK || + (err = hal_mkmif_read_word(NULL, MKM_VOLATILE_STATUS_ADDRESS, &status)) != HAL_OK) return err; if (buf != NULL && len) { @@ -129,12 +125,12 @@ hal_error_t hal_mkm_volatile_read(uint8_t *buf, const size_t len) */ if (status != MKM_STATUS_SET) memset(buf, 0x0, len); - else if ((err = hal_mkmif_read(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK) + else if ((err = hal_mkmif_read(NULL, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != HAL_OK) return err; } if (status == MKM_STATUS_SET) - return LIBHAL_OK; + return HAL_OK; if (status == MKM_STATUS_NOT_SET) return HAL_ERROR_MASTERKEY_NOT_SET; @@ -152,12 +148,12 @@ hal_error_t hal_mkm_volatile_write(const uint8_t * const buf, const size_t len) if (buf == NULL) return HAL_ERROR_MASTERKEY_FAIL; - if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != LIBHAL_OK) + if ((err = hal_mkm_volatile_init()) != HAL_OK || + (err = hal_mkmif_write(NULL, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, len)) != HAL_OK || + (err = hal_mkmif_write_word(NULL, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_SET)) != HAL_OK) return err; - return LIBHAL_OK; + return HAL_OK; } hal_error_t hal_mkm_volatile_erase(const size_t len) @@ -168,12 +164,12 @@ hal_error_t hal_mkm_volatile_erase(const size_t len) if (len != KEK_LENGTH) return HAL_ERROR_MASTERKEY_BAD_LENGTH; - if ((err = hal_mkm_volatile_init()) != LIBHAL_OK || - (err = hal_mkmif_write(core, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != LIBHAL_OK || - (err = hal_mkmif_write_word(core, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != LIBHAL_OK) + if ((err = hal_mkm_volatile_init()) != HAL_OK || + (err = hal_mkmif_write(NULL, MKM_VOLATILE_STATUS_ADDRESS + 4, buf, sizeof(buf))) != HAL_OK || + (err = hal_mkmif_write_word(NULL, MKM_VOLATILE_STATUS_ADDRESS, MKM_STATUS_NOT_SET)) != HAL_OK) return err; - return LIBHAL_OK; + return HAL_OK; } /* @@ -194,9 +190,9 @@ hal_error_t hal_mkm_get_kek(uint8_t *kek, hal_error_t err = hal_mkm_volatile_read(kek, len); - if (err == LIBHAL_OK) { + if (err == HAL_OK) { *kek_len = len; - return LIBHAL_OK; + return HAL_OK; } #if HAL_MKM_FLASH_BACKUP_KLUDGE @@ -209,9 +205,9 @@ hal_error_t hal_mkm_get_kek(uint8_t *kek, * hal_mkm_volatile_read() returns HAL_ERROR_CORE_BUSY. Whee! */ - if (hal_mkm_flash_read_no_lock(kek, len) == LIBHAL_OK) { + if (hal_mkm_flash_read_no_lock(kek, len) == HAL_OK) { *kek_len = len; - return LIBHAL_OK; + return HAL_OK; } #endif @@ -35,7 +35,6 @@ #include "hal.h" #include "hal_internal.h" -#include "hashsig.h" const hal_hash_handle_t hal_hash_handle_none = {HAL_HANDLE_NONE}; @@ -121,6 +120,8 @@ static inline int check_pkey_type_curve_flags(const hal_key_type_t type, hal_error_t hal_rpc_get_version(uint32_t *version) { + if (version == NULL) + return HAL_ERROR_BAD_ARGUMENTS; return hal_rpc_misc_dispatch->get_version(version); } @@ -185,6 +186,8 @@ hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, siz hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg, uint8_t *id, size_t *len, const size_t len_max) { + if (id == NULL && len_max != 0) + return HAL_ERROR_BAD_ARGUMENTS; return hal_rpc_hash_dispatch->get_digest_algorithm_id(alg, id, len, len_max); } @@ -201,7 +204,7 @@ hal_error_t hal_rpc_hash_initialize(const hal_client_handle_t client, const hal_digest_algorithm_t alg, const uint8_t * const key, const size_t key_len) { - if (hash == NULL) + if (hash == NULL || (key == NULL && key_len != 0)) return HAL_ERROR_BAD_ARGUMENTS; return hal_rpc_hash_dispatch->initialize(client, session, hash, alg, key, key_len); } @@ -278,8 +281,8 @@ hal_error_t hal_rpc_pkey_generate_hashsig(const hal_client_handle_t client, 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_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, const hal_key_flags_t flags) { if (pkey == NULL || name == NULL || !check_pkey_flags(flags)) @@ -329,7 +332,7 @@ size_t hal_rpc_pkey_get_public_key_len(const hal_pkey_handle_t pkey) hal_error_t hal_rpc_pkey_get_public_key(const hal_pkey_handle_t pkey, uint8_t *der, size_t *der_len, const size_t der_max) { - if (der == NULL || der_len == NULL || der_max == 0) + if (der == NULL && der_max != 0) return HAL_ERROR_BAD_ARGUMENTS; return hal_rpc_pkey_dispatch->get_public_key(pkey, der, der_len, der_max); } diff --git a/rpc_client.c b/rpc_client.c index e97289e..c9ac9b7 100644 --- a/rpc_client.c +++ b/rpc_client.c @@ -36,7 +36,6 @@ #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 @@ -138,7 +137,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); - size_t rcvlen = length; + size_t rcvlen; hal_client_handle_t dummy_client = {0}; hal_error_t rpc_ret; @@ -151,7 +150,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_variable_opaque(&iptr, ilimit, buffer, &rcvlen)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, buffer, &rcvlen, length)); // XXX check rcvlen vs length } return rpc_ret; @@ -311,8 +310,12 @@ 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) { - *len = len_max; - check(hal_xdr_decode_variable_opaque(&iptr, ilimit, id, len)); + uint32_t len32; + check(hal_xdr_decode_int(&iptr, ilimit, &len32)); + if (len != NULL) + *len = len32; + if (id != NULL) + check(hal_xdr_decode_fixed_opaque(&iptr, ilimit, id, len32)); } return rpc_ret; } @@ -395,7 +398,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); - size_t digest_len = length; + size_t digest_len; hal_client_handle_t dummy_client = {0}; hal_error_t rpc_ret; @@ -409,7 +412,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_variable_opaque(&iptr, ilimit, digest, &digest_len)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, digest, &digest_len, length)); /* XXX check digest_len vs length */ } return rpc_ret; @@ -425,7 +428,7 @@ 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); - size_t name_len = sizeof(name->uuid); + size_t name_len; hal_error_t rpc_ret; check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD)); @@ -440,7 +443,7 @@ static hal_error_t pkey_remote_load(const hal_client_handle_t client, 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)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len, sizeof(name->uuid))); if (name_len != sizeof(name->uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } @@ -484,7 +487,7 @@ 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); - size_t name_len = sizeof(name->uuid); + size_t name_len; hal_error_t rpc_ret; check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA)); @@ -501,7 +504,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_variable_opaque(&iptr, ilimit, name->uuid, &name_len)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len, sizeof(name->uuid))); if (name_len != sizeof(name->uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } @@ -519,7 +522,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); - size_t name_len = sizeof(name->uuid); + size_t name_len; hal_error_t rpc_ret; check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC)); @@ -535,7 +538,7 @@ 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_variable_opaque(&iptr, ilimit, name->uuid, &name_len)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len, sizeof(name->uuid))); if (name_len != sizeof(name->uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } @@ -548,14 +551,14 @@ static hal_error_t pkey_remote_generate_hashsig(const hal_client_handle_t client 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_lms_algorithm_t lms_type, + const hal_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); + size_t name_len; hal_error_t rpc_ret; check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_HASHSIG)); @@ -573,7 +576,7 @@ static hal_error_t pkey_remote_generate_hashsig(const hal_client_handle_t client 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)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len, sizeof(name->uuid))); if (name_len != sizeof(name->uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } @@ -737,8 +740,12 @@ 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) { - *der_len = der_max; - check(hal_xdr_decode_variable_opaque(&iptr, ilimit, der, der_len)); + uint32_t len32; + check(hal_xdr_decode_int(&iptr, ilimit, &len32)); + if (der_len != NULL) + *der_len = len32; + if (der != NULL) + check(hal_xdr_decode_fixed_opaque(&iptr, ilimit, der, len32)); } return rpc_ret; } @@ -765,10 +772,8 @@ static hal_error_t pkey_remote_sign(const hal_pkey_handle_t pkey, check(read_matching_packet(RPC_FUNC_PKEY_SIGN, inbuf, sizeof(inbuf), &iptr, &ilimit)); check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); - if (rpc_ret == HAL_OK) { - *signature_len = signature_max; - check(hal_xdr_decode_variable_opaque(&iptr, ilimit, signature, signature_len)); - } + if (rpc_ret == HAL_OK) + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, signature, signature_len, signature_max)); return rpc_ret; } @@ -851,8 +856,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) { - size_t uuid_len = sizeof(result[i].uuid); - check(hal_xdr_decode_variable_opaque(&iptr, ilimit, result[i].uuid, &uuid_len)); + size_t uuid_len; + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, result[i].uuid, &uuid_len, sizeof(result[i].uuid))); if (uuid_len != sizeof(result[i].uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } @@ -902,7 +907,7 @@ static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey, { /* inbuf[] here includes one extra word per attribute for padding */ uint8_t outbuf[nargs(5 + attributes_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); - uint8_t inbuf[nargs(3 + 3 * attributes_len) + attributes_buffer_len]; + uint8_t inbuf[nargs(4 + 3 * attributes_len) + attributes_buffer_len]; const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); hal_client_handle_t dummy_client = {0}; hal_error_t rpc_ret; @@ -935,11 +940,11 @@ static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey, attributes[i].length = u32; } else { - size_t len = attributes_buffer + attributes_buffer_len - abuf; - check(hal_xdr_decode_variable_opaque(&iptr, ilimit, abuf, &len)); + size_t len; + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, abuf, &len, attributes_buffer + attributes_buffer_len - abuf)); attributes[i].value = abuf; attributes[i].length = len; - abuf += u32; + abuf += len; } } } @@ -969,10 +974,8 @@ 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) { - *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)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, pkcs8, pkcs8_len, pkcs8_max)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, kek, kek_len, kek_max)); } return rpc_ret; } @@ -989,7 +992,7 @@ 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); - size_t name_len = sizeof(name->uuid); + size_t name_len; hal_error_t rpc_ret; check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_IMPORT)); @@ -1007,7 +1010,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_variable_opaque(&iptr, ilimit, name->uuid, &name_len)); + check(hal_xdr_decode_variable_opaque(&iptr, ilimit, name->uuid, &name_len, sizeof(name->uuid))); if (name_len != sizeof(name->uuid)) return HAL_ERROR_KEY_NAME_TOO_LONG; } diff --git a/rpc_client_daemon.c b/rpc_client_daemon.c index 1c506eb..d47ac7d 100644 --- a/rpc_client_daemon.c +++ b/rpc_client_daemon.c @@ -37,6 +37,7 @@ #include <netinet/in.h> #include <unistd.h> #include <sys/un.h> +#include <sys/socket.h> #include "hal.h" #include "hal_internal.h" @@ -44,7 +44,7 @@ static hal_error_t get_version(uint32_t *version) static hal_error_t get_random(void *buffer, const size_t length) { - if (buffer == NULL || length == 0) + if (buffer == NULL) return HAL_ERROR_IMPOSSIBLE; return hal_get_random(NULL, buffer, length); @@ -38,7 +38,6 @@ #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 @@ -530,12 +529,13 @@ static hal_error_t pkey_local_generate_hashsig(const hal_client_handle_t client, 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_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, const hal_key_flags_t flags) { hal_assert(pkey != NULL && name != NULL); + uint8_t keybuf[hal_hashsig_key_t_size]; hal_hashsig_key_t *key = NULL; hal_pkey_slot_t *slot; hal_error_t err; @@ -555,7 +555,7 @@ static hal_error_t pkey_local_generate_hashsig(const hal_client_handle_t client, slot->curve = HAL_CURVE_NONE; slot->flags = flags; - if ((err = hal_hashsig_key_gen(NULL, &key, hss_levels, lms_type, lmots_type)) != HAL_OK) { + if ((err = hal_hashsig_key_gen(NULL, &key, keybuf, sizeof(keybuf), hss_levels, lms_type, lmots_type, flags)) != HAL_OK) { slot->type = HAL_KEY_TYPE_NONE; return err; } @@ -566,11 +566,8 @@ static hal_error_t pkey_local_generate_hashsig(const hal_client_handle_t client, 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. - */ + key = NULL; + memset(keybuf, 0, sizeof(keybuf)); memset(der, 0, sizeof(der)); if (err != HAL_OK) { @@ -602,8 +599,6 @@ 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) { hal_pkey_slot_t *slot = find_handle(pkey); @@ -616,20 +611,9 @@ 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; - } + if (slot->type == HAL_KEY_TYPE_HASHSIG_PRIVATE && + (err = hal_hashsig_delete(&slot->name)) != HAL_OK) + return err; err = hal_ks_delete(ks_from_flags(slot->flags), slot); @@ -700,127 +684,98 @@ static hal_error_t pkey_local_get_key_flags(const hal_pkey_handle_t pkey, } /* - * Get length of public key associated with handle. + * Get public key associated with handle. */ -static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey) +static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey, + uint8_t *der, size_t *der_len, const size_t der_max) { hal_pkey_slot_t *slot = find_handle(pkey); if (slot == NULL) - return 0; - - size_t result = 0; + return HAL_ERROR_KEY_NOT_FOUND; -#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; + uint8_t buf[HAL_KS_WRAPPED_KEYSIZE]; + size_t buf_len; hal_error_t err; - if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) == HAL_OK) { + if ((err = ks_fetch_from_flags(slot, buf, &buf_len, sizeof(buf))) == HAL_OK) { switch (slot->type) { case HAL_KEY_TYPE_RSA_PUBLIC: case HAL_KEY_TYPE_EC_PUBLIC: case HAL_KEY_TYPE_HASHSIG_PUBLIC: - result = der_len; + if (der_len != NULL) + *der_len = buf_len; + if (der != NULL) { + if (der_max < buf_len) + err = HAL_ERROR_RESULT_TOO_LONG; + else + memcpy(der, buf, buf_len); + } break; case HAL_KEY_TYPE_RSA_PRIVATE: - if (hal_rsa_private_key_from_der(&rsa_key, keybuf, sizeof(keybuf), der, der_len) == HAL_OK) - result = hal_rsa_public_key_to_der_len(rsa_key); - break; + { + uint8_t keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *key; + if ((err = hal_rsa_private_key_from_der(&key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK) + err = hal_rsa_public_key_to_der(key, der, der_len, der_max); + memset(keybuf, 0, sizeof(keybuf)); + } + break; case HAL_KEY_TYPE_EC_PRIVATE: - if (hal_ecdsa_private_key_from_der(&ecdsa_key, keybuf, sizeof(keybuf), der, der_len) == HAL_OK) - result = hal_ecdsa_public_key_to_der_len(ecdsa_key); - break; + { + uint8_t keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *key; + if ((err = hal_ecdsa_private_key_from_der(&key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK) + err = hal_ecdsa_public_key_to_der(key, der, der_len, der_max); + memset(keybuf, 0, sizeof(keybuf)); + } + 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; + { + uint8_t keybuf[hal_hashsig_key_t_size]; + hal_hashsig_key_t *key; + if ((err = hal_hashsig_private_key_from_der(&key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK) { + err = hal_hashsig_public_key_to_der(key, der, der_len, der_max); + key = NULL; + } + memset(keybuf, 0, sizeof(keybuf)); + } + break; default: + err = HAL_ERROR_UNSUPPORTED_KEY; break; } } - memset(keybuf, 0, sizeof(keybuf)); - memset(der, 0, sizeof(der)); + memset(buf, 0, sizeof(buf)); - return result; + return err; } /* - * Get public key associated with handle. + * Get length of public key associated with handle. */ -static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey, - uint8_t *der, size_t *der_len, const size_t der_max) +static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey) { hal_pkey_slot_t *slot = find_handle(pkey); if (slot == NULL) - return HAL_ERROR_KEY_NOT_FOUND; + return 0; - 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; + size_t der_len; hal_error_t err; - if ((err = ks_fetch_from_flags(slot, buf, &buf_len, sizeof(buf))) == HAL_OK) { - switch (slot->type) { - - 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) - err = HAL_ERROR_RESULT_TOO_LONG; - else if (der != NULL) - memcpy(der, buf, buf_len); - break; - - case HAL_KEY_TYPE_RSA_PRIVATE: - if ((err = hal_rsa_private_key_from_der(&rsa_key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK) - err = hal_rsa_public_key_to_der(rsa_key, der, der_len, der_max); - break; - - case HAL_KEY_TYPE_EC_PRIVATE: - if ((err = hal_ecdsa_private_key_from_der(&ecdsa_key, keybuf, sizeof(keybuf), buf, buf_len)) == HAL_OK) - 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; - } - } - - memset(keybuf, 0, sizeof(keybuf)); - memset(buf, 0, sizeof(buf)); - - return err; + if ((err = pkey_local_get_public_key(pkey, NULL, &der_len, 0)) == HAL_OK) + return der_len; + else + return 0; } /* @@ -929,24 +884,28 @@ static hal_error_t pkey_local_sign_hashsig(hal_pkey_slot_t *slot, if (input == NULL || input_len == 0) { hal_digest_algorithm_t alg; + size_t digest_len; 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_get_digest_length(alg, &digest_len)) != HAL_OK) return err; - if (input_len > signature_max) + if (digest_len > signature_max) return HAL_ERROR_RESULT_TOO_LONG; - if ((err = hal_rpc_hash_finalize(hash, signature, input_len)) != HAL_OK) + uint8_t digest[digest_len]; + + if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK) return err; - input = signature; + err = hal_hashsig_sign(NULL, key, digest, digest_len, signature, signature_len, signature_max); } - if ((err = hal_hashsig_sign(NULL, key, input, input_len, signature, signature_len, signature_max)) != HAL_OK) - return err; + else + err = hal_hashsig_sign(NULL, key, input, input_len, signature, signature_len, signature_max); - return HAL_OK; + key = NULL; + return err; } static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey, @@ -1113,13 +1072,23 @@ static hal_error_t pkey_local_verify_hashsig(uint8_t *keybuf, const size_t keybu 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) + switch (type) { + case HAL_KEY_TYPE_HASHSIG_PRIVATE: + err = hal_hashsig_private_key_from_der(&key, keybuf, keybuf_len, der, der_len); + break; + case HAL_KEY_TYPE_HASHSIG_PUBLIC: + err = hal_hashsig_public_key_from_der(&key, keybuf, keybuf_len, der, der_len); + break; + default: + err = HAL_ERROR_IMPOSSIBLE; + } + + if (err != 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) @@ -1162,6 +1131,7 @@ static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey, verifier = pkey_local_verify_ecdsa; keybuf_size = hal_ecdsa_key_t_size; break; + case HAL_KEY_TYPE_HASHSIG_PRIVATE: case HAL_KEY_TYPE_HASHSIG_PUBLIC: verifier = pkey_local_verify_hashsig; keybuf_size = hal_hashsig_key_t_size; @@ -1374,6 +1344,11 @@ static hal_error_t pkey_local_export(const hal_pkey_handle_t pkey_handle, if ((err = ks_fetch_from_flags(pkey, pkcs8, &len, pkcs8_max)) != HAL_OK) goto fail; + /* hashsig export partitions the keyspace, so needs to update the stored key */ + if (pkey->type == HAL_KEY_TYPE_HASHSIG_PRIVATE && + (err = hal_hashsig_export(&pkey->name, pkcs8, &len, pkcs8_max)) != HAL_OK) + goto fail; + if ((err = hal_get_random(NULL, kek, KEK_LENGTH)) != HAL_OK) goto fail; @@ -1483,6 +1458,13 @@ static hal_error_t pkey_local_import(const hal_client_handle_t client, if ((err = hal_aes_keyunwrap(NULL, kek, sizeof(kek), data, data_len, der, &der_len)) != HAL_OK) goto fail; + hal_key_type_t type; + hal_curve_name_t curve; + if ((err = hal_asn1_guess_key_type(&type, &curve, der, der_len)) == HAL_OK && + type == HAL_KEY_TYPE_HASHSIG_PRIVATE && + (err = hal_hashsig_import(der, der_len, flags)) != HAL_OK) + goto fail; + err = hal_rpc_pkey_load(client, session, pkey, name, der, der_len, flags); fail: diff --git a/rpc_server.c b/rpc_server.c index 5a06e37..9598413 100644 --- a/rpc_server.c +++ b/rpc_server.c @@ -35,7 +35,6 @@ #include "hal.h" #include "hal_internal.h" #include "xdr_internal.h" -#include "hashsig.h" /* * RPC calls. @@ -68,7 +67,7 @@ static hal_error_t get_random(const uint8_t **iptr, const uint8_t * const ilimit check(hal_xdr_decode_int(iptr, ilimit, &length)); /* sanity check length */ - if (length == 0 || length > (uint32_t)(olimit - *optr - nargs(1))) + if (nargs(1) + pad(length) > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; /* get the data directly into the output buffer */ @@ -168,13 +167,19 @@ static hal_error_t hash_get_digest_algorithm_id(const uint8_t **iptr, const uint 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 - nargs(1))) + if (nargs(1) + pad(len_max) > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; - /* get the data directly into the output buffer */ - 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); + if (len_max == 0) { + if ((err = hal_rpc_hash_get_digest_algorithm_id(alg, NULL, &len, 0)) == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, len)); + } + else { + /* get the data directly into the output buffer */ + 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); + } } return err; @@ -210,6 +215,8 @@ static hal_error_t hash_initialize(const uint8_t **iptr, const uint8_t * const i check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); check(hal_xdr_decode_int(iptr, ilimit, &alg)); check(hal_xdr_decode_variable_opaque_ptr(iptr, ilimit, &key, &key_len)); + if (key_len == 0) + key = NULL; check(hal_rpc_hash_initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len)); @@ -245,7 +252,7 @@ static hal_error_t hash_finalize(const uint8_t **iptr, const uint8_t * const ili check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); check(hal_xdr_decode_int(iptr, ilimit, &length)); /* sanity check length */ - if (length > (uint32_t)(olimit - *optr - nargs(1))) + if (nargs(1) + pad(length) > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; /* get the data directly into the output buffer */ @@ -493,7 +500,7 @@ static hal_error_t pkey_get_public_key(const uint8_t **iptr, const uint8_t * con 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 - nargs(1))) + if (nargs(1) + pad(len_max) > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; /* get the data directly into the output buffer */ @@ -523,7 +530,7 @@ static hal_error_t pkey_sign(const uint8_t **iptr, const uint8_t * const ilimit, 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 - nargs(1))) + if (nargs(1) + pad(sig_max) > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; /* get the data directly into the output buffer */ @@ -576,6 +583,9 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit check(hal_xdr_decode_int(iptr, ilimit, &flags)); check(hal_xdr_decode_int(iptr, ilimit, &attributes_len)); + if (nargs(2 * attributes_len) > (uint32_t)(ilimit - *iptr)) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1]; for (size_t i = 0; i < attributes_len; i++) { @@ -597,6 +607,9 @@ static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit const hal_uuid_t * const previous_uuid = (const void *) previous_uuid_ptr; + if (nargs(2) + result_max * (nargs(1) + sizeof(hal_uuid_t)) > (uint32_t)(olimit - *optr)) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + hal_uuid_t result[result_max]; unsigned result_len, ustate = state; @@ -628,6 +641,9 @@ static hal_error_t pkey_set_attributes(const uint8_t **iptr, const uint8_t * con check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); check(hal_xdr_decode_int(iptr, ilimit, &attributes_len)); + if (nargs(2 * attributes_len) > (uint32_t)(ilimit - *iptr)) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1]; for (size_t i = 0; i < attributes_len; i++) { @@ -656,7 +672,7 @@ static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * con { hal_client_handle_t client; hal_pkey_handle_t pkey; - uint32_t attributes_len, u32; + uint32_t attributes_len, attributes_buffer_len; uint8_t *optr_orig = *optr; hal_error_t err; @@ -664,14 +680,15 @@ static hal_error_t pkey_get_attributes(const uint8_t **iptr, const uint8_t * con check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); check(hal_xdr_decode_int(iptr, ilimit, &attributes_len)); + if (nargs(1 + attributes_len) > (uint32_t)(ilimit - *iptr)) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + hal_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1]; for (size_t i = 0; i < attributes_len; i++) check(hal_xdr_decode_int(iptr, ilimit, &attributes[i].type)); - check(hal_xdr_decode_int(iptr, ilimit, &u32)); - - const size_t attributes_buffer_len = u32; + check(hal_xdr_decode_int(iptr, ilimit, &attributes_buffer_len)); if (nargs(1 + 2 * attributes_len) + attributes_buffer_len > (uint32_t)(olimit - *optr)) return HAL_ERROR_RPC_PACKET_OVERFLOW; @@ -715,6 +732,9 @@ static hal_error_t pkey_export(const uint8_t **iptr, const uint8_t * const ilimi check(hal_xdr_decode_int(iptr, ilimit, &pkcs8_max)); check(hal_xdr_decode_int(iptr, ilimit, &kek_max)); + if (nargs(2) + pad(pkcs8_max) + pad(kek_max) > (uint32_t)(olimit - *optr)) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + uint8_t pkcs8[pkcs8_max], kek[kek_max]; check(hal_rpc_pkey_export(pkey, kekek, pkcs8, &pkcs8_len, sizeof(pkcs8), kek, &kek_len, sizeof(kek))); diff --git a/tests/Makefile b/tests/Makefile index d186000..515c662 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2015, NORDUnet A/S +# Copyright (c) 2015-2018, NORDUnet A/S # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,15 +27,9 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -ifndef CRYPTECH_ROOT - CRYPTECH_ROOT := $(abspath ../../..) -endif - -LIBTFM_SRC ?= ${CRYPTECH_ROOT}/sw/thirdparty/libtfm -LIBTFM_BLD ?= ${LIBTFM_SRC} - -LIBHAL_SRC ?= ${CRYPTECH_ROOT}/sw/libhal +LIBHAL_SRC ?= .. LIBHAL_BLD ?= ${LIBHAL_SRC} +LIBTFM_BLD ?= ../../thirdparty/libtfm LIBS = ${LIBHAL_BLD}/libhal.a ${LIBTFM_BLD}/libtfm.a @@ -63,8 +57,6 @@ else endif -$(info Building libhal with configuration IO_BUS=${IO_BUS} RPC_MODE=${RPC_MODE} KS=${KS} RPC_TRANSPORT=${RPC_TRANSPORT} MODEXP_CORE=${MODEXP_CORE}) - all: ${BIN} test: all @@ -76,7 +68,7 @@ clean distclean: ${BIN}: %: %.o ${LIBS} ${CC} ${CFLAGS} -o $@ $^ ${LDFLAGS} -%.o: %.c ${LBHAL_SRC}/*.h ${LIBTFM_BLD}/tfm.h +%.o: %.c ${LIBHAL_SRC}/*.h ${LIBTFM_BLD}/tfm.h ${CC} ${CFLAGS} -c -o $@ $< test-rpc_hashsig.o: test-hashsig.h diff --git a/tests/parallel-signatures.py b/tests/parallel-signatures.py index 8d98460..980f759 100755 --- a/tests/parallel-signatures.py +++ b/tests/parallel-signatures.py @@ -64,6 +64,12 @@ from Crypto.Hash.SHA256 import SHA256Hash as SHA256 from Crypto.Hash.SHA384 import SHA384Hash as SHA384 from Crypto.Hash.SHA512 import SHA512Hash as SHA512 +try: + import statistics + statistics_loaded = True +except ImportError: + statistics_loaded = False + logger = logging.getLogger(__name__) @@ -254,6 +260,8 @@ class Result(object): self.args = args self.name = name self.sum = datetime.timedelta(seconds = 0) + if statistics_loaded: + self.readings = [None] * args.iterations self.t0 = None self.t1 = None self.n = 0 @@ -264,14 +272,32 @@ class Result(object): self.t1 = t1 delta = t1 - t0 self.sum += delta + if statistics_loaded: + self.readings[self.n] = delta.total_seconds() self.n += 1 if not self.args.quiet: sys.stdout.write("\r{:4d} {}".format(self.n, delta)) sys.stdout.flush() - @property - def mean(self): - return self.sum / self.n + if statistics_loaded: + + @property + def mean(self): + return statistics.mean(self.readings) + + @property + def median(self): + return statistics.median(self.readings) + + @property + def stdev(self): + return statistics.pstdev(self.readings) + + else: + + @property + def mean(self): + return self.sum / self.n @property def secs_per_sig(self): @@ -286,15 +312,28 @@ class Result(object): return self.sum.total_seconds() / (self.t1 - self.t0).total_seconds() def report(self): - sys.stdout.write(("\r{0.name} " - "sigs/sec {0.sigs_per_sec} " - "secs/sig {0.secs_per_sig} " - "mean {0.mean} " - "speedup {0.speedup} " - "(n {0.n}, " - "c {0.args.clients} " - "t0 {0.t0} " - "t1 {0.t1})\n").format(self)) + if statistics_loaded: + sys.stdout.write(("\r{0.name} " + "sigs/sec {0.sigs_per_sec} " + "secs/sig {0.secs_per_sig} " + "mean {0.mean} " + "median {0.median} " + "stdev {0.stdev} " + "speedup {0.speedup} " + "(n {0.n}, " + "c {0.args.clients} " + "t0 {0.t0} " + "t1 {0.t1})\n").format(self)) + else: + sys.stdout.write(("\r{0.name} " + "sigs/sec {0.sigs_per_sec} " + "secs/sig {0.secs_per_sig} " + "mean {0.mean} " + "speedup {0.speedup} " + "(n {0.n}, " + "c {0.args.clients} " + "t0 {0.t0} " + "t1 {0.t1})\n").format(self)) sys.stdout.flush() diff --git a/tests/test-rpc_hashsig.c b/tests/test-rpc_hashsig.c index 00728c3..1c5765b 100644 --- a/tests/test-rpc_hashsig.c +++ b/tests/test-rpc_hashsig.c @@ -48,26 +48,22 @@ #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; +#ifndef timersub +#define timersub(a, b, res) \ + do { \ + (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; \ + } \ + } while (0) +#endif + static int info = 0; #define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) @@ -86,10 +82,10 @@ static int test_hashsig_testvec_local(const hashsig_tc_t * const tc, hal_key_fla 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)); + lose("Error loading 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)); + lose("Error verifying: %s\n", hal_error_string(err)); printf("OK\n"); return 1; @@ -119,27 +115,27 @@ static int test_hashsig_testvec_remote(const hashsig_tc_t * const tc, hal_key_fl 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)); + lose("Error loading 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)); + lose("Error DER encoding 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)); + lose("Error loading public key: %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)); + lose("Error verifying: %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)); + goto fail_out; printf("OK\n"); return 1; @@ -148,7 +144,8 @@ static int test_hashsig_testvec_remote(const hashsig_tc_t * const tc, hal_key_fl 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)); + fail_out: + printf("Error deleting public key: %s\n", hal_error_string(err)); return 0; } @@ -169,36 +166,36 @@ static void hexdump(const char * const label, const uint8_t * const buf, const s printf("\n"); } -static inline size_t lms_type_to_h(const lms_algorithm_t lms_type) +static inline size_t lms_type_to_h(const hal_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; + case HAL_LMS_SHA256_N32_H5: return 5; + case HAL_LMS_SHA256_N32_H10: return 10; + case HAL_LMS_SHA256_N32_H15: return 15; + case HAL_LMS_SHA256_N32_H20: return 20; + case HAL_LMS_SHA256_N32_H25: return 25; default: return 0; } } -static inline size_t lmots_type_to_w(const lmots_algorithm_t lmots_type) +static inline size_t lmots_type_to_w(const hal_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; + case HAL_LMOTS_SHA256_N32_W1: return 1; + case HAL_LMOTS_SHA256_N32_W2: return 2; + case HAL_LMOTS_SHA256_N32_W4: return 4; + case HAL_LMOTS_SHA256_N32_W8: return 8; default: return 0; } } -static inline size_t lmots_type_to_p(const lmots_algorithm_t lmots_type) +static inline size_t lmots_type_to_p(const hal_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; + case HAL_LMOTS_SHA256_N32_W1: return 265; + case HAL_LMOTS_SHA256_N32_W2: return 133; + case HAL_LMOTS_SHA256_N32_W4: return 67; + case HAL_LMOTS_SHA256_N32_W8: return 34; default: return 0; } } @@ -224,7 +221,7 @@ static hal_error_t dump_hss_signature(const uint8_t * const sig, const size_t le 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); + size_t p = lmots_type_to_p((const hal_lmots_algorithm_t)lmots_type); for (size_t j = 0; j < p; ++j) { char label[16]; sprintf(label, "y[%lu]", j); @@ -235,7 +232,7 @@ static hal_error_t dump_hss_signature(const uint8_t * const sig, const size_t le 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); + size_t h = lms_type_to_h((const hal_lms_algorithm_t)lms_type); for (size_t j = 0; j < h; ++j) { char label[16]; sprintf(label, "path[%lu]", j); @@ -260,166 +257,176 @@ static hal_error_t dump_hss_signature(const uint8_t * const sig, const size_t le 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) +static int test_hashsig_generate(const size_t L, + const hal_lms_algorithm_t lms_type, + const hal_lmots_algorithm_t lmots_type, + hal_key_flags_t flags, + const int keep, + hal_pkey_handle_t *handle) { 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_uuid_t private_name; + struct timeval tv_start, tv_end, tv_diff; + + 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)); + gettimeofday(&tv_start, NULL); + } - 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); - } + if ((err = hal_rpc_pkey_generate_hashsig(client, session, &private_key, &private_name, + L, lms_type, lmots_type, flags)) != HAL_OK) + lose("Error generating 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 << lms_type_to_h(lms_type))); + printf("Info: %ldm%ld.%03lds to generate key (%ld.%03lds per lmots key)\n", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000, + (long)per_key / 1000000, ((long)per_key % 1000000) / 1000); + } - uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)]; + if (keep) { + char name_str[HAL_UUID_TEXT_SIZE]; + if ((err = hal_uuid_format(&private_name, name_str, sizeof(name_str))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + printf("Private key name: %s\n", name_str); + } - 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)); + *handle = private_key; + printf("OK\n"); + return 1; - assert(len == sizeof(public_der)); +fail: + if (private_key.handle != HAL_HANDLE_NONE && + (err = hal_rpc_pkey_delete(private_key)) != HAL_OK) + printf("Error deleting private key: %s\n", hal_error_string(err)); - 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)); + handle->handle = HAL_HANDLE_NONE; + return 0; +} - 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)); +static int test_hashsig_sign(const hal_pkey_handle_t private_key, + const uint8_t * const msg, const size_t msg_len, + const size_t iterations, + const char * const save_name, + uint8_t *sig, size_t *sig_len, const size_t sig_max) +{ + hal_error_t err; + struct timeval tv_start, tv_end, tv_diff; + int i; + + if (info) + gettimeofday(&tv_start, NULL); + + for (i = 0; i < iterations; ++i) { + if ((err = hal_rpc_pkey_sign(private_key, hal_hash_handle_none, + msg, msg_len, + sig, sig_len, sig_max)) != HAL_OK) { + if (i > 0 && err == HAL_ERROR_HASHSIG_KEY_EXHAUSTED) + break; + else + lose("Error signing (%d): %s\n", i, hal_error_string(err)); } + } - 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_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", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000, i, + (long)per_sig / 1000000, ((long)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 (*save_name) { + /* save the signature for interop verification */ + char fn[strlen(save_name) + 5]; + sprintf(fn, "%s.sig", save_name); + FILE *fp; + if ((fp = fopen(fn, "wb")) == NULL) + lose("Error opening %s: %s\n", fn, strerror(errno)); + size_t len; + if ((len = fwrite(sig, 1, *sig_len, fp)) != *sig_len) + lose("Error: wrote %lu bytes to %s, expected %lu\n", len, fn, *sig_len); + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + } - if (!keep) { - if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK) - lose("Could not delete private key: %s\n", hal_error_string(err)); - } + printf("OK\n"); + return 1; - if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) - lose("Could not delete public key: %s\n", hal_error_string(err)); +fail: + return 0; +} - printf("OK\n"); - return 1; +static int test_hashsig_verify(const hal_pkey_handle_t private_key, + const uint8_t * const msg, const size_t msg_len, + const char * const save_name, + uint8_t *sig, size_t sig_len) +{ + const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; + hal_error_t err; + + hal_pkey_handle_t public_key = {HAL_HANDLE_NONE}; + hal_uuid_t public_name; + uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)]; + size_t der_len; + + if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &der_len, sizeof(public_der))) != HAL_OK) + lose("Error DER encoding public key from private key: %s\n", hal_error_string(err)); + assert(der_len == sizeof(public_der)); + + if ((err = hal_rpc_pkey_load(client, session, &public_key, &public_name, + public_der, sizeof(public_der), HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + lose("Error loading public key: %s\n", hal_error_string(err)); + + if (*save_name) { + /* save the public key for interop verification */ + 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]; + size_t xdr_len; + if ((err = hal_hashsig_public_key_der_to_xdr(public_der, sizeof(public_der), pub, &xdr_len, sizeof(pub))) != HAL_OK) + lose("Error XDR encoding public key: %s\n", hal_error_string(err)); + size_t write_len; + if ((write_len = fwrite(pub, 1, xdr_len, fp)) != xdr_len) + lose("Wrote %lu bytes to %s, expected %lu\n", write_len, fn, xdr_len); + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); } -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)); + struct timeval tv_start, tv_end, tv_diff; + if (info) + gettimeofday(&tv_start, NULL); - 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)); + if ((err = hal_rpc_pkey_verify(public_key, hal_hash_handle_none, + msg, msg_len, sig, sig_len)) != HAL_OK) + lose("Error verifying: %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", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000); + } + if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) + lose("Error deleting public key: %s\n", hal_error_string(err)); + + printf("OK\n"); + return 1; + +fail: return 0; } @@ -437,7 +444,7 @@ static int read_sig(char *fn) 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)); + lose("Error: 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)); @@ -455,21 +462,24 @@ fail: int main(int argc, char *argv[]) { const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; char *pin = "fnord"; - int do_default = 1; int do_testvec = 0; - size_t iterations = 1; + size_t iterations = 0; 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; + int save = 0, keep = 0, verify = 0; + char *name = NULL; + hal_key_flags_t flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN; char *p; hal_error_t err; int ok = 1; + uint8_t *msg = tc1_msg; + size_t msg_len = sizeof(tc1_msg); 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\ +Usage: %s [-i] [-p pin] [-t] [-L #] [-l #] [-o #] [-n #] [-s] [-r file] [-m file] [-x] [-v]\n\ -i: enable informational messages - runtimes and signature lengths\n\ -p: user PIN\n\ -t: verify test vectors\n\ @@ -477,23 +487,23 @@ Usage: %s [-d] [-i] [-p pin] [-t] [-L n] [-l n] [-o n] [-n n] [-s] [-r file]\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\ + -K: use named key for signing (don't generate)\n\ + -s: save generated public key and signatures for interop verification\n\ -r: read and pretty-print a saved signature file\n\ + -m: use file as message to be signed\n\ + -x: mark key as exportable\n\ + -v: verify generated signature\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) { + while ((opt = getopt(argc, argv, "itp:L:l:o:n:skK:r:xvm: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; @@ -503,28 +513,24 @@ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; 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; @@ -532,34 +538,57 @@ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; case 'k': keep = 1; break; + case 'K': + name = optarg; + break; case 'r': ok &= read_sig(optarg); - do_default = 0; break; + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + verify = 1; + if (iterations == 0) + iterations = 1; + break; + case 'm': + { + FILE *fp; + struct stat statbuf; + if (stat(optarg, &statbuf) != 0) + lose("Error statting %s: %s\n", optarg, strerror(errno)); + msg_len = statbuf.st_size; + if ((msg = malloc(msg_len)) == NULL) + lose("Error allocating message buffer: %s\n", strerror(errno)); + if ((fp = fopen(optarg, "rb")) == NULL) + lose("Error opening %s: %s\n", optarg, strerror(errno)); + size_t len; + if ((len = fread(msg, 1, msg_len, fp)) != msg_len) + lose("Error: read %lu bytes from %s, expected %lu\n", len, optarg, msg_len); + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", optarg, strerror(errno)); + break; + } case 'h': case '?': fprintf(stdout, usage, argv[0]); - exit(EXIT_SUCCESS); + return EXIT_SUCCESS; default: fprintf(stderr, usage, argv[0]); - exit(EXIT_FAILURE); + return 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)); + lose("Error 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)); + lose("Error logging into HSM: %s\n", hal_error_string(err)); if (do_testvec) { for (int i = 0; i < (sizeof(hashsig_tc)/sizeof(*hashsig_tc)); i++) @@ -574,21 +603,88 @@ Numeric arguments can be a single number or a range, e.g. '1..4'\n"; /* 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 (name != NULL) { + hal_uuid_t uuid; + hal_pkey_handle_t private_key = {HAL_HANDLE_NONE}; + + if ((err = hal_uuid_parse(&uuid, name)) != HAL_OK) + lose("Error parsing private key name: %s\n", hal_error_string(err)); + + else if ((err = hal_rpc_pkey_open(client, session, &private_key, &uuid)) != HAL_OK) + lose("Error opening private key: %s\n", hal_error_string(err)); + + if (save) { + /* save the message for interop verification */ + FILE *fp; + if ((fp = fopen(name, "wb")) == NULL) + lose("Error opening %s: %s\n", name, strerror(errno)); + size_t write_len; + if ((write_len = fwrite(msg, 1, msg_len, fp)) != msg_len) + lose("Error: wrote %lu bytes to %s, expected %lu\n", write_len, name, msg_len); + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", name, strerror(errno)); + } + + uint8_t sig[16000]; + size_t sig_len; + if (iterations > 0) + ok &= test_hashsig_sign(private_key, msg, msg_len, iterations, + save ? name : "", sig, &sig_len, sizeof(sig)); + + if (ok && verify) + ok &= test_hashsig_verify(private_key, msg, msg_len, save ? name : "", sig, sig_len); + + /* implicitly keep the key */ + } + + else { + if (L_lo) { + for (size_t L = L_lo; L <= L_hi; ++L) { + for (hal_lms_algorithm_t lms_type = lms_lo; lms_type <= lms_hi; ++lms_type) { + for (hal_lmots_algorithm_t lmots_type = lmots_lo; lmots_type <= lmots_hi; ++lmots_type) { + 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)); + + char save_name[16] = ""; + if (save) { + /* save the message for interop verification */ + 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 write_len; + if ((write_len = fwrite(msg, 1, msg_len, fp)) != msg_len) + lose("Error: wrote %lu bytes to %s, expected %lu\n", write_len, save_name, msg_len); + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", save_name, strerror(errno)); + } + + hal_pkey_handle_t private_key = {HAL_HANDLE_NONE}; + ok &= test_hashsig_generate(L, lms_type, lmots_type, flags, keep, &private_key); + + uint8_t sig[hal_hashsig_signature_len(L, lms_type, lmots_type)]; + size_t sig_len; + if (ok && iterations > 0) + ok &= test_hashsig_sign(private_key, msg, msg_len, iterations, save_name, sig, &sig_len, sizeof(sig)); + + if (ok && verify) + ok &= test_hashsig_verify(private_key, msg, msg_len, save_name, sig, sig_len); + + if (!keep && ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK)) + lose("Error deleting private key: %s\n", hal_error_string(err)); + } } } } } if ((err = hal_rpc_logout(client)) != HAL_OK) - printf("Warning: Trouble logging out of HSM: %s\n", hal_error_string(err)); + lose("Error 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)); + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); +fail: return !ok; } diff --git a/tests/test-xdr.c b/tests/test-xdr.c index eedf48d..f084e01 100644 --- a/tests/test-xdr.c +++ b/tests/test-xdr.c @@ -95,8 +95,8 @@ int main(int argc, char *argv[]) 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) { + size_t len; + if ((ret = hal_xdr_decode_variable_opaque(&readptr, limit, readbuf, &len, bufptr - readptr)) != HAL_OK) { printf("%s\n", hal_error_string(ret)); break; } diff --git a/unit-tests.py b/unit-tests.py index 514aace..27a4b24 100644 --- a/unit-tests.py +++ b/unit-tests.py @@ -860,11 +860,11 @@ class TestPKeyGen(TestCaseLoggedIn): Tests involving key generation. """ - def sign_verify(self, hashalg, k1, k2): + def sign_verify(self, hashalg, k1, k2, length = 1024): h = hsm.hash_initialize(hashalg) h.update("Your mother was a hamster") data = h.finalize() - sig = k1.sign(data = data) + sig = k1.sign(data = data, length = length) k1.verify(signature = sig, data = data) k2.verify(signature = sig, data = data) @@ -882,6 +882,13 @@ class TestPKeyGen(TestCaseLoggedIn): self.addCleanup(k2.delete) self.sign_verify(hashalg, k1, k2) + def gen_sign_verify_hashsig(self, L, lms, lmots, length): + k1 = hsm.pkey_generate_hashsig(L, lms, lmots, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN) + self.addCleanup(k1.delete) + k2 = hsm.pkey_load(k1.public_key, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN) + self.addCleanup(k2.delete) + self.sign_verify(HAL_DIGEST_ALGORITHM_SHA256, k1, k2, length) + def test_gen_sign_verify_ecdsa_p256_sha256(self): self.gen_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA256, HAL_CURVE_P256) @@ -906,6 +913,12 @@ class TestPKeyGen(TestCaseLoggedIn): with self.assertRaises(HAL_ERROR_BAD_ARGUMENTS): hsm.pkey_generate_rsa(1028).delete() + def test_gen_sign_verify_hashsig_L1_h5_w4(self): + self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352) + + def test_gen_sign_verify_hashsig_L2_h5_w2(self): + self.gen_sign_verify_hashsig(2, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W2, 8980) + class TestPKeyHashing(TestCaseLoggedIn): """ @@ -930,35 +943,42 @@ class TestPKeyHashing(TestCaseLoggedIn): self.addCleanup(k2.delete) method(alg, k1, k2) + def gen_sign_verify_hashsig(self, L, lms, lmots, length, method): + k1 = hsm.pkey_generate_hashsig(L, lms, lmots, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN) + self.addCleanup(k1.delete) + k2 = hsm.pkey_load(k1.public_key, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN) + self.addCleanup(k2.delete) + method(HAL_DIGEST_ALGORITHM_SHA256, k1, k2, length) + @staticmethod def h(alg, mixed_mode = False): h = hsm.hash_initialize(alg, mixed_mode = mixed_mode) h.update("Your mother was a hamster") return h - def sign_verify_data(self, alg, k1, k2): + def sign_verify_data(self, alg, k1, k2, length = 1024): data = self.h(alg, mixed_mode = True).finalize() - sig = k1.sign(data = data) + sig = k1.sign(data = data, length = length) k1.verify(signature = sig, data = data) k2.verify(signature = sig, data = data) - def sign_verify_remote_remote(self, alg, k1, k2): - sig = k1.sign(hash = self.h(alg, mixed_mode = False)) + def sign_verify_remote_remote(self, alg, k1, k2, length = 1024): + sig = k1.sign(hash = self.h(alg, mixed_mode = False), length = length) k1.verify(signature = sig, hash = self.h(alg, mixed_mode = False)) k2.verify(signature = sig, hash = self.h(alg, mixed_mode = False)) - def sign_verify_remote_local(self, alg, k1, k2): - sig = k1.sign(hash = self.h(alg, mixed_mode = False)) + def sign_verify_remote_local(self, alg, k1, k2, length = 1024): + sig = k1.sign(hash = self.h(alg, mixed_mode = False), length = length) k1.verify(signature = sig, hash = self.h(alg, mixed_mode = True)) k2.verify(signature = sig, hash = self.h(alg, mixed_mode = True)) - def sign_verify_local_remote(self, alg, k1, k2): - sig = k1.sign(hash = self.h(alg, mixed_mode = True)) + def sign_verify_local_remote(self, alg, k1, k2, length = 1024): + sig = k1.sign(hash = self.h(alg, mixed_mode = True), length = length) k1.verify(signature = sig, hash = self.h(alg, mixed_mode = False)) k2.verify(signature = sig, hash = self.h(alg, mixed_mode = False)) - def sign_verify_local_local(self, alg, k1, k2): - sig = k1.sign(hash = self.h(alg, mixed_mode = True)) + def sign_verify_local_local(self, alg, k1, k2, length = 1024): + sig = k1.sign(hash = self.h(alg, mixed_mode = True), length = length) k1.verify(signature = sig, hash = self.h(alg, mixed_mode = True)) k2.verify(signature = sig, hash = self.h(alg, mixed_mode = True)) @@ -1082,6 +1102,18 @@ class TestPKeyHashing(TestCaseLoggedIn): def test_load_sign_verify_ecdsa_p521_sha512_local_local(self): self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_local_local) + def test_gen_sign_verify_hashsig_L1_h5_w4_remote_remote(self): + self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352, self.sign_verify_remote_remote) + + def test_gen_sign_verify_hashsig_L1_h5_w4_remote_local(self): + self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352, self.sign_verify_remote_local) + + def test_gen_sign_verify_hashsig_L1_h5_w4_local_remote(self): + self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352, self.sign_verify_local_remote) + + def test_gen_sign_verify_hashsig_L1_h5_w4_local_local(self): + self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352, self.sign_verify_local_local) + @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package") class TestPKeyRSAInterop(TestCaseLoggedIn): @@ -1272,40 +1304,32 @@ class TestPKeyAttribute(TestCaseLoggedIn): for j in xrange(n_attrs))) pinwheel() - # These sizes work with a 4096-byte keystore block; if you tweak - # the undelrying block size, you may need to tweak these tests too. + # These sizes work with a 8192-byte keystore block; if you tweak + # the underlying block size, you may need to tweak these tests too. def test_attribute_svelt_volatile_many(self): self.load_and_fill(0, n_attrs = 64) def test_attribute_bloat_volatile_many(self): - self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh") - with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG): - self.load_and_fill(0, n_attrs = 128) + self.load_and_fill(0, n_attrs = 128) def test_attribute_svelt_volatile_big(self): self.load_and_fill(0, n_attrs = 6, n_fill = 256) def test_attribute_bloat_volatile_big(self): - self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh") - with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG): - self.load_and_fill(0, n_attrs = 6, n_fill = 512) + self.load_and_fill(0, n_attrs = 6, n_fill = 512) def test_attribute_svelt_token_many(self): self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 64) def test_attribute_bloat_token_many(self): - self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh") - with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG): - self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128) + self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 128) def test_attribute_svelt_token_big(self): self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 6, n_fill = 256) def test_attribute_bloat_token_big(self): - self.skipUnlessAll("bloat tests with large flash blocks exceed XDR limits, sigh") - with self.assertRaises(HAL_ERROR_RESULT_TOO_LONG): - self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 6, n_fill = 512) + self.load_and_fill(HAL_KEY_FLAG_TOKEN, n_attrs = 6, n_fill = 512) @unittest.skipUnless(ecdsa_loaded, "Requires Python ECDSA package") diff --git a/utils/Makefile b/utils/Makefile index ce36d4c..799bf94 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016, NORDUnet A/S +# Copyright (c) 2015-2018, NORDUnet A/S # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,23 +27,17 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -ifndef CRYPTECH_ROOT - CRYPTECH_ROOT := $(abspath ../../..) -endif - -LIBTFM_SRC ?= ${CRYPTECH_ROOT}/sw/thirdparty/libtfm -LIBTFM_BLD ?= ${LIBTFM_SRC} - -LIBHAL_SRC ?= ${CRYPTECH_ROOT}/sw/libhal +LIBHAL_SRC ?= .. LIBHAL_BLD ?= ${LIBHAL_SRC} +LIBTFM_BLD ?= ../../thirdparty/libtfm LIBS = ${LIBHAL_BLD}/libhal.a ${LIBTFM_BLD}/libtfm.a CFLAGS ?= -g3 -Wall -fPIC -std=c99 -I${LIBHAL_SRC} -I${LIBTFM_BLD} -BIN = eim_peek_poke cores +BIN = $(if $(wildcard ${LIBHAL_BLD}/hal_io_eim.o),eim_peek_poke) $(if $(wildcard ${LIBHAL_BLD}/core.o),cores) pkey-export pkey-import pkey -all: $(if $(wildcard ${LIBHAL_BLD}/hal_io_eim.o),eim_peek_poke) $(if $(wildcard ${LIBHAL_BLD}/core.o),cores) +all: ${BIN} clean: rm -f *.o ${BIN} diff --git a/utils/pkey-export.c b/utils/pkey-export.c new file mode 100644 index 0000000..660052e --- /dev/null +++ b/utils/pkey-export.c @@ -0,0 +1,187 @@ +/* + * pkey-export.c + * ------------- + * Export a key. + * + * 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 <stdio.h> +#include <getopt.h> +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <hal.h> + +#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7) + +#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) + +static int read_file(const char * const fn, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + int fd; + if ((fd = open(fn, O_RDONLY)) == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t nread; + if ((nread = read(fd, buf, buf_max)) == -1) + lose("Error reading %s: %s\n", fn, strerror(errno)); + + *buf_len = nread; + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +static int write_buf(const char * const name, const char * const ext, const uint8_t * const buf, const size_t buf_len) +{ + char fn[strlen(name) + strlen(ext) + 1]; + strcpy(fn, name); + strcat(fn, ext); + + int fd = creat(fn, S_IRUSR); + if (fd == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + ssize_t nwrite; + if ((nwrite = write(fd, buf, buf_len)) != buf_len) + lose("Error writing %s: wrote %lu, expected %lu\n", fn, nwrite, buf_len); + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +#define lose_usage(...) do { printf(__VA_ARGS__); printf(usage, argv[0]); goto fail; } while (0) + +int main(int argc, char *argv[]) +{ + hal_error_t err; + const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; + char *pin = "fnord"; + char *kekek_fn = NULL; + char *save_fn = NULL; + char *keyname = NULL; + +char usage[] = "\ +Usage: %s [-p pin] <-k kekek> [-o outfile] keyname\n\ +"; + + int opt; + while ((opt = getopt(argc, argv, "p:k:o:")) != -1) { + switch (opt) { + case 'p': + pin = optarg; + break; + case 'k': + kekek_fn = optarg; + break; + case 'o': + save_fn = optarg; + break; + case 'h': + case '?': + printf(usage, argv[0]); + return 0; + } + } + keyname = argv[optind]; + + if (kekek_fn == NULL) + lose_usage("Error: missing option -k\n"); + if (save_fn == NULL) + save_fn = keyname; + if (keyname == NULL) + lose_usage("Error: missing keyname\n"); + + uint8_t kekek_der[HAL_KS_WRAPPED_KEYSIZE]; size_t kekek_der_len; + if (read_file(kekek_fn, kekek_der, &kekek_der_len, sizeof(kekek_der)) != 0) + goto fail; + + hal_uuid_t pkey_name; + + if ((err = hal_uuid_parse(&pkey_name, keyname)) != HAL_OK) + lose("Error parsing private key name: %s\n", hal_error_string(err)); + + + if ((err = hal_rpc_client_init()) != HAL_OK) + lose("Error initializing RPC client: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK) + lose("Error logging into HSM: %s\n", hal_error_string(err)); + + hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; + + if ((err = hal_rpc_pkey_open(client, session, &pkey, &pkey_name)) != HAL_OK) + lose("Error opening private key: %s\n", hal_error_string(err)); + + hal_pkey_handle_t kekek = {HAL_HANDLE_NONE}; + hal_uuid_t kekek_name; + + if ((err = hal_rpc_pkey_load(client, session, &kekek, &kekek_name, + kekek_der, kekek_der_len, + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)) != HAL_OK) + lose("Error loading export key: %s\n", hal_error_string(err)); + + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; + uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len; + + if ((err = hal_rpc_pkey_export(pkey, kekek, + der, &der_len, sizeof(der), + kek, &kek_len, sizeof(kek))) != HAL_OK) + lose("Error exporting private key: %s\n", hal_error_string(err)); + + if (write_buf(save_fn, ".der", der, der_len) != 0 || + write_buf(save_fn, ".kek", kek, kek_len) != 0) + goto fail; + + if ((err = hal_rpc_logout(client)) != HAL_OK) + lose("Error logging out of HSM: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_client_close()) != HAL_OK) + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); + + return 0; + +fail: + return -1; +} diff --git a/utils/pkey-import.c b/utils/pkey-import.c new file mode 100644 index 0000000..611448f --- /dev/null +++ b/utils/pkey-import.c @@ -0,0 +1,168 @@ +/* + * pkey-import.c + * ------------- + * Import a key. + * + * 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 <stdio.h> +#include <getopt.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <hal.h> + +#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7) + +#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) + +static int read_file(const char * const fn, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + int fd; + if ((fd = open(fn, O_RDONLY)) == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t nread; + if ((nread = read(fd, buf, buf_max)) == -1) + lose("Error reading %s: %s\n", fn, strerror(errno)); + + *buf_len = nread; + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +static int read_buf(const char * const name, const char * const ext, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + char fn[strlen(name) + strlen(ext) + 1]; + strcpy(fn, name); + strcat(fn, ext); + + return read_file(fn, buf, buf_len, buf_max); +} + +#define lose_usage(...) do { printf(__VA_ARGS__); printf(usage, argv[0]); goto fail; } while (0) + +int main(int argc, char *argv[]) +{ + hal_error_t err; + const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; + char *pin = "fnord"; + char *kekek_fn = NULL; + char *key_fn = NULL; + +char usage[] = "\ +Usage: %s [-p pin] <-k kekek> keyfile\n\ +"; + + int opt; + while ((opt = getopt(argc, argv, "p:k:")) != -1) { + switch (opt) { + case 'p': + pin = optarg; + break; + case 'k': + kekek_fn = optarg; + break; + case 'h': + case '?': + printf(usage, argv[0]); + return 0; + } + } + key_fn = argv[optind]; + + if (kekek_fn == NULL) + lose_usage("Error: missing option -k\n"); + if (key_fn == NULL) + lose_usage("Error: missing keyfile\n"); + + uint8_t kekek_der[HAL_KS_WRAPPED_KEYSIZE]; size_t kekek_der_len; + + if (read_file(kekek_fn, kekek_der, &kekek_der_len, sizeof(kekek_der)) != 0) + goto fail; + + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; + uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len; + + if (read_buf(key_fn, ".der", der, &der_len, sizeof(der)) != 0 || + read_buf(key_fn, ".kek", kek, &kek_len, sizeof(kek)) != 0) + goto fail; + + if ((err = hal_rpc_client_init()) != HAL_OK) + lose("Error initializing RPC client: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK) + lose("Error logging into HSM: %s\n", hal_error_string(err)); + + hal_pkey_handle_t kekek = {HAL_HANDLE_NONE}; + hal_uuid_t kekek_name; + + if ((err = hal_rpc_pkey_load(client, session, &kekek, &kekek_name, + kekek_der, kekek_der_len, + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)) != HAL_OK) + lose("Error loading import key: %s\n", hal_error_string(err)); + + hal_pkey_handle_t private_key = {HAL_HANDLE_NONE}; + hal_uuid_t private_name; + + if ((err = hal_rpc_pkey_import(client, session, + &private_key, &private_name, + kekek, + der, der_len, + kek, kek_len, + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN | HAL_KEY_FLAG_EXPORTABLE)) != HAL_OK) + lose("Error importing private key: %s\n", hal_error_string(err)); + + char name_str[HAL_UUID_TEXT_SIZE]; + + if ((err = hal_uuid_format(&private_name, name_str, sizeof(name_str))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + printf("New private key name: %s\n", name_str); + + if ((err = hal_rpc_logout(client)) != HAL_OK) + lose("Error logging out of HSM: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_client_close()) != HAL_OK) + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); + + return 0; + +fail: + return -1; +} diff --git a/utils/pkey.c b/utils/pkey.c new file mode 100644 index 0000000..fa566a9 --- /dev/null +++ b/utils/pkey.c @@ -0,0 +1,1215 @@ +/* + * pkey.c + * ------ + * Fully-featured key management app + * + * 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 <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#include <strings.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <hal.h> + +/* + * The all-singing, all-dancing key management app. + * This is designed so that commands can be concatenated, e.g. + * + * pkey generate rsa sign -h -n 100 verify -h delete + * + * i.e. Generate an RSA key with default parameters, hash the default message + * and sign it 100 times, verify the signature, and delete the key. + * + * generate rsa [-l keylen-in-bits] [-e exponent] + * generate ec [-c curve] + * generate hashsig [-L levels] [-h height] [-w Winternitz factor] + * list [-t type] [-c curve] [-y keystore] + * sign [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile] [-n iterations] + * verify [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile] + * export [-k keyname] [-K kekekfile] [-o outfile] + * import [-K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)] + * delete [-k keyname] + */ + +/* + * By default, GNU getopt() permutes the arguments to put all options first, + * followed by non-options. Adding a dash at the start of the option string + * preserves argument ordering by treating any non-option as an option with + * character code 1. + * + * In contrast, BSD getopt() does not permute the arguments, but returns -1 on + * the first non-option it sees (and ignores a leading dash in the option + * string, thank god). + * + * We can't predict or detect which version of getopt() we get linked with, so + * we do this weird hybrid, where option value 1 causes the parser to back up + * one and drop out. + */ + +#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7) + +#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) + +#ifndef timersub +#define timersub(a, b, res) \ + do { \ + (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; \ + } \ + } while (0) +#endif + +static int info = 0; +static char *pin = "fnord"; + +static hal_pkey_handle_t key_handle = {HAL_HANDLE_NONE}; +static hal_uuid_t key_uuid = {{0}}; + +#define DFLT_MSG "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +static uint8_t msg[16000] = DFLT_MSG; +static size_t msg_len = sizeof(DFLT_MSG); + +static uint8_t sig[16000] = ""; +static size_t sig_len = 0; + +static hal_key_flags_t flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN; + +static const hal_client_handle_t client = {HAL_HANDLE_NONE}; +static const hal_session_handle_t session = {HAL_HANDLE_NONE}; + +static size_t file_size(const char * const fn) +{ + struct stat statbuf; + if (stat(fn, &statbuf) != 0) { + printf("%s: %s\n", fn, strerror(errno)); + return SIZE_MAX; + } + + return statbuf.st_size; +} + +static int file_read(const char * const fn, void *buf, size_t *buf_len, const size_t buf_max) +{ + size_t fsize = file_size(fn); + if (fsize == SIZE_MAX) + return -1; + if (fsize > buf_max) + lose("Error: %s (%lu bytes) is too big for buffer (%lu bytes)\n", fn, fsize, buf_max); + + FILE *fp; + if ((fp = fopen(fn, "rb")) == NULL) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t len; + if ((len = fread(buf, 1, fsize, fp)) != fsize) + lose("Error: read %lu bytes from %s, expected %lu\n", len, fn, fsize); + + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + *buf_len = len; + return 0; + +fail: + return -1; +} + +static int file_write(const char * const fn, const void * const buf, const size_t buf_len, int secret) +{ + FILE *fp; + if ((fp = fopen(fn, "wb")) == NULL) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t nwrite; + if ((nwrite = fwrite(buf, 1, buf_len, fp)) != buf_len) + lose("Error writing %s: wrote %lu, expected %lu\n", fn, nwrite, buf_len); + + if (fclose(fp) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + if (secret && chmod(fn, S_IRUSR) != 0) + lose("Error chmod'ing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + (void)unlink(fn); + return -1; +} + +static int logged_in = 0; +static int pkey_login(void) +{ + if (!logged_in) { + hal_error_t err = HAL_OK; + + if ((err = hal_rpc_client_init()) != HAL_OK) + lose("Error initializing RPC client: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK) + lose("Error logging into HSM: %s\n", hal_error_string(err)); + + logged_in = 1; + } + return 0; + +fail: + return -1; +} + +static int pkey_logout(void) +{ + if (logged_in) { + hal_error_t err = HAL_OK; + + if ((err = hal_rpc_logout(client)) != HAL_OK) + lose("Error logging out of HSM: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_client_close()) != HAL_OK) + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); + + logged_in = 0; + } + return 0; + +fail: + return -1; +} + +static int pkey_open(const char * const key_name) +{ + hal_error_t err; + if (key_handle.handle == HAL_HANDLE_NONE) { + if ((err = hal_uuid_parse(&key_uuid, key_name)) != HAL_OK) + lose("Error parsing key name: %s\n", hal_error_string(err)); + if ((err = hal_rpc_pkey_open(client, session, &key_handle, &key_uuid)) != HAL_OK) + lose("Error opening key: %s\n", hal_error_string(err)); + } + return 0; + +fail: + key_handle.handle = HAL_HANDLE_NONE; + return -1; +} + +static int pkey_load(const char * const fn, hal_pkey_handle_t *key_handle) +{ + size_t der_len = file_size(fn); + if (der_len == SIZE_MAX) + return -1; + uint8_t der[der_len]; + if (file_read(fn, der, &der_len, sizeof(der)) == -1) + return -1; + + hal_pkey_handle_t handle = {HAL_HANDLE_NONE}; + hal_uuid_t uuid; + hal_error_t err; + if ((err = hal_rpc_pkey_load(client, session, &handle, &uuid, + der, der_len, + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)) != HAL_OK) + lose("Error loading key: %s\n", hal_error_string(err)); + + *key_handle = handle; + + return 0; + +fail: + return -1; +} + +static int pkey_gen_rsa(int argc, char *argv[]) +{ + char usage[] = "Usage: generate rsa [-l keylen-in-bits] [-e exponent]"; + + unsigned keylen = 1024; + unsigned long exponent = 0x010001; /* default exponent, and the only one accepted by hal_rsa_key_gen */ + uint8_t exp[sizeof(exponent)]; + + int opt; + while ((opt = getopt(argc, argv, "-l:e:xv")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'l': + keylen = atoi(optarg); + break; + case 'e': + { + char *endptr; + exponent = (uint32_t)strtoul(optarg, &endptr, 0); + if (endptr == optarg || errno == ERANGE) { + printf("invalid exponent %s\n", optarg); + puts(usage); + return -1; + } + break; + } + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + flags &= ~HAL_KEY_FLAG_TOKEN; + break; + default: + puts(usage); + return -1; + } + } +done: + + for (int i = sizeof(exp) - 1; i >= 0; --i) { + exp[i] = exponent & 0xff; + exponent >>= 8; + } + + struct timeval tv_start, tv_end, tv_diff; + if (info) + gettimeofday(&tv_start, NULL); + + hal_error_t err; + if ((err = hal_rpc_pkey_generate_rsa(client, session, &key_handle, &key_uuid, + keylen, exp, sizeof(exp), flags)) != HAL_OK) + lose("Could not generate RSA private key: %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 generate key\n", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000); + } + + char key_name[HAL_UUID_TEXT_SIZE]; + if ((err = hal_uuid_format(&key_uuid, key_name, sizeof(key_name))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + if (info) + printf("Private key name: %s\n", key_name); + + return 0; + +fail: + if (key_handle.handle != HAL_HANDLE_NONE && + (err = hal_rpc_pkey_delete(key_handle)) != HAL_OK) + printf("Error deleting private key: %s\n", hal_error_string(err)); + + key_handle.handle = HAL_HANDLE_NONE; + + return -1; +} + +static int pkey_gen_ec(int argc, char *argv[]) +{ + char usage[] = "Usage: generate ec [-c curve]"; + + hal_curve_name_t curve = HAL_CURVE_P256; + hal_error_t err; + struct timeval tv_start, tv_end, tv_diff; + + int opt; + while ((opt = getopt(argc, argv, "-c:xv")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'c': + if (strcasecmp(optarg, "P256") == 0) + curve = HAL_CURVE_P256; + else if (strcasecmp(optarg, "P384") == 0) + curve = HAL_CURVE_P384; + else if (strcasecmp(optarg, "P521") == 0) + curve = HAL_CURVE_P521; + else { + printf("generate ec: invalid curve %s - must be one of P256, P384, P521\n", optarg); + return -1; + } + break; + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + flags &= ~HAL_KEY_FLAG_TOKEN; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (info) + gettimeofday(&tv_start, NULL); + + if ((err = hal_rpc_pkey_generate_ec(client, session, &key_handle, &key_uuid, + curve, flags)) != HAL_OK) + lose("Could not generate EC private key: %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 generate key\n", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000); + } + + char key_name[HAL_UUID_TEXT_SIZE]; + if ((err = hal_uuid_format(&key_uuid, key_name, sizeof(key_name))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + if (info) + printf("Private key name: %s\n", key_name); + + return 0; + +fail: + if (key_handle.handle != HAL_HANDLE_NONE && + (err = hal_rpc_pkey_delete(key_handle)) != HAL_OK) + printf("Error deleting private key: %s\n", hal_error_string(err)); + + key_handle.handle = HAL_HANDLE_NONE; + + return -1; +} + +static int pkey_gen_hashsig(int argc, char *argv[]) +{ + char usage[] = "Usage: generate hashsig [-L levels] [-h height] [-w Winternitz factor]"; + + unsigned L = 1, h = 5, w = 2; + hal_lms_algorithm_t lms_type; + hal_lmots_algorithm_t lmots_type; + + int opt; + while ((opt = getopt(argc, argv, "-L:h:w:xv")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'L': + L = atoi(optarg); + break; + case 'h': + h = atoi(optarg); + break; + case 'w': + w = atoi(optarg); + break; + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + flags &= ~HAL_KEY_FLAG_TOKEN; + break; + default: + puts(usage); + return -1; + } + } +done: + + switch (h) { + case 5: + lms_type = HAL_LMS_SHA256_N32_H5; + break; + case 10: + lms_type = HAL_LMS_SHA256_N32_H10; + break; + default: + printf("generate hashsig: invalid/unsupported h value %u\n", h); + return -1; + } + + switch (w) { + case 1: + lmots_type = HAL_LMOTS_SHA256_N32_W1; + break; + case 2: + lmots_type = HAL_LMOTS_SHA256_N32_W2; + break; + case 4: + lmots_type = HAL_LMOTS_SHA256_N32_W4; + break; + case 8: + lmots_type = HAL_LMOTS_SHA256_N32_W8; + break; + default: + printf("generate hashsig: invalid w value %u\n", w); + return -1; + } + + hal_error_t err; + struct timeval tv_start, tv_end, tv_diff; + + 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)); + gettimeofday(&tv_start, NULL); + } + + if ((err = hal_rpc_pkey_generate_hashsig(client, session, &key_handle, &key_uuid, + L, lms_type, lmots_type, flags)) != HAL_OK) + lose("Error generating 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", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000, + (long)per_key / 1000000, ((long)per_key % 1000000) / 1000); + } + + char key_name[HAL_UUID_TEXT_SIZE]; + if ((err = hal_uuid_format(&key_uuid, key_name, sizeof(key_name))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + if (info) + printf("Private key name: %s\n", key_name); + + return 0; + +fail: + if (key_handle.handle != HAL_HANDLE_NONE && + (err = hal_rpc_pkey_delete(key_handle)) != HAL_OK) + printf("Error deleting private key: %s\n", hal_error_string(err)); + + key_handle.handle = HAL_HANDLE_NONE; + + return -1; +} + +static int pkey_generate(int argc, char *argv[]) +{ + char usage[] = "Usage: generate [-x (exportable)] [-v (volatile keystore)] rsa|ec|hashsig"; + + int opt; + while ((opt = getopt(argc, argv, "-xv")) != -1) { + switch (opt) { + case 1: + /* found the keytype argument */ + --optind; + goto done; + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + flags &= ~HAL_KEY_FLAG_TOKEN; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (optind < argc) { + optarg = argv[optind++]; + if (strcmp(optarg, "rsa") == 0) + return pkey_gen_rsa(argc, argv); + else if (strcmp(optarg, "ec") == 0) + return pkey_gen_ec(argc, argv); + else if (strcmp(optarg, "hashsig") == 0) + return pkey_gen_hashsig(argc, argv); + else { + printf("generate: unknown key type %s\n", optarg); + puts(usage); + return -1; + } + } + else { + printf("generate: missing key type\n"); + puts(usage); + return -1; + } +} + +static int pkey_list(int argc, char *argv[]) +{ + char usage[] = "Usage: list [-t type] [-c curve] [-y keystore]"; + +#if 0 + char *type = NULL; + char *curve = NULL; + char *keystore = NULL; +#endif + + int type_rsa = 0, type_ec = 0, type_hashsig = 0; + + int opt; + while ((opt = getopt(argc, argv, "-t:c:y:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 't': + if (strcasecmp(optarg, "rsa") == 0) + type_rsa = 1; + else if (strcasecmp(optarg, "ec") == 0) + type_ec = 1; + else if (strcasecmp(optarg, "hashsig") == 0) + type_hashsig = 1; + else + lose("unsupported key type %s, expected 'rsa', 'ec', or 'hashsig'\n", optarg); + break; +#if 0 + case 'c': + curve = optarg; + break; + case 'y': + keystore = optarg; + break; +#endif + default: + puts(usage); + return -1; + } + } +done: + + if (type_rsa == 0 && type_ec == 0 && type_hashsig == 0) + type_rsa = type_ec = type_hashsig = 1; + + char key_name[HAL_UUID_TEXT_SIZE]; + hal_uuid_t previous_uuid = {{0}}; + hal_pkey_handle_t pkey; + hal_curve_name_t curve; + hal_key_flags_t flags; + unsigned n, state = 0; + hal_uuid_t uuids[50]; + hal_key_type_t type; + hal_error_t err; + int done = 0; + + while (!done) { + + if ((err = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, + 0, 0, NULL, 0, &state, uuids, &n, + sizeof(uuids)/sizeof(*uuids), + &previous_uuid)) != HAL_OK) { + printf("Could not fetch UUID list: %s\n", hal_error_string(err)); + return -1; + } + + done = n < sizeof(uuids)/sizeof(*uuids); + + if (!done) + previous_uuid = uuids[sizeof(uuids)/sizeof(*uuids) - 1]; + + for (unsigned i = 0; i < n; i++) { + + if ((err = hal_uuid_format(&uuids[i], key_name, sizeof(key_name))) != HAL_OK) { + printf("Could not convert key name, skipping: %s\n", + hal_error_string(err)); + continue; + } + + if ((err = hal_rpc_pkey_open(client, session, &pkey, &uuids[i])) != HAL_OK) { + printf("Could not open key %s, skipping: %s\n", + key_name, hal_error_string(err)); + continue; + } + + if ((err = hal_rpc_pkey_get_key_type(pkey, &type)) != HAL_OK || + (err = hal_rpc_pkey_get_key_curve(pkey, &curve)) != HAL_OK || + (err = hal_rpc_pkey_get_key_flags(pkey, &flags)) != HAL_OK) + printf("Could not fetch metadata for key %s, skipping: %s\n", + key_name, hal_error_string(err)); + + if (err == HAL_OK) + err = hal_rpc_pkey_close(pkey); + else + (void) hal_rpc_pkey_close(pkey); + + if (err != HAL_OK) + continue; + + const char *type_name = "unknown"; + switch (type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + if (!type_rsa) continue; + type_name = "RSA private"; + break; + case HAL_KEY_TYPE_RSA_PUBLIC: + if (!type_rsa) continue; + type_name = "RSA public"; + break; + case HAL_KEY_TYPE_EC_PRIVATE: + if (!type_ec) continue; + type_name = "EC private"; + break; + case HAL_KEY_TYPE_EC_PUBLIC: + if (!type_hashsig) continue; + type_name = "EC public"; + break; + case HAL_KEY_TYPE_HASHSIG_PRIVATE: + if (!type_hashsig) continue; + type_name = "hashsig private"; + break; + case HAL_KEY_TYPE_HASHSIG_PUBLIC: + if (!type_hashsig) continue; + type_name = "hashsig public"; + break; + default: + continue; + } + + const char *curve_name = "unknown"; + switch (curve) { + case HAL_CURVE_NONE: curve_name = "none"; break; + case HAL_CURVE_P256: curve_name = "P-256"; break; + case HAL_CURVE_P384: curve_name = "P-384"; break; + case HAL_CURVE_P521: curve_name = "P-521"; break; + } + + printf("name %s, type %s, ", key_name, type_name); + if (curve != HAL_CURVE_NONE) + printf("curve %s, ", curve_name); + printf("flags 0x%lx\n", (unsigned long) flags); + } + } + + return 0; + +fail: + return -1; +} + +/* Hash and PKCS #1 encode a message, because that's what RSA and ECDSA(?) + * expect to sign, rather than plaintext. + * + * Also, do the full hashing here, rather than passing a hash handle to + * sign/verify, because we may want to sign/verify repeatedly to get + * performance numbers. + */ +static int hash_message(uint8_t *digest, size_t *digest_len, const size_t digest_max) +{ + hal_error_t err; + hal_hash_handle_t hash; + + if ((err = hal_rpc_hash_initialize(client, session, &hash, HAL_DIGEST_ALGORITHM_SHA256, NULL, 0)) != HAL_OK) + lose("sign: Error initializing hash: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_hash_update(hash, msg, msg_len)) != HAL_OK) + lose("sign: Error updating hash: %s\n", hal_error_string(err)); + + extern hal_error_t hal_rpc_pkcs1_construct_digestinfo(const hal_hash_handle_t handle, + uint8_t *digest_info, + size_t *digest_info_len, + const size_t digest_info_max); + if ((err = hal_rpc_pkcs1_construct_digestinfo(hash, digest, digest_len, digest_max)) != HAL_OK) + lose("sign: Error constructing PKCS #1 DigestInfo: %s\n", hal_error_string(err)); + + return 0; + +fail: + return -1; +} + +static int pkey_sign(int argc, char *argv[]) +{ + char usage[] = "Usage: sign [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile] [-n iterations]"; + + char *sig_fn = NULL; + unsigned n = 1; + int hash_msg = 0; + + int opt; + while ((opt = getopt(argc, argv, "-hk:m:s:n:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'h': + hash_msg = 1; + break; + case 'k': + if (pkey_open(optarg) != 0) + return -1; + break; + case 'm': + if (file_read(optarg, msg, &msg_len, sizeof(msg)) != 0) + return -1; + break; + case 's': + sig_fn = optarg; + break; + case 'n': + n = atoi(optarg); + break; + default: + puts(usage); + return -1; + } + } +done: + + if (key_handle.handle == HAL_HANDLE_NONE) { + printf("sign: missing key\n"); + puts(usage); + return -1; + } + + if (msg_len == 0) { + printf("sign: missing message\n"); + puts(usage); + return -1; + } + + uint8_t *m = msg; + size_t mlen = msg_len; + uint8_t digest[128]; + if (hash_msg && hash_message(m = digest, &mlen, sizeof(digest)) != 0) + goto fail; + + struct timeval tv_start, tv_end, tv_diff; + if (info) + gettimeofday(&tv_start, NULL); + + unsigned i; + for (i = 0; i < n; ++i) { + hal_error_t err; + if ((err = hal_rpc_pkey_sign(key_handle, hal_hash_handle_none, + m, mlen, sig, &sig_len, sizeof(sig))) != HAL_OK) { + if (i > 0 && err == HAL_ERROR_HASHSIG_KEY_EXHAUSTED) + break; + else + lose("Error signing (%d): %s\n", i, hal_error_string(err)); + } + } + + 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 of length %lu (%ld.%03lds per signature)\n", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000, i, sig_len, + (long)per_sig / 1000000, ((long)per_sig % 1000000) / 1000); + } + + if (sig_fn != NULL && file_write(sig_fn, sig, sig_len, 0) != 0) + return -1; + + return 0; + +fail: + return -1; +} + +static int pkey_verify(int argc, char *argv[]) +{ + char usage[] = "Usage: verify [-h (hash)] [-k keyname] [-m msgfile] [-s sigfile]"; + + int hash_msg = 0; + + int opt; + while ((opt = getopt(argc, argv, "-hk:m:s:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + break; + case 'h': + hash_msg = 1; + break; + case 'k': + if (pkey_open(optarg) != 0) + return -1; + break; + case 'm': + if (file_read(optarg, msg, &msg_len, sizeof(msg)) != 0) + return -1; + break; + case 's': + if (file_read(optarg, sig, &sig_len, sizeof(sig)) != 0) + return -1; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (key_handle.handle == HAL_HANDLE_NONE) { + printf("verify: missing key\n"); + puts(usage); + return -1; + } + + if (msg_len == 0) { + printf("verify: missing message\n"); + puts(usage); + return -1; + } + + if (sig_len == 0) { + printf("verify: missing signature\n"); + puts(usage); + return -1; + } + + uint8_t *m = msg; + size_t mlen = msg_len; + uint8_t digest[128]; + if (hash_msg && hash_message(m = digest, &mlen, sizeof(digest)) != 0) + goto fail; + + hal_error_t err; + struct timeval tv_start, tv_end, tv_diff; + if (info) + gettimeofday(&tv_start, NULL); + + if ((err = hal_rpc_pkey_verify(key_handle, hal_hash_handle_none, + m, mlen, sig, sig_len)) != HAL_OK) + lose("Error verifying: %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", + (long)tv_diff.tv_sec / 60, (long)tv_diff.tv_sec % 60, (long)tv_diff.tv_usec / 1000); + } + + return 0; + +fail: + return -1; +} + +static int pkey_export(int argc, char *argv[]) +{ + char usage[] = "Usage: export [-k keyname] [-K kekekfile] [-o outfile]"; + + hal_pkey_handle_t kekek_handle = {HAL_HANDLE_NONE}; + char *kekek_fn = NULL; + char *out_fn = NULL; + + int opt; + while ((opt = getopt(argc, argv, "-k:K:o:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + break; + case 'k': + if (pkey_open(optarg) != 0) + return -1; + break; + case 'K': + kekek_fn = optarg; + break; + case 'o': + out_fn = optarg; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (key_handle.handle == HAL_HANDLE_NONE) { + printf("export: missing key\n"); + puts(usage); + return -1; + } + + if (kekek_fn == NULL) { + printf("export: missing kekek\n"); + puts(usage); + return -1; + } + + { + hal_error_t err; + char key_name[HAL_UUID_TEXT_SIZE]; + if (out_fn == NULL) { + if ((err = hal_uuid_format(&key_uuid, key_name, sizeof(key_name))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + out_fn = key_name; + } + + if (pkey_load(kekek_fn, &kekek_handle) != 0) + goto fail; + + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; + uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len; + + if ((err = hal_rpc_pkey_export(key_handle, kekek_handle, + der, &der_len, sizeof(der), + kek, &kek_len, sizeof(kek))) != HAL_OK) + lose("Error exporting private key: %s\n", hal_error_string(err)); + + char fn[strlen(out_fn) + 5]; + strcpy(fn, out_fn); strcat(fn, ".der"); + if (file_write(fn, der, der_len, 1) != 0) + goto fail; + + strcpy(fn, out_fn); strcat(fn, ".kek"); + if (file_write(fn, kek, kek_len, 1) != 0) + goto fail; + + if ((err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK) + lose("Could not delete key: %s\n", hal_error_string(err)); + } + + return 0; + +fail: + if (kekek_handle.handle != HAL_HANDLE_NONE) + (void)hal_rpc_pkey_delete(kekek_handle); + + return -1; +} + +static int pkey_import(int argc, char *argv[]) +{ + char usage[] = "Usage: import [-K kekekfile] [-i infile] [-x (exportable)] [-v (volatile keystore)]"; + + hal_pkey_handle_t kekek_handle = {HAL_HANDLE_NONE}; + char *kekek_fn = NULL; + char *in_fn = NULL; + + int opt; + while ((opt = getopt(argc, argv, "-K:i:xv")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + break; + case 'K': + kekek_fn = optarg; + break; + case 'i': + in_fn = optarg; + break; + case 'x': + flags |= HAL_KEY_FLAG_EXPORTABLE; + break; + case 'v': + flags &= ~HAL_KEY_FLAG_TOKEN; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (kekek_fn == NULL) { + printf("export: missing kekek\n"); + puts(usage); + return -1; + } + + if (in_fn == NULL) { + printf("export: missing infile\n"); + puts(usage); + return -1; + } + + if (pkey_load(kekek_fn, &kekek_handle) != 0) + goto fail; + + { + char fn[strlen(in_fn) + 5]; + strcpy(fn, in_fn); strcat(fn, ".der"); + size_t der_len = file_size(fn); + if (der_len == SIZE_MAX) + goto fail; + uint8_t der[der_len]; + if (file_read(fn, der, &der_len, sizeof(der)) != 0) + goto fail; + + strcpy(fn, in_fn); strcat(fn, ".kek"); + size_t kek_len = file_size(fn); + if (kek_len == SIZE_MAX) + goto fail; + uint8_t kek[kek_len]; + if (file_read(fn, kek, &kek_len, sizeof(kek)) != 0) + goto fail; + + hal_error_t err; + if ((err = hal_rpc_pkey_import(client, session, + &key_handle, &key_uuid, + kekek_handle, + der, der_len, + kek, kek_len, + flags)) != HAL_OK) + lose("Error importing private key: %s\n", hal_error_string(err)); + + char name_str[HAL_UUID_TEXT_SIZE]; + if ((err = hal_uuid_format(&key_uuid, name_str, sizeof(name_str))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + printf("New private key name: %s\n", name_str); + + if ((err = hal_rpc_pkey_delete(kekek_handle)) != HAL_OK) + lose("Could not delete key: %s\n", hal_error_string(err)); + } + + return 0; + +fail: + if (kekek_handle.handle != HAL_HANDLE_NONE) + (void)hal_rpc_pkey_delete(kekek_handle); + + return -1; +} + +static int pkey_delete(int argc, char *argv[]) +{ + char usage[] = "Usage: delete [-k keyname]"; + + int opt; + hal_error_t err; + while ((opt = getopt(argc, argv, "-k:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'k': + if (pkey_open(optarg) != 0) + return -1; + if ((err = hal_rpc_pkey_delete(key_handle)) != HAL_OK) + lose("Could not delete key: %s\n", hal_error_string(err)); + key_handle.handle = HAL_HANDLE_NONE; + break; + default: + puts(usage); + return -1; + } + } +done: + + if (key_handle.handle != HAL_HANDLE_NONE) { + if ((err = hal_rpc_pkey_delete(key_handle)) != HAL_OK) + lose("Could not delete key: %s\n", hal_error_string(err)); + key_handle.handle = HAL_HANDLE_NONE; + } + + return 0; + +fail: + return -1; +} + +int main(int argc, char *argv[]) +{ + char usage[] = "Usage: %s [-i] [-p pin] generate|list|sign|verify|export|import|delete\n"; + + if (argc == 1) { + printf(usage, argv[0]); + return -1; + } + + do { + int opt; + while ((opt = getopt(argc, argv, "-ip:")) != -1) { + switch (opt) { + case 1: + /* found the next command */ + --optind; + goto done; + case 'i': + info = 1; + break; + case 'p': + pin = optarg; + break; + default: + printf(usage, argv[0]); + goto fail; + } + } + done: + + if (pkey_login() != 0) + goto fail; + + if (optind < argc) { + optarg = argv[optind++]; + if (strcmp(optarg, "generate") == 0) { + if (pkey_generate(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "list") == 0) { + if (pkey_list(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "sign") == 0) { + if (pkey_sign(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "verify") == 0) { + if (pkey_verify(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "export") == 0) { + if (pkey_export(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "import") == 0) { + if (pkey_import(argc, argv) != 0) + goto fail; + } + else if (strcmp(optarg, "delete") == 0) { + if (pkey_delete(argc, argv) != 0) + goto fail; + } + else { + printf("unknown command '%s'\n", optarg); + printf(usage, argv[0]); + goto fail; + } + } + } while (optind < argc); + + return pkey_logout(); + +fail: + (void)pkey_logout(); + return -1; +} @@ -71,14 +71,18 @@ hal_error_t hal_uuid_gen(hal_uuid_t *uuid) hal_error_t hal_uuid_parse(hal_uuid_t *uuid, const char * const string) { static const char fmt[] - = "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx"; + = "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x"; if (uuid == NULL || string == NULL || sscanf(string, fmt, - uuid->uuid + 0, uuid->uuid + 1, uuid->uuid + 2, uuid->uuid + 3, - uuid->uuid + 4, uuid->uuid + 5, uuid->uuid + 6, uuid->uuid + 7, - uuid->uuid + 8, uuid->uuid + 9, uuid->uuid + 10, uuid->uuid + 11, - uuid->uuid + 12, uuid->uuid + 13, uuid->uuid + 14, uuid->uuid + 15) != 16) + (unsigned *)(uuid->uuid + 0), (unsigned *)(uuid->uuid + 1), + (unsigned *)(uuid->uuid + 2), (unsigned *)(uuid->uuid + 3), + (unsigned *)(uuid->uuid + 4), (unsigned *)(uuid->uuid + 5), + (unsigned *)(uuid->uuid + 6), (unsigned *)(uuid->uuid + 7), + (unsigned *)(uuid->uuid + 8), (unsigned *)(uuid->uuid + 9), + (unsigned *)(uuid->uuid + 10), (unsigned *)(uuid->uuid + 11), + (unsigned *)(uuid->uuid + 12), (unsigned *)(uuid->uuid + 13), + (unsigned *)(uuid->uuid + 14), (unsigned *)(uuid->uuid + 15)) != 16) return HAL_ERROR_BAD_ARGUMENTS; return HAL_OK; @@ -87,16 +91,20 @@ hal_error_t hal_uuid_parse(hal_uuid_t *uuid, const char * const string) hal_error_t hal_uuid_format(const hal_uuid_t * const uuid, char *buffer, const size_t buffer_len) { static const char fmt[] - = "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"; + = "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"; if (uuid == NULL || buffer == NULL || buffer_len < HAL_UUID_TEXT_SIZE) return HAL_ERROR_BAD_ARGUMENTS; if (snprintf(buffer, buffer_len, fmt, - uuid->uuid[ 0], uuid->uuid[ 1], uuid->uuid[ 2], uuid->uuid[ 3], - uuid->uuid[ 4], uuid->uuid[ 5], uuid->uuid[ 6], uuid->uuid[ 7], - uuid->uuid[ 8], uuid->uuid[ 9], uuid->uuid[10], uuid->uuid[11], - uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]) != HAL_UUID_TEXT_SIZE - 1) + (unsigned)uuid->uuid[ 0], (unsigned)uuid->uuid[ 1], + (unsigned)uuid->uuid[ 2], (unsigned)uuid->uuid[ 3], + (unsigned)uuid->uuid[ 4], (unsigned)uuid->uuid[ 5], + (unsigned)uuid->uuid[ 6], (unsigned)uuid->uuid[ 7], + (unsigned)uuid->uuid[ 8], (unsigned)uuid->uuid[ 9], + (unsigned)uuid->uuid[10], (unsigned)uuid->uuid[11], + (unsigned)uuid->uuid[12], (unsigned)uuid->uuid[13], + (unsigned)uuid->uuid[14], (unsigned)uuid->uuid[15]) != HAL_UUID_TEXT_SIZE - 1) return HAL_ERROR_RESULT_TOO_LONG; return HAL_OK; @@ -35,7 +35,6 @@ #include <stdio.h> #include <stdint.h> -#include <stddef.h> /* ptrdiff_t */ #include <string.h> /* memcpy, memset */ #include "hal.h" @@ -50,11 +49,10 @@ hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, const uint8_t * const limit, const uint32_t value) { /* arg checks */ - if (outbuf == NULL || *outbuf == NULL || limit == NULL) - return HAL_ERROR_BAD_ARGUMENTS; + hal_assert(outbuf != NULL && *outbuf != NULL && limit != NULL && limit >= *outbuf); /* buffer overflow check */ - if (limit - *outbuf < (ptrdiff_t)sizeof(value)) + if ((size_t)(limit - *outbuf) < sizeof(value)) return HAL_ERROR_XDR_BUFFER_OVERFLOW; **(uint32_t **)outbuf = htonl(value); @@ -66,11 +64,10 @@ hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, const uint8_t * const li hal_error_t hal_xdr_decode_int_peek(const uint8_t ** const inbuf, const uint8_t * const limit, uint32_t *value) { /* arg checks */ - if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL) - return HAL_ERROR_BAD_ARGUMENTS; + hal_assert(inbuf != NULL && *inbuf != NULL && limit != NULL && limit >= *inbuf && value != NULL); /* buffer overflow check */ - if (limit - *inbuf < (ptrdiff_t)sizeof(*value)) + if ((size_t)(limit - *inbuf) < sizeof(*value)) return HAL_ERROR_XDR_BUFFER_OVERFLOW; *value = ntohl(**(uint32_t **)inbuf); @@ -94,15 +91,14 @@ hal_error_t hal_xdr_decode_int(const uint8_t ** const inbuf, const uint8_t * con 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) { - if (len == 0) - return HAL_OK; - /* arg checks */ - if (outbuf == NULL || *outbuf == NULL || limit == NULL || value == NULL) - return HAL_ERROR_BAD_ARGUMENTS; + hal_assert(outbuf != NULL && *outbuf != NULL && limit != NULL && limit >= *outbuf && (value != NULL || len == 0)); /* buffer overflow check */ - if (limit - *outbuf < (ptrdiff_t)((len + 3) & ~3)) + /* We need to explicitly check (len > 0xfffffffc) because padding will + * round it up to 0. + */ + if ((len > 0xfffffffc) || ((size_t)(limit - *outbuf) < ((len + 3) & ~3))) return HAL_ERROR_XDR_BUFFER_OVERFLOW; /* write the data */ @@ -110,11 +106,8 @@ hal_error_t hal_xdr_encode_fixed_opaque(uint8_t ** const outbuf, const uint8_t * *outbuf += len; /* pad if necessary */ - if (len & 3) { - size_t n = 4 - (len & 3); - memset(*outbuf, 0, n); - *outbuf += n; - } + for (size_t i = len; (i & 3) != 0; ++i) + *((*outbuf)++) = 0; return HAL_OK; } @@ -122,11 +115,10 @@ hal_error_t hal_xdr_encode_fixed_opaque(uint8_t ** const outbuf, const uint8_t * 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) { /* arg checks */ - if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL) - return HAL_ERROR_BAD_ARGUMENTS; + hal_assert(inbuf != NULL && *inbuf != NULL && limit != NULL && limit >= *inbuf && value != NULL); /* buffer overflow check */ - if (limit - *inbuf < (ptrdiff_t)len) + if ((size_t)(limit - *inbuf) < len) return HAL_ERROR_XDR_BUFFER_OVERFLOW; /* return a pointer to the data */ @@ -180,8 +172,7 @@ hal_error_t hal_xdr_decode_variable_opaque_ptr(const uint8_t ** const inbuf, con uint32_t xdr_len; /* arg checks */ - if (len == NULL) - return HAL_ERROR_BAD_ARGUMENTS; + hal_assert(len != NULL); /* read length */ if ((err = hal_xdr_decode_int(inbuf, limit, &xdr_len)) == HAL_OK) { @@ -199,16 +190,19 @@ hal_error_t hal_xdr_decode_variable_opaque_ptr(const uint8_t ** const inbuf, con /* 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) +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, const size_t len_max) { hal_error_t err; size_t xdr_len; const uint8_t *p; + /* arg checks */ + hal_assert(value != NULL && len != NULL && len_max != 0); + /* 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) + if (len_max < xdr_len) return HAL_ERROR_XDR_BUFFER_OVERFLOW; /* read the data */ memcpy(value, p, xdr_len); diff --git a/xdr_internal.h b/xdr_internal.h index aa3a1e9..6cdc064 100644 --- a/xdr_internal.h +++ b/xdr_internal.h @@ -68,7 +68,7 @@ hal_error_t hal_xdr_encode_variable_opaque(uint8_t ** const outbuf, 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); + size_t * const len, const size_t len_max); hal_error_t hal_xdr_decode_variable_opaque_ptr(const uint8_t ** const inbuf, const uint8_t * const limit, |