diff options
50 files changed, 8264 insertions, 423 deletions
@@ -8,9 +8,16 @@ config.status tests/test-aes-key-wrap tests/test-bus tests/test-ecdsa +tests/test-ecdsa-*.der tests/test-hash tests/test-pbkdf2 +tests/test-rpc_hash +tests/test-rpc_pkey +tests/test-rpc_server tests/test-rsa +tests/test-rsa-*.der tests/test-trng +tests/test-rpc_get_version +tests/test-rpc_get_random utils/cores utils/eim_peek_poke diff --git a/GNUmakefile b/GNUmakefile index 2a11683..e7b272d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# Copyright (c) 2015, NORDUnet A/S +# Copyright (c) 2015-2016, NORDUnet A/S # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,39 +27,179 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -INC = hal.h +# Number of static hash and HMAC state blocks to allocate. +# Numbers pulled out of a hat, just testing. + +STATIC_HASH_STATE_BLOCKS = 10 +STATIC_HMAC_STATE_BLOCKS = 4 +STATIC_PKEY_STATE_BLOCKS = 6 + +INC = hal.h hal_internal.h LIB = libhal.a -OBJ = ${IO_OBJ} core.o csprng.o hash.o aes_keywrap.o pbkdf2.o \ - modexp.o rsa.o ecdsa.o asn1.o errorstrings.o -IO_OBJ_EIM = hal_io_eim.o novena-eim.o -IO_OBJ_I2C = hal_io_i2c.o +OBJ = errorstrings.o rsa.o ecdsa.o asn1.o ${CORE_OBJ} ${IO_OBJ} ${RPC_OBJ} ${KS_OBJ} +CORE_OBJ := core.o csprng.o hash.o aes_keywrap.o pbkdf2.o modexp.o + +USAGE = "usage: make [IO_BUS=eim|i2c|fmc] [RPC_CLIENT=local|remote|mixed] [RPC_SERVER=yes] [KS=mmap|volatile|flash]" + +# I/O bus to the FPGA +# +# IO_BUS = eim | i2c | fmc +# eim: EIM bus from Novena +# i2c: older I2C bus from Novena +# fmc: FMC bus from dev-bridge board + +IO_BUS ?= eim +ifeq (${IO_BUS},eim) + IO_OBJ = hal_io_eim.o novena-eim.o +else ifeq (${IO_BUS},i2c) + IO_OBJ = hal_io_i2c.o +else ifeq (${IO_BUS},fmc) + IO_OBJ = hal_io_fmc.o +endif + +# If we're building for STM32, position-independent code leads to some +# hard-to-debug function pointer errors. OTOH, if we're building for Linux +# (even on the Novena), we want to make it possible to build a shared library. + +ifneq (${IO_BUS},fmc) + CFLAGS += -fPIC +endif + +# RPC_CLIENT = local | remote | mixed +# local: Build for Novena or dev-bridge, access FPGA cores directly. +# remote: Build for other host, communicate with RPC server. +# mixed: Do hashing locally in software, other functions remotely. +# +# RPC_SERVER = yes +# +# RPC_TRANSPORT = loopback | serial +# loopback: communicate over loopback socket on Novena +# serial: communicate over USB in serial pass-through mode + +RPC_CORE_OBJ = rpc_hash.o rpc_misc.o rpc_pkey.o + +ifdef RPC_SERVER + RPC_SERVER_OBJ = rpc_server.o rpc_api.o ${RPC_CORE_OBJ} + RPC_TRANSPORT ?= serial +endif + +ifdef RPC_CLIENT + RPC_CLIENT_OBJ = rpc_client.o rpc_api.o + ifeq (${RPC_CLIENT},local) + RPC_CLIENT_OBJ += ${RPC_CORE_OBJ} + else + CFLAGS += -DHAL_RSA_USE_MODEXP=0 + RPC_TRANSPORT ?= serial + ifeq (${RPC_CLIENT},mixed) + RPC_CLIENT_OBJ += rpc_hash.o hash.o + endif + ifndef RPC_SERVER + # If we're only building a remote RPC client lib, don't include + # the modules that access the FPGA cores. + CORE_OBJ := + IO_OBJ := + endif + endif +endif -# Default I/O bus is EIM, override this to use I2C instead -IO_OBJ = ${IO_OBJ_EIM} +ifdef RPC_TRANSPORT + RPC_TRANSPORT_OBJ = xdr.o + ifeq (${RPC_TRANSPORT},loopback) + ifdef RPC_SERVER + RPC_TRANSPORT_OBJ += rpc_server_loopback.o + endif + ifdef RPC_CLIENT + RPC_TRANSPORT_OBJ += rpc_client_loopback.o + endif + else ifeq (${RPC_TRANSPORT},serial) + RPC_TRANSPORT_OBJ += slip.o + ifdef RPC_SERVER + RPC_TRANSPORT_OBJ += rpc_server_serial.o + endif + ifdef RPC_CLIENT + RPC_TRANSPORT_OBJ += rpc_client_serial.o + endif + endif +endif + +RPC_OBJ = ${RPC_SERVER_OBJ} ${RPC_CLIENT_OBJ} ${RPC_TRANSPORT_OBJ} + +# RPC client locality, for rpc_client.c. This has to be kept in sync with +# hal_internal.h. Yeah, it's ugly, but the C preprocessor can only +# compare integers, not strings. + +ifeq (${RPC_CLIENT},local) + RPC_CLIENT_FLAG = 0 +else ifeq (${RPC_CLIENT},remote) + RPC_CLIENT_FLAG = 1 +else ifeq (${RPC_CLIENT},mixed) + RPC_CLIENT_FLAG = 2 +endif +ifdef RPC_CLIENT_FLAG +CFLAGS += -DRPC_CLIENT=${RPC_CLIENT_FLAG} +endif + +# The mmap and flash keystore implementations are both server code. +# +# The volatile keystore (conventional memory) is client code, to +# support using the same API for things like PKCS #11 "session" objects. +# +# Default at the moment is mmap, since that should work on the Novena +# and we haven't yet written the flash code for the bridge board. + +KS_OBJ = ks.o +KS ?= mmap +ifeq (${KS},mmap) + KS_OBJ += ks_mmap.o +else ifeq (${KS},volatile) + KS_OBJ += ks_volatile.o +else ifeq (${KS},flash) + KS_OBJ += ks_flash.o +endif TFMDIR := $(abspath ../thirdparty/libtfm) -CFLAGS += -g3 -Wall -fPIC -std=c99 -I${TFMDIR} +CFLAGS += -g3 -Wall -std=c99 -I${TFMDIR} LDFLAGS := -g3 -L${TFMDIR} -ltfm +CFLAGS += -DHAL_STATIC_HASH_STATE_BLOCKS=${STATIC_HASH_STATE_BLOCKS} +CFLAGS += -DHAL_STATIC_HMAC_STATE_BLOCKS=${STATIC_HMAC_STATE_BLOCKS} +CFLAGS += -DHAL_STATIC_PKEY_STATE_BLOCKS=${STATIC_PKEY_STATE_BLOCKS} + all: ${LIB} cd tests; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@ +ifneq (${CORE_OBJ},) cd utils; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@ +endif + +client: + ${MAKE} RPC_CLIENT=remote + +mixed: + ${MAKE} RPC_CLIENT=mixed + +server: + ${MAKE} RPC_SERVER=yes + +loopback: + ${MAKE} RPC_CLIENT=remote RPC_SERVER=yes RPC_TRANSPORT=loopback ${OBJ}: ${INC} ${LIB}: ${OBJ} ${AR} rcs $@ $^ -asn1.o rsa.o ecdsa.o: asn1_internal.h - -ecdsa.o: ecdsa_curves.h +asn1.o rsa.o ecdsa.o: asn1_internal.h +ecdsa.o: ecdsa_curves.h +novena-eim.o hal_io_eim.o: novena-eim.h +slip.o rpc_client_serial.o rpc_server_serial.o: slip_internal.h test: all + export RPC_CLIENT RPC_SERVER cd tests; ${MAKE} -k $@ clean: - rm -f ${OBJ} ${LIB} + rm -f *.o ${LIB} cd tests; ${MAKE} $@ cd utils; ${MAKE} $@ @@ -68,5 +208,5 @@ distclean: clean tags: TAGS -TAGS: *.[ch] tests/*.[ch] +TAGS: *.[ch] tests/*.[ch] utils/*.[ch] etags $^ diff --git a/aes_keywrap.c b/aes_keywrap.c index 9d10ad9..d666624 100644 --- a/aes_keywrap.c +++ b/aes_keywrap.c @@ -48,7 +48,7 @@ #include <assert.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" /* * How long the ciphertext will be for a given plaintext length. @@ -153,6 +153,87 @@ hal_error_t hal_asn1_encode_integer(const fp_int * const bn, } /* + * Encode a public key into an RFC 5280 SubjectPublicKeyInfo. + */ + +hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t alg_oid_len, + const uint8_t * const curve_oid, const size_t curve_oid_len, + const uint8_t * const pubkey, const size_t pubkey_len, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + if (alg_oid == NULL || alg_oid_len == 0 || pubkey_len == 0 || + (der != NULL && pubkey == NULL) || (curve_oid == NULL && curve_oid_len != 0)) + return HAL_ERROR_BAD_ARGUMENTS; + + const uint8_t curve_oid_tag = curve_oid == NULL ? ASN1_NULL : ASN1_OBJECT_IDENTIFIER; + + hal_error_t err; + + size_t hlen, hlen_spki, hlen_algid, hlen_alg, hlen_curve, hlen_bit; + + if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, NULL, &hlen_alg, 0)) != HAL_OK || + (err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, NULL, &hlen_curve, 0)) != HAL_OK || + (err = hal_asn1_encode_header(ASN1_BIT_STRING, 1 + pubkey_len, NULL, &hlen_bit, 0)) != HAL_OK) + return err; + + const size_t algid_len = hlen_alg + alg_oid_len + hlen_curve + curve_oid_len; + + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, NULL, &hlen_algid, 0)) != HAL_OK) + return err; + + const size_t vlen = hlen_algid + hlen_alg + alg_oid_len + hlen_curve + curve_oid_len + hlen_bit + 1 + pubkey_len; + + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, NULL, &hlen_spki, 0)) != HAL_OK) + return err; + + /* + * Handle pubkey early, in case it was staged into our output buffer. + */ + if (der != NULL && hlen_spki + vlen <= der_max) + memmove(der + hlen_spki + vlen - pubkey_len, pubkey, pubkey_len); + + err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max); + + if (der_len != NULL) + *der_len = hlen + vlen; + + if (der == NULL || err != HAL_OK) + return err; + + uint8_t *d = der + hlen; + memset(d, 0, vlen - pubkey_len); + + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, algid_len, d, &hlen, der + der_max - d)) != HAL_OK) + return err; + d += hlen; + + if ((err = hal_asn1_encode_header(ASN1_OBJECT_IDENTIFIER, alg_oid_len, d, &hlen, der + der_max - d)) != HAL_OK) + return err; + d += hlen; + memcpy(d, alg_oid, alg_oid_len); + d += alg_oid_len; + + if ((err = hal_asn1_encode_header(curve_oid_tag, curve_oid_len, d, &hlen, der + der_max - d)) != HAL_OK) + return err; + d += hlen; + if (curve_oid != NULL) + memcpy(d, curve_oid, curve_oid_len); + d += curve_oid_len; + + if ((err = hal_asn1_encode_header(ASN1_BIT_STRING, 1 + pubkey_len, d, &hlen, der + der_max - d)) != HAL_OK) + return err; + d += hlen; + *d++ = 0x00; + + d += pubkey_len; /* pubkey handled early, above. */ + + assert(d == der + hlen_spki + vlen); + assert(d <= der + der_max); + + return HAL_OK; +} + +/* * Parse tag and length of an ASN.1 object. Tag must match value * specified by the caller. On success, sets hlen and vlen to lengths * of header and value, respectively. @@ -219,6 +300,91 @@ hal_error_t hal_asn1_decode_integer(fp_int *bn, } /* + * Decode a public key from an RFC 5280 SubjectPublicKeyInfo. + */ + +hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len, + const uint8_t **curve_oid, size_t *curve_oid_len, + const uint8_t **pubkey, size_t *pubkey_len, + const uint8_t *const der, const size_t der_len) +{ + if (alg_oid == NULL || alg_oid_len == NULL || curve_oid == NULL || curve_oid_len == NULL || + pubkey == NULL || pubkey_len == NULL || der == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + const uint8_t * const der_end = der + der_len; + const uint8_t *d = der; + + size_t hlen, vlen; + hal_error_t err; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, d, der_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + + const uint8_t * const algid_end = d + vlen; + + if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + if (vlen > algid_end - d) + return HAL_ERROR_ASN1_PARSE_FAILED; + *alg_oid = d; + *alg_oid_len = vlen; + d += vlen; + + *curve_oid = NULL; + *curve_oid_len = 0; + + if (d < algid_end) { + switch (*d) { + + case ASN1_OBJECT_IDENTIFIER: + if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, algid_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + if (vlen > algid_end - d) + return HAL_ERROR_ASN1_PARSE_FAILED; + *curve_oid = d; + *curve_oid_len = vlen; + d += vlen; + break; + + case ASN1_NULL: + if ((err = hal_asn1_decode_header(ASN1_NULL, d, algid_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + if (vlen == 0) + break; + + default: + return HAL_ERROR_ASN1_PARSE_FAILED; + } + } + + if (d != algid_end) + return HAL_ERROR_ASN1_PARSE_FAILED; + + if ((err = hal_asn1_decode_header(ASN1_BIT_STRING, d, der_end - d, &hlen, &vlen)) != HAL_OK) + return err; + d += hlen; + if (vlen >= algid_end - d || vlen == 0 || *d != 0x00) + return HAL_ERROR_ASN1_PARSE_FAILED; + *pubkey = ++d; + *pubkey_len = --vlen; + d += vlen; + + if (d != der_end) + return HAL_ERROR_ASN1_PARSE_FAILED; + + return HAL_OK; +} + +/* * Local variables: * indent-tabs-mode: nil * End: diff --git a/asn1_internal.h b/asn1_internal.h index bfe9372..0b08b84 100644 --- a/asn1_internal.h +++ b/asn1_internal.h @@ -1,9 +1,12 @@ /* - * asn1.h - * ------ - * Library internal header file for ASN.1 routines. + * asn1_internal.h + * --------------- + * Library internal header file for ASN.1 routines. These functions + * are not part of the public libhal API. * - * These functions are not part of the public libhal API. + * The only reason for not collapsing this header file into + * hal_internal.h is to maintain some isolation between the few + * modules which use libtfm and the rest of the library. * * More than 20 years after it was written, the best simple * introduction to ASN.1 is still Burt Kalski's "A Layman's Guide to a @@ -40,8 +43,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _HAL_ASN1_H_ -#define _HAL_ASN1_H_ +#ifndef _HAL_ASN1_INTERNAL_H_ +#define _HAL_ASN1_INTERNAL_H_ #include <stdint.h> @@ -100,7 +103,17 @@ extern hal_error_t hal_asn1_encode_integer(const fp_int * const bn, extern hal_error_t hal_asn1_decode_integer(fp_int *bn, const uint8_t * const der, size_t *der_len, const size_t der_max); -#endif /* _HAL_ASN1_H_ */ +extern hal_error_t hal_asn1_encode_spki(const uint8_t * const alg_oid, const size_t alg_oid_len, + const uint8_t * const curve_oid, const size_t curve_oid_len, + const uint8_t * const pubkey, const size_t pubkey_len, + uint8_t *der, size_t *der_len, const size_t der_max); + +extern hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len, + const uint8_t **curve_oid, size_t *curve_oid_len, + const uint8_t **pubkey, size_t *pubkey_len, + const uint8_t *const der, const size_t der_len); + +#endif /* _HAL_ASN1_INTERNAL_H_ */ /* * Local variables: @@ -39,7 +39,7 @@ #include <string.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" /* * Each Cryptech core has a set of 4-byte registers, which are accessed @@ -37,7 +37,7 @@ #include <stdint.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" #ifndef WAIT_FOR_CSPRNG_VALID #define WAIT_FOR_CSPRNG_VALID 1 @@ -83,6 +83,10 @@ #define HAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM 0 #endif +#ifdef RPC_CLIENT +#define hal_get_random(core, buffer, length) hal_rpc_get_random(buffer, length) +#endif + /* * Whether we want debug output. */ @@ -150,8 +154,8 @@ typedef struct { } ec_point_t; struct hal_ecdsa_key { - hal_ecdsa_key_type_t type; /* Public or private is */ - hal_ecdsa_curve_t curve; /* Curve descriptor */ + hal_key_type_t type; /* Public or private */ + hal_curve_name_t curve; /* Curve descriptor */ ec_point_t Q[1]; /* Public key */ fp_int d[1]; /* Private key */ }; @@ -181,7 +185,7 @@ const size_t hal_ecdsa_key_t_size = sizeof(struct hal_ecdsa_key); * first time anything asks for any of them. */ -static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve) +static const ecdsa_curve_t * const get_curve(const hal_curve_name_t curve) { static ecdsa_curve_t curve_p256, curve_p384, curve_p521; static int initialized = 0; @@ -230,13 +234,29 @@ static const ecdsa_curve_t * const get_curve(const hal_ecdsa_curve_t curve) } switch (curve) { - case HAL_ECDSA_CURVE_P256: return &curve_p256; - case HAL_ECDSA_CURVE_P384: return &curve_p384; - case HAL_ECDSA_CURVE_P521: return &curve_p521; - default: return NULL; + case HAL_CURVE_P256: return &curve_p256; + case HAL_CURVE_P384: return &curve_p384; + case HAL_CURVE_P521: return &curve_p521; + default: return NULL; } } +static inline const ecdsa_curve_t * oid_to_curve(hal_curve_name_t *curve_name, + const uint8_t * const oid, + const size_t oid_len) +{ + assert(curve_name != NULL && oid != NULL); + + const ecdsa_curve_t *curve = NULL; + *curve_name = HAL_CURVE_NONE; + + while ((curve = get_curve(++*curve_name)) != NULL) + if (oid_len == curve->oid_len && memcmp(oid, curve->oid, oid_len) == 0) + return curve; + + return NULL; +} + /* * Finite field operations (hence "ff_"). These are basically just * the usual bignum operations, constrained by the field modulus. @@ -831,7 +851,7 @@ static int point_is_on_curve(const ec_point_t * const P, hal_error_t hal_ecdsa_key_gen(const hal_core_t *core, hal_ecdsa_key_t **key_, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve_) + const hal_curve_name_t curve_) { const ecdsa_curve_t * const curve = get_curve(curve_); hal_ecdsa_key_t *key = keybuf; @@ -842,7 +862,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core, memset(keybuf, 0, keybuf_len); - key->type = HAL_ECDSA_PRIVATE; + key->type = HAL_KEY_TYPE_EC_PRIVATE; key->curve = curve_; if ((err = point_pick_random(curve, key->d, key->Q)) != HAL_OK) @@ -859,7 +879,7 @@ hal_error_t hal_ecdsa_key_gen(const hal_core_t *core, */ hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key, - hal_ecdsa_key_type_t *key_type) + hal_key_type_t *key_type) { if (key == NULL || key_type == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -873,7 +893,7 @@ hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key, */ hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key, - hal_ecdsa_curve_t *curve) + hal_curve_name_t *curve) { if (key == NULL || curve == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -929,7 +949,7 @@ void hal_ecdsa_key_clear(hal_ecdsa_key_t *key) hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve_, + const hal_curve_name_t curve_, const uint8_t * const x, const size_t x_len, const uint8_t * const y, const size_t y_len) { @@ -941,7 +961,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_, memset(keybuf, 0, keybuf_len); - key->type = HAL_ECDSA_PUBLIC; + key->type = HAL_KEY_TYPE_EC_PUBLIC; key->curve = curve_; fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(x), x_len); @@ -966,7 +986,7 @@ hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key_, hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve_, + const hal_curve_name_t curve_, const uint8_t * const x, const size_t x_len, const uint8_t * const y, const size_t y_len, const uint8_t * const d, const size_t d_len) @@ -980,7 +1000,7 @@ hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key_, if ((err = hal_ecdsa_key_load_public(key_, keybuf, keybuf_len, curve_, x, x_len, y, y_len)) != HAL_OK) return err; - key->type = HAL_ECDSA_PRIVATE; + key->type = HAL_KEY_TYPE_EC_PRIVATE; fp_read_unsigned_bin(key->d, unconst_uint8_t(d), d_len); return HAL_OK; } @@ -1052,7 +1072,7 @@ size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key) hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_, void *keybuf, const size_t keybuf_len, const uint8_t * const der, const size_t der_len, - const hal_ecdsa_curve_t curve) + const hal_curve_name_t curve) { hal_ecdsa_key_t *key = keybuf; @@ -1060,7 +1080,7 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_, return HAL_ERROR_BAD_ARGUMENTS; memset(keybuf, 0, keybuf_len); - key->type = HAL_ECDSA_PUBLIC; + key->type = HAL_KEY_TYPE_EC_PUBLIC; key->curve = curve; size_t hlen, vlen; @@ -1103,10 +1123,10 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_, * probably be using an ASN.1 compiler like asn1c instead. */ -hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key, - uint8_t *der, size_t *der_len, const size_t der_max) +hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max) { - if (key == NULL || key->type != HAL_ECDSA_PRIVATE) + if (key == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE) return HAL_ERROR_BAD_ARGUMENTS; const ecdsa_curve_t * const curve = get_curve(key->curve); @@ -1192,10 +1212,10 @@ hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key, * take if encoded as DER. */ -size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key) +size_t hal_ecdsa_private_key_to_der_len(const hal_ecdsa_key_t * const key) { size_t len; - return hal_ecdsa_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; + return hal_ecdsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; } /* @@ -1205,9 +1225,9 @@ size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key) * probably be using an ASN.1 compiler like asn1c instead. */ -hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_, - void *keybuf, const size_t keybuf_len, - const uint8_t * const der, const size_t der_len) +hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_, + void *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len) { hal_ecdsa_key_t *key = keybuf; @@ -1215,7 +1235,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_, return HAL_ERROR_BAD_ARGUMENTS; memset(keybuf, 0, keybuf_len); - key->type = HAL_ECDSA_PRIVATE; + key->type = HAL_KEY_TYPE_EC_PRIVATE; size_t hlen, vlen; hal_error_t err; @@ -1248,10 +1268,7 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_, if ((err = hal_asn1_decode_header(ASN1_OBJECT_IDENTIFIER, d, vlen, &hlen, &vlen)) != HAL_OK) return err; d += hlen; - for (key->curve = (hal_ecdsa_curve_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++) - if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0) - break; - if (curve == NULL) + if ((curve = oid_to_curve(&key->curve, d, vlen)) == NULL) lose(HAL_ERROR_ASN1_PARSE_FAILED); d += vlen; @@ -1284,6 +1301,104 @@ hal_error_t hal_ecdsa_key_from_der(hal_ecdsa_key_t **key_, } /* + * Write public key in SubjectPublicKeyInfo format, see RFCS 5280 and 5480. + */ + +static const uint8_t oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; + +hal_error_t hal_ecdsa_public_key_to_der(const hal_ecdsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + if (key == NULL || (key->type != HAL_KEY_TYPE_EC_PRIVATE && + key->type != HAL_KEY_TYPE_EC_PUBLIC)) + return HAL_ERROR_BAD_ARGUMENTS; + + const ecdsa_curve_t * const curve = get_curve(key->curve); + if (curve == NULL) + return HAL_ERROR_IMPOSSIBLE; + + const size_t q_len = fp_unsigned_bin_size(unconst_fp_int(curve->q)); + const size_t Qx_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->x)); + const size_t Qy_len = fp_unsigned_bin_size(unconst_fp_int(key->Q->y)); + const size_t ecpoint_len = q_len * 2 + 1; + assert(q_len >= Qx_len && q_len >= Qy_len); + + if (der != NULL && ecpoint_len < der_max) { + memset(der, 0, ecpoint_len); + + uint8_t *d = der; + *d++ = 0x04; /* Uncompressed */ + + fp_to_unsigned_bin(unconst_fp_int(key->Q->x), d + q_len - Qx_len); + d += q_len; + + fp_to_unsigned_bin(unconst_fp_int(key->Q->y), d + q_len - Qy_len); + d += q_len; + + assert(d < der + der_max); + } + + return hal_asn1_encode_spki(oid_ecPublicKey, sizeof(oid_ecPublicKey), + curve->oid, curve->oid_len, + der, ecpoint_len, + der, der_len, der_max); +} + +/* + * Convenience wrapper to return how many bytes a public key would + * take if encoded as DER. + */ + +size_t hal_ecdsa_public_key_to_der_len(const hal_ecdsa_key_t * const key) +{ + size_t len; + return hal_ecdsa_public_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; +} + +/* + * Read public key in SubjectPublicKeyInfo format, see RFCS 5280 and 5480. + */ + +hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_key_t **key_, + void *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len) +{ + hal_ecdsa_key_t *key = keybuf; + + if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key)) + return HAL_ERROR_BAD_ARGUMENTS; + + memset(keybuf, 0, keybuf_len); + key->type = HAL_KEY_TYPE_EC_PUBLIC; + + const uint8_t *alg_oid = NULL, *curve_oid = NULL, *pubkey = NULL; + size_t alg_oid_len, curve_oid_len, pubkey_len; + const ecdsa_curve_t *curve; + hal_error_t err; + + if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, &pubkey, &pubkey_len, + der, der_len)) != HAL_OK) + return err; + + if (alg_oid == NULL || curve_oid == NULL || pubkey == NULL || + alg_oid_len != sizeof(oid_ecPublicKey) || memcmp(alg_oid, oid_ecPublicKey, alg_oid_len) != 0 || + (curve = oid_to_curve(&key->curve, curve_oid, curve_oid_len)) == NULL || + pubkey_len < 3 || (pubkey_len & 1) == 0 || pubkey[0] != 0x04 || + pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(curve->q))) + return HAL_ERROR_ASN1_PARSE_FAILED; + + const uint8_t * const Qx = pubkey + 1; + const uint8_t * const Qy = Qx + pubkey_len / 2; + + fp_read_unsigned_bin(key->Q->x, unconst_uint8_t(Qx), pubkey_len / 2); + fp_read_unsigned_bin(key->Q->y, unconst_uint8_t(Qy), pubkey_len / 2); + fp_set(key->Q->z, 1); + + *key_ = key; + return HAL_OK; +} + +/* * Encode a signature in PKCS #11 format: an octet string consisting * of concatenated values for r and s, each padded (if necessary) out * to the byte length of the order of the base point. @@ -1345,89 +1460,15 @@ static hal_error_t decode_signature_pkcs11(const ecdsa_curve_t * const curve, } /* - * Encode a signature in ASN.1 format SEQUENCE { INTEGER r, INTEGER s }. - */ - -static hal_error_t encode_signature_asn1(const ecdsa_curve_t * const curve, - const fp_int * const r, const fp_int * const s, - uint8_t *signature, size_t *signature_len, const size_t signature_max) -{ - assert(curve != NULL && r != NULL && s != NULL); - - size_t hlen, r_len, s_len; - hal_error_t err; - - if ((err = hal_asn1_encode_integer(r, NULL, &r_len, 0)) != HAL_OK || - (err = hal_asn1_encode_integer(s, NULL, &s_len, 0)) != HAL_OK) - return err; - - const size_t vlen = r_len + s_len; - - err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, signature, &hlen, signature_max); - - if (signature_len != NULL) - *signature_len = hlen + vlen; - - if (signature == NULL || err != HAL_OK) - return err; - - uint8_t * const r_out = signature + hlen; - uint8_t * const s_out = r_out + r_len; - - if ((err = hal_asn1_encode_integer(r, r_out, NULL, signature_max - (r_out - signature))) != HAL_OK || - (err = hal_asn1_encode_integer(s, s_out, NULL, signature_max - (s_out - signature))) != HAL_OK) - return err; - - return HAL_OK; -} - -/* - * Decode a signature from ASN.1 format SEQUENCE { INTEGER r, INTEGER s }. - */ - -static hal_error_t decode_signature_asn1(const ecdsa_curve_t * const curve, - fp_int *r, fp_int *s, - const uint8_t * const signature, const size_t signature_len) -{ - assert(curve != NULL && r != NULL && s != NULL); - - if (signature == NULL) - return HAL_ERROR_BAD_ARGUMENTS; - - size_t len1, len2; - hal_error_t err; - - if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, signature, signature_len, &len1, &len2)) != HAL_OK) - return err; - - const uint8_t * der = signature + len1; - const uint8_t * const der_end = der + len2; - - if ((err = hal_asn1_decode_integer(r, der, &len1, der_end - der)) != HAL_OK) - return err; - der += len1; - - if ((err = hal_asn1_decode_integer(s, der, &len1, der_end - der)) != HAL_OK) - return err; - der += len1; - - if (der != der_end) - return HAL_ERROR_ASN1_PARSE_FAILED; - - return HAL_OK; -} - -/* * Sign a caller-supplied hash. */ hal_error_t hal_ecdsa_sign(const hal_core_t *core, const hal_ecdsa_key_t * const key, const uint8_t * const hash, const size_t hash_len, - uint8_t *signature, size_t *signature_len, const size_t signature_max, - const hal_ecdsa_signature_format_t signature_format) + uint8_t *signature, size_t *signature_len, const size_t signature_max) { - if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_ECDSA_PRIVATE) + if (key == NULL || hash == NULL || signature == NULL || signature_len == NULL || key->type != HAL_KEY_TYPE_EC_PRIVATE) return HAL_ERROR_BAD_ARGUMENTS; const ecdsa_curve_t * const curve = get_curve(key->curve); @@ -1487,21 +1528,8 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core, * Encode the signature, then we're done. */ - switch (signature_format) { - - case HAL_ECDSA_SIGNATURE_FORMAT_ASN1: - if ((err = encode_signature_asn1(curve, r, s, signature, signature_len, signature_max)) != HAL_OK) - goto fail; - break; - - case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11: - if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK) - goto fail; - break; - - default: - lose(HAL_ERROR_BAD_ARGUMENTS); - } + if ((err = encode_signature_pkcs11(curve, r, s, signature, signature_len, signature_max)) != HAL_OK) + goto fail; err = HAL_OK; @@ -1518,8 +1546,7 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core, hal_error_t hal_ecdsa_verify(const hal_core_t *core, const hal_ecdsa_key_t * const key, const uint8_t * const hash, const size_t hash_len, - const uint8_t * const signature, const size_t signature_len, - const hal_ecdsa_signature_format_t signature_format) + const uint8_t * const signature, const size_t signature_len) { assert(key != NULL && hash != NULL && signature != NULL); @@ -1551,21 +1578,8 @@ hal_error_t hal_ecdsa_verify(const hal_core_t *core, * Start by decoding the signature. */ - switch (signature_format) { - - case HAL_ECDSA_SIGNATURE_FORMAT_ASN1: - if ((err = decode_signature_asn1(curve, r, s, signature, signature_len)) != HAL_OK) - return err; - break; - - case HAL_ECDSA_SIGNATURE_FORMAT_PKCS11: - if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK) - return err; - break; - - default: - return HAL_ERROR_BAD_ARGUMENTS; - } + if ((err = decode_signature_pkcs11(curve, r, s, signature, signature_len)) != HAL_OK) + return err; /* * Check that r and s are in the allowed range, read the hash, then @@ -4,7 +4,7 @@ * Memory map, access functions, and HAL for Cryptech cores. * * Authors: Joachim Strombergson, Paul Selkirk, Rob Austein - * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -36,15 +36,19 @@ #ifndef _HAL_H_ #define _HAL_H_ +#include <stdint.h> +#include <sys/types.h> +#include <stdlib.h> + /* * A handy macro from cryptlib. */ #ifndef bitsToBytes -#define bitsToBytes(x) (x / 8) +#define bitsToBytes(x) ((x) / 8) #endif /* - * Current name and version values. + * Current name and version values for crypto cores. * * Should these even be here? Dunno. * Should the versions be here even if the names should be? @@ -114,6 +118,17 @@ DEFINE_HAL_ERROR(HAL_ERROR_KEY_NOT_ON_CURVE, "EC key is not on its purported curve") \ DEFINE_HAL_ERROR(HAL_ERROR_INVALID_SIGNATURE, "Invalid signature") \ DEFINE_HAL_ERROR(HAL_ERROR_CORE_NOT_FOUND, "Requested core not found") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_ACCESS, "Could not access keystore") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEY_NOT_FOUND, "Key not found") \ + DEFINE_HAL_ERROR(HAL_ERROR_KEY_NAME_IN_USE, "Key name in use") \ + DEFINE_HAL_ERROR(HAL_ERROR_NO_KEY_SLOTS_AVAILABLE, "No key slots available") \ + DEFINE_HAL_ERROR(HAL_ERROR_PIN_INCORRECT, "PIN incorrect") \ + DEFINE_HAL_ERROR(HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE, "No client slots available") \ + DEFINE_HAL_ERROR(HAL_ERROR_FORBIDDEN, "Forbidden") \ + DEFINE_HAL_ERROR(HAL_ERROR_XDR_BUFFER_OVERFLOW, "XDR buffer overflow") \ + DEFINE_HAL_ERROR(HAL_ERROR_RPC_TRANSPORT, "RPC transport error") \ + DEFINE_HAL_ERROR(HAL_ERROR_RPC_PACKET_OVERFLOW, "RPC packet overflow") \ + DEFINE_HAL_ERROR(HAL_ERROR_RPC_BAD_FUNCTION, "Bad RPC function number") \ END_OF_HAL_ERROR_LIST /* Marker to forestall silly line continuation errors */ @@ -125,24 +140,21 @@ typedef enum { HAL_ERROR_LIST N_HAL_ERRORS } hal_error_t; #undef DEFINE_HAL_ERROR /* - * Public functions. + * Error translation. */ -#include <stdint.h> -#include <sys/types.h> +extern const char *hal_error_string(const hal_error_t err); /* - * Typedef to isolate code from our current choice of representation - * for a Cryptech bus address. + * Very low level public API for working directly with crypto cores. */ -typedef off_t hal_addr_t; - /* - * Error translation. + * Typedef to isolate code from our current choice of representation + * for a Cryptech bus address. */ -extern const char *hal_error_string(const hal_error_t err); +typedef off_t hal_addr_t; /* * Opaque structure representing a core. @@ -186,7 +198,7 @@ extern hal_addr_t hal_core_base(const hal_core_t *core); extern const hal_core_t * hal_core_iterate(const hal_core_t *core); /* - * Higher level public API. + * Slightly higher level public API, still working directly with cores. */ /* @@ -200,13 +212,6 @@ extern hal_error_t hal_get_random(const hal_core_t *core, void *buffer, const si */ /* - * Longest hash block and digest we support at the moment. - */ - -#define HAL_MAX_HASH_BLOCK_LENGTH SHA512_BLOCK_LEN -#define HAL_MAX_HASH_DIGEST_LENGTH SHA512_DIGEST_LEN - -/* * Opaque driver structure for digest algorithms. */ @@ -221,7 +226,18 @@ typedef struct hal_hash_driver hal_hash_driver_t; * problem. */ +typedef enum { + hal_digest_algorithm_none, + hal_digest_algorithm_sha1, + hal_digest_algorithm_sha256, + hal_digest_algorithm_sha512_224, + hal_digest_algorithm_sha512_256, + hal_digest_algorithm_sha384, + hal_digest_algorithm_sha512 +} hal_digest_algorithm_t; + typedef struct { + hal_digest_algorithm_t digest_algorithm; size_t block_length; size_t digest_length; size_t hash_state_length; @@ -284,6 +300,10 @@ extern void hal_hash_cleanup(hal_hash_state_t **state); extern void hal_hmac_cleanup(hal_hmac_state_t **state); +extern const hal_hash_descriptor_t *hal_hash_get_descriptor(const hal_hash_state_t * const state); + +extern const hal_hash_descriptor_t *hal_hmac_get_descriptor(const hal_hmac_state_t * const state); + /* * AES key wrap functions. */ @@ -326,10 +346,27 @@ extern hal_error_t hal_modexp(const hal_core_t *core, /* - * RSA. + * Key types and curves, used in various places. */ -typedef enum { HAL_RSA_PRIVATE, HAL_RSA_PUBLIC } hal_rsa_key_type_t; +typedef enum { + HAL_KEY_TYPE_NONE, + HAL_KEY_TYPE_RSA_PRIVATE, + HAL_KEY_TYPE_RSA_PUBLIC, + HAL_KEY_TYPE_EC_PRIVATE, + HAL_KEY_TYPE_EC_PUBLIC +} hal_key_type_t; + +typedef enum { + HAL_CURVE_NONE, + HAL_CURVE_P256, + HAL_CURVE_P384, + HAL_CURVE_P521 +} hal_curve_name_t; + +/* + * RSA. + */ typedef struct hal_rsa_key hal_rsa_key_t; @@ -356,7 +393,7 @@ extern hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key, const uint8_t * const e, const size_t e_len); extern hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key, - hal_rsa_key_type_t *key_type); + hal_key_type_t *key_type); extern hal_error_t hal_rsa_key_get_modulus(const hal_rsa_key_t * const key, uint8_t *modulus, @@ -386,24 +423,27 @@ extern hal_error_t hal_rsa_key_gen(const hal_core_t *core, const unsigned key_length, const uint8_t * const public_exponent, const size_t public_exponent_len); -extern hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key, - uint8_t *der, size_t *der_len, const size_t der_max); +extern hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max); -extern size_t hal_rsa_key_to_der_len(const hal_rsa_key_t * const key); +extern size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key); -extern hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key, - void *keybuf, const size_t keybuf_len, - const uint8_t * const der, const size_t der_len); +extern hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key, + void *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len); -/* - * ECDSA. - */ +extern hal_error_t hal_rsa_public_key_to_der(const hal_rsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max); -typedef enum { HAL_ECDSA_PRIVATE, HAL_ECDSA_PUBLIC } hal_ecdsa_key_type_t; +extern size_t hal_rsa_public_key_to_der_len(const hal_rsa_key_t * const key); -typedef enum { HAL_ECDSA_CURVE_P256, HAL_ECDSA_CURVE_P384, HAL_ECDSA_CURVE_P521 } hal_ecdsa_curve_t; +extern hal_error_t hal_rsa_public_key_from_der(hal_rsa_key_t **key, + void *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len); -typedef enum { HAL_ECDSA_SIGNATURE_FORMAT_ASN1, HAL_ECDSA_SIGNATURE_FORMAT_PKCS11 } hal_ecdsa_signature_format_t; +/* + * ECDSA. + */ typedef struct hal_ecdsa_key hal_ecdsa_key_t; @@ -413,22 +453,22 @@ extern void hal_ecdsa_set_debug(const int onoff); extern hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve, + const hal_curve_name_t curve, const uint8_t * const x, const size_t x_len, const uint8_t * const y, const size_t y_len, const uint8_t * const d, const size_t d_len); extern hal_error_t hal_ecdsa_key_load_public(hal_ecdsa_key_t **key, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve, + const hal_curve_name_t curve, const uint8_t * const x, const size_t x_len, const uint8_t * const y, const size_t y_len); extern hal_error_t hal_ecdsa_key_get_type(const hal_ecdsa_key_t * const key, - hal_ecdsa_key_type_t *key_type); + hal_key_type_t *key_type); extern hal_error_t hal_ecdsa_key_get_curve(const hal_ecdsa_key_t * const key, - hal_ecdsa_curve_t *curve); + hal_curve_name_t *curve); extern hal_error_t hal_ecdsa_key_get_public(const hal_ecdsa_key_t * const key, uint8_t *x, size_t *x_len, const size_t x_max, @@ -439,16 +479,25 @@ extern void hal_ecdsa_key_clear(hal_ecdsa_key_t *key); extern hal_error_t hal_ecdsa_key_gen(const hal_core_t *core, hal_ecdsa_key_t **key, void *keybuf, const size_t keybuf_len, - const hal_ecdsa_curve_t curve); + const hal_curve_name_t curve); + +extern hal_error_t hal_ecdsa_private_key_to_der(const hal_ecdsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max); -extern hal_error_t hal_ecdsa_key_to_der(const hal_ecdsa_key_t * const key, - uint8_t *der, size_t *der_len, const size_t der_max); +extern size_t hal_ecdsa_private_key_to_der_len(const hal_ecdsa_key_t * const key); -extern size_t hal_ecdsa_key_to_der_len(const hal_ecdsa_key_t * const key); +extern hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_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_ecdsa_key_from_der(hal_ecdsa_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_ecdsa_public_key_to_der(const hal_ecdsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max); + +extern size_t hal_ecdsa_public_key_to_der_len(const hal_ecdsa_key_t * const key); + +extern hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_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_ecdsa_key_to_ecpoint(const hal_ecdsa_key_t * const key, uint8_t *der, size_t *der_len, const size_t der_max); @@ -458,19 +507,224 @@ extern size_t hal_ecdsa_key_to_ecpoint_len(const hal_ecdsa_key_t * const key); extern hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key, void *keybuf, const size_t keybuf_len, const uint8_t * const der, const size_t der_len, - const hal_ecdsa_curve_t curve); + const hal_curve_name_t curve); extern hal_error_t hal_ecdsa_sign(const hal_core_t *core, const hal_ecdsa_key_t * const key, const uint8_t * const hash, const size_t hash_len, - uint8_t *signature, size_t *signature_len, const size_t signature_max, - const hal_ecdsa_signature_format_t signature_format); + uint8_t *signature, size_t *signature_len, const size_t signature_max); extern hal_error_t hal_ecdsa_verify(const hal_core_t *core, const hal_ecdsa_key_t * const key, const uint8_t * const hash, const size_t hash_len, - const uint8_t * const signature, const size_t signature_len, - const hal_ecdsa_signature_format_t signature_format); + const uint8_t * const signature, const size_t signature_len); + +/* + * Higher level RPC-based mechanism for working with HSM at arm's + * length, using handles instead of direct access to the cores. + * + * Session handles are pretty much as in PKCS #11: from our viewpoint, + * a session is a lock-step stream of operations, so while operations + * from different sessions can interleave, operations within a single + * session cannot. + * + * Client handles are a small extension to the PKCS #11 model, + * intended to support multiple PKCS #11 using applications sharing a + * single HSM. Technically, sessions are per-client, but in practice + * there's no sane reason why we'd use the same session handle + * concurrently in multiple clients. Mostly, the client abstraction + * is to handle login and logout against the HSM's PIN. Clients add + * nothing whatsoever to the security model (the HSM has no way of + * knowing whether the host is lumping multiple applications into a + * single "client"), the point of the exercise is just to make the + * C_Login()/C_Logout() semantics work as expected in the presence of + * multiple applications. + * + * NB: Unlike the other handles used in this protocol, session and + * client handles are created by the client (host) side of the RPC + * mechanism, not the server (HSM) side. + */ + +#define HAL_HANDLE_NONE (0) + +typedef struct { uint32_t handle; } hal_client_handle_t; +typedef struct { uint32_t handle; } hal_session_handle_t; + +typedef enum { HAL_USER_NONE, HAL_USER_NORMAL, HAL_USER_SO, HAL_USER_WHEEL } hal_user_t; + +extern hal_error_t hal_rpc_set_pin(const hal_client_handle_t client, + const hal_user_t user, + const char * const newpin, const size_t newpin_len); + +extern hal_error_t hal_rpc_login(const hal_client_handle_t client, + const hal_user_t user, + const char * const pin, const size_t pin_len); + +extern hal_error_t hal_rpc_logout(const hal_client_handle_t client); + +extern hal_error_t hal_rpc_logout_all(void); + +extern hal_error_t hal_rpc_is_logged_in(const hal_client_handle_t client, + const hal_user_t user); + +/* + * Get the version number of the remote RPC server. + */ + +extern hal_error_t hal_rpc_get_version(uint32_t *version); + +/* + * Get random bytes. + */ + +extern hal_error_t hal_rpc_get_random(void *buffer, const size_t length); + +/* + * Combined hash and HMAC functions: pass NULL key for plain hashing. + */ + +typedef struct { uint32_t handle; } hal_hash_handle_t; + +extern const hal_hash_handle_t hal_hash_handle_none; + +extern hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, size_t *length); + +extern hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg, + uint8_t *id, size_t *len, const size_t len_max); + +extern hal_error_t hal_rpc_hash_get_algorithm(const hal_hash_handle_t hash, hal_digest_algorithm_t *alg); + +/* + * Once started, a hash or HMAC operation is bound to a particular + * session, so we only need the client and session arguments to initialize. + */ + +extern hal_error_t hal_rpc_hash_initialize(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_length); + +extern hal_error_t hal_rpc_hash_update(const hal_hash_handle_t hash, + const uint8_t * data, const size_t length); + +extern hal_error_t hal_rpc_hash_finalize(const hal_hash_handle_t hash, + uint8_t *digest, const size_t length); + +/* + * Public key functions. + * + * The _sign() and _verify() methods accept a hash OR an input string; + * either "hash" should be hal_hash_handle_none or input should be NULL, + * but not both. + * + * Use of client and session handles here needs a bit more thought. + * + * Client handles are straightforward: basically, anything that + * creates a new pkey handle should take a client handle, which should + * suffice, as object handles never cross clients. + * + * Session handles are more interesting, as PKCS #11's versions of + * session and object handles do in effect allow one session to hand + * an object handle to another session. So any action which can do + * significant work (ie, which is complicated enough that we can't + * guarantee an immediate response) needs to take a session handle. + * + * There will probably be a few cases where a session handle isn't + * strictly required but we ask for one anyway because the API turns + * out to be easier to understand that way (eg, we probably want to + * ask for a session handle anywhere we ask for a client handle, + * whether we need the session handle or not, so that users of this + * API don't have to remember which pkey-handle-creating calls require + * a session handle and which ones don't...). + */ + +#define HAL_RPC_PKEY_NAME_MAX 128 + +typedef struct { uint32_t handle; } hal_pkey_handle_t; + +typedef uint32_t hal_key_flags_t; + +#define HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE (1 << 0) +#define HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT (1 << 1) +#define HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT (1 << 2) + +extern hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const hal_curve_name_t curve, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + const hal_key_flags_t flags); + +extern hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len); + +extern hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const unsigned key_length, + const uint8_t * const public_exponent, const size_t public_exponent_len, + const hal_key_flags_t flags); + +extern hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const hal_curve_name_t curve, + const hal_key_flags_t flags); + +extern hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey); + +extern hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey); + +extern hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey, + hal_key_type_t *type); + +extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_pkey_handle_t pkey, + hal_key_flags_t *flags); + +extern size_t hal_rpc_pkey_get_public_key_len(const hal_pkey_handle_t pkey); + +extern hal_error_t hal_rpc_pkey_get_public_key(const hal_pkey_handle_t pkey, + uint8_t *der, size_t *der_len, const size_t der_max); + +extern hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max); + +extern hal_error_t hal_rpc_pkey_verify(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len); + +typedef struct { + hal_key_type_t type; + hal_curve_name_t curve; + hal_key_flags_t flags; + char name[HAL_RPC_PKEY_NAME_MAX]; + size_t name_len; + /* ... */ +} hal_pkey_info_t; + +extern hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max); + +extern hal_error_t hal_rpc_client_init(void); +extern hal_error_t hal_rpc_client_close(void); +extern hal_error_t hal_rpc_server_init(void); +extern hal_error_t hal_rpc_server_close(void); +extern void hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen); +extern void hal_rpc_server_main(void); #endif /* _HAL_H_ */ diff --git a/hal_internal.h b/hal_internal.h new file mode 100644 index 0000000..8c0b0bc --- /dev/null +++ b/hal_internal.h @@ -0,0 +1,397 @@ +/* + * hal_internal.h + * -------------- + * Internal API declarations for libhal. + * + * Authors: Rob Austein, Paul Selkirk + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _HAL_INTERNAL_H_ +#define _HAL_INTERNAL_H_ + +#include "hal.h" +#include "verilog_constants.h" + +/* + * Longest hash block and digest we support at the moment. + */ + +#define HAL_MAX_HASH_BLOCK_LENGTH SHA512_BLOCK_LEN +#define HAL_MAX_HASH_DIGEST_LENGTH SHA512_DIGEST_LEN + +/* + * Everything in this file is part of the internal API, that is, + * subject to change without notice. Nothing outside of libhal itself + * should be looking at this file. + */ + +/* + * Dispatch structures for RPC implementation. + * + * The breakdown of which functions go into which dispatch vectors is + * based entirely on pesky details like making sure that the right + * functions get linked in the right cases, and should not be + * construed as making any particular sense in any larger context. + * + * In theory eventually we might want a fully general mechanism to + * allow us to dispatch arbitrary groups of functions either locally + * or remotely on a per-user basis. In practice, we probably want to + * run everything on the HSM except for hashing and digesting, so just + * code for that case initially while leaving the design open for a + * more general mechanism later if warranted. + * + * So we have three cases: + * + * - We're the HSM, so we do everything locally (ie, we run the RPC + * server functions. + * + * - We're the host, so we do everything remotely (ie, we do + * everything using the client-side RPC calls. + * + * - We're the host but are doing hashing locally, so we do a mix. + * This is slightly more complicated than it might at first appear, + * because we must handle the case of one of the pkey functions + * taking a hash context instead of a literal hash value, in which + * case we have to extract the hash value from the context and + * supply it to the pkey RPC client code as a literal value. + */ + +typedef struct { + + hal_error_t (*set_pin)(const hal_client_handle_t client, + const hal_user_t user, + const char * const newpin, const size_t newpin_len); + + hal_error_t (*login)(const hal_client_handle_t client, + const hal_user_t user, + const char * const newpin, const size_t newpin_len); + + hal_error_t (*logout)(const hal_client_handle_t client); + + hal_error_t (*logout_all)(void); + + hal_error_t (*is_logged_in)(const hal_client_handle_t client, + const hal_user_t user); + + hal_error_t (*get_random)(void *buffer, const size_t length); + + hal_error_t (*get_version)(uint32_t *version); + +} hal_rpc_misc_dispatch_t; + + +typedef struct { + + hal_error_t (*get_digest_length)(const hal_digest_algorithm_t alg, size_t *length); + + hal_error_t (*get_digest_algorithm_id)(const hal_digest_algorithm_t alg, + uint8_t *id, size_t *len, const size_t len_max); + + hal_error_t (*get_algorithm)(const hal_hash_handle_t hash, hal_digest_algorithm_t *alg); + + hal_error_t (*initialize)(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_length); + + hal_error_t (*update)(const hal_hash_handle_t hash, + const uint8_t * data, const size_t length); + + hal_error_t (*finalize)(const hal_hash_handle_t hash, + uint8_t *digest, const size_t length); +} hal_rpc_hash_dispatch_t; + + +typedef struct { + + hal_error_t (*load)(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const hal_curve_name_t curve, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + const hal_key_flags_t flags); + + hal_error_t (*find)(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len); + + hal_error_t (*generate_rsa)(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const unsigned key_length, + const uint8_t * const public_exponent, const size_t public_exponent_len, + const hal_key_flags_t flags); + + hal_error_t (*generate_ec)(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const hal_curve_name_t curve, + const hal_key_flags_t flags); + + hal_error_t (*close)(const hal_pkey_handle_t pkey); + + hal_error_t (*delete)(const hal_pkey_handle_t pkey); + + hal_error_t (*get_key_type)(const hal_pkey_handle_t pkey, + hal_key_type_t *key_type); + + hal_error_t (*get_key_flags)(const hal_pkey_handle_t pkey, + hal_key_flags_t *flags); + + size_t (*get_public_key_len)(const hal_pkey_handle_t pkey); + + hal_error_t (*get_public_key)(const hal_pkey_handle_t pkey, + uint8_t *der, size_t *der_len, const size_t der_max); + + hal_error_t (*sign)(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max); + + hal_error_t (*verify)(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len); + + hal_error_t (*list)(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max); + +} hal_rpc_pkey_dispatch_t; + + +extern const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch, hal_rpc_remote_misc_dispatch, *hal_rpc_misc_dispatch; +extern const hal_rpc_hash_dispatch_t hal_rpc_local_hash_dispatch, hal_rpc_remote_hash_dispatch, *hal_rpc_hash_dispatch; +extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote_pkey_dispatch, hal_rpc_mixed_pkey_dispatch, *hal_rpc_pkey_dispatch; + +/* + * Keystore API. + * + * The original design for this subsystem used two separate tables, + * one for RSA keys, one for EC keys, because the RSA keys are so much + * larger than the EC keys. This led to unnecessarily complex and + * duplicated code, so for now we treat all keys the same, and waste + * the unneded space in the case of EC keys. + * + * Sizes for ASN.1-encoded keys, this may not be exact due to ASN.1 + * INTEGER encoding rules but should be good enough for buffer sizing: + * + * 2048-bit RSA: 1194 bytes + * 4096-bit RSA: 2351 bytes + * 8192-bit RSA: 4655 bytes + * EC P-256: 121 bytes + * EC P-384: 167 bytes + * EC P-521: 223 bytes + * + * Plus we need a bit of AES-keywrap overhead, since we're storing the + * wrapped form (see hal_aes_keywrap_cyphertext_length()). + * + * We also need to store PINs somewhere, so they go into the keystore + * data structure even though they're not keys. Like keys, they're + * stored in a relatively safe form (PBKDF2), so while we would prefer + * to keep them private, they don't require tamper-protected RAM. + */ + +#define HAL_KS_WRAPPED_KEYSIZE ((4655 + 15) & ~7) + +#ifndef HAL_STATIC_PKEY_STATE_BLOCKS +#define HAL_STATIC_PKEY_STATE_BLOCKS 0 +#endif + +typedef struct { + hal_key_type_t type; + hal_curve_name_t curve; + hal_key_flags_t flags; + uint8_t name[HAL_RPC_PKEY_NAME_MAX]; + size_t name_len; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + size_t der_len; + uint8_t in_use; +} hal_ks_key_t; + +#ifndef HAL_PIN_SALT_LENGTH +#define HAL_PIN_SALT_LENGTH 16 +#endif + +typedef struct { + uint32_t iterations; + uint8_t pin[HAL_MAX_HASH_DIGEST_LENGTH]; + uint8_t salt[HAL_PIN_SALT_LENGTH]; +} hal_ks_pin_t; + +typedef struct { + +#if HAL_STATIC_PKEY_STATE_BLOCKS > 0 + hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS]; +#endif + + hal_ks_pin_t wheel_pin; + hal_ks_pin_t so_pin; + hal_ks_pin_t user_pin; + +} hal_ks_keydb_t; + +/* + * Internal functions within the keystore implementation. Think of + * these as concrete methods for the keystore API subclassed onto + * various storage technologies. + */ + +extern const hal_ks_keydb_t *hal_ks_get_keydb(void); + +extern hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key, + const int loc); + +extern hal_error_t hal_ks_del_keydb(const int loc); + +extern hal_error_t hal_ks_get_kek(uint8_t *kek, + size_t *kek_len, + const size_t kek_max); + +/* + * Keystore API for use by the pkey implementation. + * + * In an attempt to emulate what current theory says will eventually + * be the behavior of the underlying Cryptech Verilog "hardware", + * these functions automatically apply the AES keywrap transformations. + * + * Unclear whether these should also call the ASN.1 encode/decode + * functions. For the moment, the answer is no, but we may need to + * revisit this as the underlying Verilog API evolves. + */ + +extern hal_error_t hal_ks_store(const hal_key_type_t type, + const hal_curve_name_t curve, + const hal_key_flags_t flags, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + int *hint); + +extern hal_error_t hal_ks_exists(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + int *hint); + +extern hal_error_t hal_ks_fetch(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + hal_curve_name_t *curve, + hal_key_flags_t *flags, + uint8_t *der, size_t *der_len, const size_t der_max, + int *hint); + +extern hal_error_t hal_ks_delete(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + int *hint); + +extern hal_error_t hal_ks_list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max); + +extern hal_error_t hal_ks_get_pin(const hal_user_t user, + const hal_ks_pin_t **pin); + +extern hal_error_t hal_ks_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin); + +/* + * RPC lowest-level send and receive routines. These are blocking, and + * transport-specific (sockets, USB). + */ + +extern hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len); +extern hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len); + +extern hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque); +extern hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque); + +extern hal_error_t hal_rpc_client_transport_init(void); +extern hal_error_t hal_rpc_client_transport_close(void); + +extern hal_error_t hal_rpc_server_transport_init(void); +extern hal_error_t hal_rpc_server_transport_close(void); + + +/* + * RPC function numbers + */ + +typedef enum { + RPC_FUNC_GET_VERSION = 0, + RPC_FUNC_GET_RANDOM, + RPC_FUNC_SET_PIN, + RPC_FUNC_LOGIN, + RPC_FUNC_LOGOUT, + RPC_FUNC_LOGOUT_ALL, + RPC_FUNC_IS_LOGGED_IN, + RPC_FUNC_HASH_GET_DIGEST_LEN, + RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID, + RPC_FUNC_HASH_GET_ALGORITHM, + RPC_FUNC_HASH_INITIALIZE, + RPC_FUNC_HASH_UPDATE, + RPC_FUNC_HASH_FINALIZE, + RPC_FUNC_PKEY_LOAD, + RPC_FUNC_PKEY_FIND, + RPC_FUNC_PKEY_GENERATE_RSA, + RPC_FUNC_PKEY_GENERATE_EC, + RPC_FUNC_PKEY_CLOSE, + RPC_FUNC_PKEY_DELETE, + RPC_FUNC_PKEY_GET_KEY_TYPE, + RPC_FUNC_PKEY_GET_KEY_FLAGS, + RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN, + RPC_FUNC_PKEY_GET_PUBLIC_KEY, + RPC_FUNC_PKEY_REMOTE_SIGN, + RPC_FUNC_PKEY_REMOTE_VERIFY, + RPC_FUNC_PKEY_LIST, +} rpc_func_num_t; + +#define RPC_VERSION 0x00010000 /* 0.1.0.0 */ + +/* RPC client locality. These have to be defines rather than an enum, + * because they're handled by the preprocessor. + */ +#define RPC_CLIENT_LOCAL 0 +#define RPC_CLIENT_REMOTE 1 +#define RPC_CLIENT_MIXED 2 + +#endif /* _HAL_INTERNAL_H_ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/hal_io_eim.c b/hal_io_eim.c index fbf1d67..e353451 100644 --- a/hal_io_eim.c +++ b/hal_io_eim.c @@ -39,7 +39,7 @@ #include "novena-eim.h" #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" static int debug = 0; static int inited = 0; diff --git a/hal_io_fmc.c b/hal_io_fmc.c new file mode 100644 index 0000000..5629b69 --- /dev/null +++ b/hal_io_fmc.c @@ -0,0 +1,207 @@ +/* + * hal_io_fmc.c + * ------------ + * This module contains common code to talk to the FPGA over the FMC bus. + * + * Author: Paul Selkirk + * Copyright (c) 2014-2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> + +#include "stm-fmc.h" +#include "hal.h" +#include "hal_internal.h" + +static int debug = 0; +static int inited = 0; + +#ifndef FMC_IO_TIMEOUT +#define FMC_IO_TIMEOUT 100000000 +#endif + +/* not available in arm-none-eabi libc */ +#ifdef __ARMEL__ // Little endian +static inline uint32_t htonl(uint32_t w) +{ + return + ((w & 0x000000ff) << 24) + + ((w & 0x0000ff00) << 8) + + ((w & 0x00ff0000) >> 8) + + ((w & 0xff000000) >> 24); +} +#else // Big endian +#define htonl(x) (x) +#endif +#define ntohl htonl + +static hal_error_t init(void) +{ + if (!inited) { + fmc_init(); + inited = 1; + } + return HAL_OK; +} + +/* Translate cryptech register number to FMC address. + * + * register number format: + * 3 bits segment selector + * 5 bits core selector (6 bits in native eim) + * 8 bits register selector + * + * sss ccccc rrrrrrrr => sss 0 ccccc rrrrrrrr 00 + */ +static hal_addr_t fmc_offset(hal_addr_t offset) +{ + return ((offset & ~0x1fff) << 3) + ((offset & 0x1fff) << 2); +} + +void hal_io_set_debug(int onoff) +{ + debug = onoff; +} + +static void dump(char *label, const uint8_t *buf, size_t len) +{ + if (debug) { + size_t i; + printf("%s [", label); + for (i = 0; i < len; ++i) + printf(" %02x", buf[i]); + printf(" ]\n"); + } +} + +hal_error_t hal_io_write(const hal_core_t *core, hal_addr_t offset, const uint8_t *buf, size_t 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; + + dump("write ", buf, len); + + offset = fmc_offset(offset + hal_core_base(core)); + for (; len > 0; offset += 4, buf += 4, len -= 4) { + uint32_t val; + val = htonl(*(uint32_t *)buf); + fmc_write_32(offset, &val); + } + + 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; + + offset = fmc_offset(offset + hal_core_base(core)); + for (; rlen > 0; offset += 4, rbuf += 4, rlen -= 4) { + uint32_t val; + fmc_read_32(offset, &val); + *(uint32_t *)rbuf = ntohl(val); + } + + dump("read ", buf, len); + + return HAL_OK; +} + +hal_error_t hal_io_init(const hal_core_t *core) +{ + uint8_t buf[4] = { 0, 0, 0, CTRL_INIT }; + return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf)); +} + +hal_error_t hal_io_next(const hal_core_t *core) +{ + uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT }; + return hal_io_write(core, ADDR_CTRL, buf, sizeof(buf)); +} + +hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count) +{ + hal_error_t err; + uint8_t buf[4]; + int i; + + for (i = 1; ; ++i) { + + if (count && (*count > 0) && (i >= *count)) + return HAL_ERROR_IO_TIMEOUT; + + if ((err = hal_io_read(core, ADDR_STATUS, buf, sizeof(buf))) != HAL_OK) + return err; + + if ((buf[3] & status) != 0) { + if (count) + *count = i; + return HAL_OK; + } + } +} + +hal_error_t hal_io_wait_ready(const hal_core_t *core) +{ + int limit = FMC_IO_TIMEOUT; + return hal_io_wait(core, STATUS_READY, &limit); +} + +hal_error_t hal_io_wait_valid(const hal_core_t *core) +{ + int limit = FMC_IO_TIMEOUT; + return hal_io_wait(core, STATUS_VALID, &limit); +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-basic-offset: 2 + * End: + */ diff --git a/hal_io_i2c.c b/hal_io_i2c.c index 7fb306e..e7dbbb6 100644 --- a/hal_io_i2c.c +++ b/hal_io_i2c.c @@ -41,7 +41,7 @@ #include <stdint.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" #define I2C_dev "/dev/i2c-2" #define I2C_addr 0x0f @@ -1,10 +1,10 @@ /* - * hashes.c - * -------- + * hash.c + * ------ * HAL interface to Cryptech hash cores. * - * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein - * Copyright (c) 2014-2015, NORDUnet A/S + * Authors: Joachim Strömbergson, Paul Selkirk, Rob Austein + * Copyright (c) 2014-2016, NORDUnet A/S * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,7 +41,36 @@ #include <stdint.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" + +/* + * Whether to include software implementations of the hash cores, + * for use when the Verilog cores aren't available. + */ + +#if RPC_CLIENT == RPC_CLIENT_MIXED +#define HAL_ENABLE_SOFTWARE_HASH_CORES 1 +#endif + +#ifndef HAL_ENABLE_SOFTWARE_HASH_CORES +#define HAL_ENABLE_SOFTWARE_HASH_CORES 0 +#endif + +typedef hal_error_t (*sw_hash_core_t)(hal_hash_state_t *); + +#if HAL_ENABLE_SOFTWARE_HASH_CORES + +static hal_error_t sw_hash_core_sha1( hal_hash_state_t *); +static hal_error_t sw_hash_core_sha256(hal_hash_state_t *); +static hal_error_t sw_hash_core_sha512(hal_hash_state_t *); + +#else /* HAL_ENABLE_SOFTWARE_HASH_CORES */ + +#define sw_hash_core_sha1 ((sw_hash_core_t) 0) +#define sw_hash_core_sha256 ((sw_hash_core_t) 0) +#define sw_hash_core_sha512 ((sw_hash_core_t) 0) + +#endif /* HAL_ENABLE_SOFTWARE_HASH_CORES */ /* * HMAC magic numbers. @@ -54,20 +83,15 @@ * Driver. This encapsulates whatever per-algorithm voodoo we need * this week. At the moment, this is mostly Cryptech core addresses, * but this is subject to change without notice. - * - * Most of the addresses in the current version could be calculated - * from a single address (the core base address), but this week's - * theory prefers the precomputed composite addresses, and doing it - * this way saves some microscopic bit of addition at runtime. - * Whatever. It'll probably all change again once we have a dynamic - * memory map, so it's not really worth overthinking at the moment. */ struct hal_hash_driver { size_t length_length; /* Length of the length field */ - hal_addr_t block_addr; /* Where to write hash blocks */ + hal_addr_t block_addr; /* Where to write hash blocks */ hal_addr_t digest_addr; /* Where to read digest */ uint8_t ctrl_mode; /* Digest mode, for cores that have modes */ + sw_hash_core_t sw_core; /* Software implementation, when enabled */ + size_t sw_word_size; /* Word size for software implementation */ }; /* @@ -88,7 +112,8 @@ struct hal_hash_state { unsigned flags; }; -#define STATE_FLAG_STATE_ALLOCATED 0x1 /* State buffer dynamically allocated */ +#define STATE_FLAG_STATE_ALLOCATED 0x1 /* State buffer dynamically allocated */ +#define STATE_FLAG_SOFTWARE_CORE 0x2 /* Use software rather than hardware core */ /* * HMAC state. Right now this just holds the key block and a hash @@ -105,34 +130,30 @@ struct hal_hmac_state { /* * Drivers for known digest algorithms. - * - * Initialization of the core_name field is not a typo, we're - * concatenating two string constants and trusting the compiler to - * whine if the resulting string doesn't fit into the field. */ static const hal_hash_driver_t sha1_driver = { - SHA1_LENGTH_LEN, SHA1_ADDR_BLOCK, SHA1_ADDR_DIGEST, 0 + SHA1_LENGTH_LEN, SHA1_ADDR_BLOCK, SHA1_ADDR_DIGEST, 0, sw_hash_core_sha1, sizeof(uint32_t) }; static const hal_hash_driver_t sha256_driver = { - SHA256_LENGTH_LEN, SHA256_ADDR_BLOCK, SHA256_ADDR_DIGEST, 0 + SHA256_LENGTH_LEN, SHA256_ADDR_BLOCK, SHA256_ADDR_DIGEST, 0, sw_hash_core_sha256, sizeof(uint32_t) }; static const hal_hash_driver_t sha512_224_driver = { - SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512_224 + SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512_224, sw_hash_core_sha512, sizeof(uint64_t) }; static const hal_hash_driver_t sha512_256_driver = { - SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512_256 + SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512_256, sw_hash_core_sha512, sizeof(uint64_t) }; static const hal_hash_driver_t sha384_driver = { - SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_384 + SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_384, sw_hash_core_sha512, sizeof(uint64_t) }; static const hal_hash_driver_t sha512_driver = { - SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512 + SHA512_LENGTH_LEN, SHA512_ADDR_BLOCK, SHA512_ADDR_DIGEST, MODE_SHA_512, sw_hash_core_sha512, sizeof(uint64_t) }; /* @@ -165,6 +186,7 @@ static const uint8_t */ const hal_hash_descriptor_t hal_hash_sha1[1] = {{ + hal_digest_algorithm_sha1, SHA1_BLOCK_LEN, SHA1_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha1, sizeof(dalgid_sha1), @@ -172,6 +194,7 @@ const hal_hash_descriptor_t hal_hash_sha1[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha256[1] = {{ + hal_digest_algorithm_sha256, SHA256_BLOCK_LEN, SHA256_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha256, sizeof(dalgid_sha256), @@ -179,6 +202,7 @@ const hal_hash_descriptor_t hal_hash_sha256[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{ + hal_digest_algorithm_sha512_224, SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512_224, sizeof(dalgid_sha512_224), @@ -186,6 +210,7 @@ const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{ + hal_digest_algorithm_sha512_256, SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512_256, sizeof(dalgid_sha512_256), @@ -193,6 +218,7 @@ const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha384[1] = {{ + hal_digest_algorithm_sha384, SHA512_BLOCK_LEN, SHA384_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha384, sizeof(dalgid_sha384), @@ -200,6 +226,7 @@ const hal_hash_descriptor_t hal_hash_sha384[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512[1] = {{ + hal_digest_algorithm_sha512, SHA512_BLOCK_LEN, SHA512_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512, sizeof(dalgid_sha512), @@ -207,6 +234,33 @@ const hal_hash_descriptor_t hal_hash_sha512[1] = {{ }}; /* + * Static state blocks. This library is intended for a style of + * embedded programming in which one avoids heap-based allocation + * functions such as malloc() wherever possible and instead uses + * static variables when just allocating on the stack won't do. + * + * The number of each kind of state block to be allocated this way + * must be configured at compile-time. Sorry, that's life in the + * deeply embedded universe. + */ + +#ifndef HAL_STATIC_HASH_STATE_BLOCKS +#define HAL_STATIC_HASH_STATE_BLOCKS 0 +#endif + +#ifndef HAL_STATIC_HMAC_STATE_BLOCKS +#define HAL_STATIC_HMAC_STATE_BLOCKS 0 +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 +static hal_hash_state_t static_hash_state[HAL_STATIC_HASH_STATE_BLOCKS]; +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 +static hal_hmac_state_t static_hmac_state[HAL_STATIC_HMAC_STATE_BLOCKS]; +#endif + +/* * Debugging control. */ @@ -218,6 +272,70 @@ void hal_hash_set_debug(int onoff) } /* + * Internal utilities to allocate static state blocks. + */ + +static inline hal_hash_state_t *alloc_static_hash_state(void) +{ + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + + for (int i = 0; i < sizeof(static_hash_state)/sizeof(*static_hash_state); i++) + if ((static_hash_state[i].flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return &static_hash_state[i]; + +#endif + + return NULL; +} + +static inline hal_hmac_state_t *alloc_static_hmac_state(void) +{ + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 + + for (int i = 0; i < sizeof(static_hmac_state)/sizeof(*static_hmac_state); i++) + if ((static_hmac_state[i].hash_state.flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return &static_hmac_state[i]; + +#endif + + return NULL; +} + +/* + * Internal utility to do a sort of byte-swapping memcpy() (sigh). + * This is only used by the software hash cores, but it's simpler to define it unconditionally. + */ + +static inline void swytebop(void *out_, const void * const in_, const size_t n, const size_t w) +{ + const uint8_t order[] = { 0x01, 0x02, 0x03, 0x04 }; + + const uint8_t * const in = in_; + uint8_t *out = out_; + + /* w must be a power of two */ + assert(in != out && in != NULL && out != NULL && w && !(w & (w - 1))); + + switch (* (uint32_t *) order) { + + case 0x01020304: + memcpy(out, in, n); + return; + + case 0x04030201: + for (int i = 0; i < n; i += w) + for (int j = 0; j < w && i + j < n; j++) + out[i + j] = in[i + w - j - 1]; + return; + + default: + assert((* (uint32_t *) order) == 0x01020304 || (* (uint32_t *) order) == 0x04030201); + } +} + +/* * Internal utility to do whatever checking we need of a descriptor, * then extract the driver pointer in a way that works nicely with * initialization of an automatic const pointer. @@ -225,7 +343,7 @@ void hal_hash_set_debug(int onoff) * Returns the driver pointer on success, NULL on failure. */ -static const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const descriptor) +static inline const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const descriptor) { return descriptor == NULL ? NULL : descriptor->driver; } @@ -235,11 +353,31 @@ static const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const * attempting to locate an appropriate core if we weren't given one. */ -static hal_error_t check_core(const hal_core_t **core, - const hal_hash_descriptor_t * const descriptor) +static inline hal_error_t check_core(const hal_core_t **core, + const hal_hash_descriptor_t * const descriptor, + unsigned *flags) { assert(descriptor != NULL && descriptor->driver != NULL); - return hal_core_check_name(core, descriptor->core_name); + +#if RPC_CLIENT == RPC_CLIENT_MIXED + hal_error_t err = HAL_ERROR_CORE_NOT_FOUND; +#else + hal_error_t err = hal_core_check_name(core, descriptor->core_name); +#endif + +#if HAL_ENABLE_SOFTWARE_HASH_CORES + + if (err == HAL_ERROR_CORE_NOT_FOUND && descriptor->driver->sw_core) { + + if (flags != NULL) + *flags |= STATE_FLAG_SOFTWARE_CORE; + + err = HAL_OK; + } + +#endif /* HAL_ENABLE_SOFTWARE_HASH_CORES */ + + return err; } /* @@ -253,6 +391,7 @@ hal_error_t hal_hash_initialize(const hal_core_t *core, { const hal_hash_driver_t * const driver = check_driver(descriptor); hal_hash_state_t *state = state_buffer; + unsigned flags = 0; hal_error_t err; if (driver == NULL || state_ == NULL) @@ -261,16 +400,17 @@ hal_error_t hal_hash_initialize(const hal_core_t *core, if (state_buffer != NULL && state_length < descriptor->hash_state_length) return HAL_ERROR_BAD_ARGUMENTS; - if ((err = check_core(&core, descriptor)) != HAL_OK) + if ((err = check_core(&core, descriptor, &flags)) != HAL_OK) return err; - if (state_buffer == NULL && (state = malloc(descriptor->hash_state_length)) == NULL) + if (state_buffer == NULL && (state = alloc_static_hash_state()) == NULL) return HAL_ERROR_ALLOCATION_FAILURE; memset(state, 0, sizeof(*state)); state->descriptor = descriptor; state->driver = driver; state->core = core; + state->flags = flags; if (state_buffer == NULL) state->flags |= STATE_FLAG_STATE_ALLOCATED; @@ -295,10 +435,11 @@ void hal_hash_cleanup(hal_hash_state_t **state_) return; memset(state, 0, state->descriptor->hash_state_length); - free(state); *state_ = NULL; } +#if RPC_CLIENT != RPC_CLIENT_MIXED + /* * Read hash result from core. At least for now, this also serves to * read current hash state from core. @@ -338,6 +479,8 @@ static hal_error_t hash_write_digest(const hal_core_t *core, return hal_io_write(core, driver->digest_addr, digest, digest_length); } +#endif + /* * Send one block to a core. */ @@ -356,6 +499,12 @@ static hal_error_t hash_write_block(hal_hash_state_t * const state) if (debug) fprintf(stderr, "[ %s ]\n", state->block_count == 0 ? "init" : "next"); +#if RPC_CLIENT == RPC_CLIENT_MIXED + return state->driver->sw_core(state); +#else + if (HAL_ENABLE_SOFTWARE_HASH_CORES && (state->flags & STATE_FLAG_SOFTWARE_CORE) != 0) + return state->driver->sw_core(state); + if ((err = hal_io_wait_ready(state->core)) != HAL_OK) return err; @@ -382,6 +531,7 @@ static hal_error_t hash_write_block(hal_hash_state_t * const state) return err; return hal_io_wait_valid(state->core); +#endif } /* @@ -444,7 +594,7 @@ hal_error_t hal_hash_update(hal_hash_state_t *state, /* Opaque state * Finish hash and return digest. */ -hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaque state block */ +hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaque state block */ uint8_t *digest_buffer, /* Returned digest */ const size_t digest_buffer_length) /* Length of digest_buffer */ { @@ -512,7 +662,11 @@ hal_error_t hal_hash_finalize(hal_hash_state_t *state, /* Opaque sta state->block_count++; /* All data pushed to core, now we just need to read back the result */ - if ((err = hash_read_digest(state->core, state->driver, digest_buffer, state->descriptor->digest_length)) != HAL_OK) + if (HAL_ENABLE_SOFTWARE_HASH_CORES && (state->flags & STATE_FLAG_SOFTWARE_CORE) != 0) + swytebop(digest_buffer, state->core_state, state->descriptor->digest_length, state->driver->sw_word_size); +#if RPC_CLIENT != RPC_CLIENT_MIXED + else if ((err = hash_read_digest(state->core, state->driver, digest_buffer, state->descriptor->digest_length)) != HAL_OK) +#endif return err; return HAL_OK; @@ -539,10 +693,10 @@ hal_error_t hal_hmac_initialize(const hal_core_t *core, if (state_buffer != NULL && state_length < descriptor->hmac_state_length) return HAL_ERROR_BAD_ARGUMENTS; - if ((err = check_core(&core, descriptor)) != HAL_OK) + if ((err = check_core(&core, descriptor, NULL)) != HAL_OK) return err; - if (state_buffer == NULL && (state = malloc(descriptor->hmac_state_length)) == NULL) + if (state_buffer == NULL && (state = alloc_static_hmac_state()) == NULL) return HAL_ERROR_ALLOCATION_FAILURE; hal_hash_state_t *h = &state->hash_state; @@ -639,7 +793,6 @@ void hal_hmac_cleanup(hal_hmac_state_t **state_) return; memset(state, 0, h->descriptor->hmac_state_length); - free(state); *state_ = NULL; } @@ -690,6 +843,266 @@ hal_error_t hal_hmac_finalize(hal_hmac_state_t *state, } /* + * Pull descriptor pointer from state block. + */ + +const hal_hash_descriptor_t *hal_hash_get_descriptor(const hal_hash_state_t * const state) +{ + return state == NULL ? NULL : state->descriptor; +} + +const hal_hash_descriptor_t *hal_hmac_get_descriptor(const hal_hmac_state_t * const state) +{ + return state == NULL ? NULL : state->hash_state.descriptor; +} + +#if HAL_ENABLE_SOFTWARE_HASH_CORES + +/* + * Software implementations of hash cores. + * + * This is based in part on a mix of Tom St Denis's libtomcrypt C + * implementation and Joachim Strömbergson's Python models for the + * Cryptech hash cores. + * + * This is not a particularly high performance implementation, as + * we've given priority to portability and simplicity over speed. + * We assume that any reasonable modern compiler can handle inline + * functions, loop unrolling, and optimization of expressions which + * become constant upon inlining and unrolling. + */ + +/* + * K constants for SHA-2. SHA-1 only uses four K constants, which are handled inline + * due to other peculiarities of the SHA-1 algorithm). + */ + +static const uint32_t sha256_K[64] = { + 0x428A2F98UL, 0x71374491UL, 0xB5C0FBCFUL, 0xE9B5DBA5UL, 0x3956C25BUL, 0x59F111F1UL, 0x923F82A4UL, 0xAB1C5ED5UL, + 0xD807AA98UL, 0x12835B01UL, 0x243185BEUL, 0x550C7DC3UL, 0x72BE5D74UL, 0x80DEB1FEUL, 0x9BDC06A7UL, 0xC19BF174UL, + 0xE49B69C1UL, 0xEFBE4786UL, 0x0FC19DC6UL, 0x240CA1CCUL, 0x2DE92C6FUL, 0x4A7484AAUL, 0x5CB0A9DCUL, 0x76F988DAUL, + 0x983E5152UL, 0xA831C66DUL, 0xB00327C8UL, 0xBF597FC7UL, 0xC6E00BF3UL, 0xD5A79147UL, 0x06CA6351UL, 0x14292967UL, + 0x27B70A85UL, 0x2E1B2138UL, 0x4D2C6DFCUL, 0x53380D13UL, 0x650A7354UL, 0x766A0ABBUL, 0x81C2C92EUL, 0x92722C85UL, + 0xA2BFE8A1UL, 0xA81A664BUL, 0xC24B8B70UL, 0xC76C51A3UL, 0xD192E819UL, 0xD6990624UL, 0xF40E3585UL, 0x106AA070UL, + 0x19A4C116UL, 0x1E376C08UL, 0x2748774CUL, 0x34B0BCB5UL, 0x391C0CB3UL, 0x4ED8AA4AUL, 0x5B9CCA4FUL, 0x682E6FF3UL, + 0x748F82EEUL, 0x78A5636FUL, 0x84C87814UL, 0x8CC70208UL, 0x90BEFFFAUL, 0xA4506CEBUL, 0xBEF9A3F7UL, 0xC67178F2UL +}; + +static const uint64_t sha512_K[80] = { + 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL, + 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, + 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL, + 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL, + 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, + 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL, + 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL, + 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL, 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, + 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL, + 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL, + 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, + 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL, + 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL, + 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, + 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL, + 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL, + 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, + 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL, + 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL, + 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL +}; + +/* + * Various bit twiddling operations. We use inline functions rather than macros to get better + * data type checking, sane argument semantics, and simpler expressions (this stuff is + * confusing enough without adding a lot of unnecessary C macro baggage). + */ + +static inline uint32_t rot_l_32(uint32_t x, unsigned n) { assert(n < 32); return ((x << n) | (x >> (32 - n))); } +static inline uint32_t rot_r_32(uint32_t x, unsigned n) { assert(n < 32); return ((x >> n) | (x << (32 - n))); } +static inline uint32_t lsh_r_32(uint32_t x, unsigned n) { assert(n < 32); return (x >> n); } + +static inline uint64_t rot_r_64(uint64_t x, unsigned n) { assert(n < 64); return ((x >> n) | (x << (64 - n))); } +static inline uint64_t lsh_r_64(uint64_t x, unsigned n) { assert(n < 64); return (x >> n); } + +static inline uint32_t Choose_32( uint32_t x, uint32_t y, uint32_t z) { return (z ^ (x & (y ^ z))); } +static inline uint32_t Majority_32(uint32_t x, uint32_t y, uint32_t z) { return ((x & y) | (z & (x | y))); } +static inline uint32_t Parity_32( uint32_t x, uint32_t y, uint32_t z) { return (x ^ y ^ z); } + +static inline uint64_t Choose_64( uint64_t x, uint64_t y, uint64_t z) { return (z ^ (x & (y ^ z))); } +static inline uint64_t Majority_64(uint64_t x, uint64_t y, uint64_t z) { return ((x & y) | (z & (x | y))); } + +static inline uint32_t Sigma0_32(uint32_t x) { return rot_r_32(x, 2) ^ rot_r_32(x, 13) ^ rot_r_32(x, 22); } +static inline uint32_t Sigma1_32(uint32_t x) { return rot_r_32(x, 6) ^ rot_r_32(x, 11) ^ rot_r_32(x, 25); } +static inline uint32_t Gamma0_32(uint32_t x) { return rot_r_32(x, 7) ^ rot_r_32(x, 18) ^ lsh_r_32(x, 3); } +static inline uint32_t Gamma1_32(uint32_t x) { return rot_r_32(x, 17) ^ rot_r_32(x, 19) ^ lsh_r_32(x, 10); } + +static inline uint64_t Sigma0_64(uint64_t x) { return rot_r_64(x, 28) ^ rot_r_64(x, 34) ^ rot_r_64(x, 39); } +static inline uint64_t Sigma1_64(uint64_t x) { return rot_r_64(x, 14) ^ rot_r_64(x, 18) ^ rot_r_64(x, 41); } +static inline uint64_t Gamma0_64(uint64_t x) { return rot_r_64(x, 1) ^ rot_r_64(x, 8) ^ lsh_r_64(x, 7); } +static inline uint64_t Gamma1_64(uint64_t x) { return rot_r_64(x, 19) ^ rot_r_64(x, 61) ^ lsh_r_64(x, 6); } + +/* + * Offset into hash state. In theory, this should works out to compile-time constants after optimization. + */ + +static inline int sha1_pos(int i, int j) { assert(i >= 0 && j >= 0 && j < 5); return (5 + j - (i % 5)) % 5; } +static inline int sha2_pos(int i, int j) { assert(i >= 0 && j >= 0 && j < 8); return (8 + j - (i % 8)) % 8; } + +/* + * Software implementation of SHA-1 block algorithm. + */ + +static hal_error_t sw_hash_core_sha1(hal_hash_state_t *state) +{ + static const uint32_t iv[5] = {0x67452301UL, 0xefcdab89UL, 0x98badcfeUL, 0x10325476UL, 0xc3d2e1f0UL}; + + if (state == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + uint32_t *H = (uint32_t *) state->core_state, S[5], W[80]; + + if (state->block_count == 0) + memcpy(H, iv, sizeof(iv)); + + memcpy(S, H, sizeof(S)); + + swytebop(W, state->block, 16 * sizeof(*W), sizeof(*W)); + + for (int i = 16; i < 80; i++) + W[i] = rot_l_32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + + for (int i = 0; i < 80; i++) { + const int a = sha1_pos(i, 0), b = sha1_pos(i, 1), c = sha1_pos(i, 2), d = sha1_pos(i, 3), e = sha1_pos(i, 4); + + uint32_t f, k; + if (i < 20) f = Choose_32( S[b], S[c], S[d]), k = 0x5A827999UL; + else if (i < 40) f = Parity_32( S[b], S[c], S[d]), k = 0x6ED9EBA1UL; + else if (i < 60) f = Majority_32( S[b], S[c], S[d]), k = 0x8F1BBCDCUL; + else f = Parity_32( S[b], S[c], S[d]), k = 0xCA62C1D6UL; + + if (debug) + fprintf(stderr, + "[Round %02d < a = 0x%08x, b = 0x%08x, c = 0x%08x, d = 0x%08x, e = 0x%08x, f = 0x%08x, k = 0x%08x, w = 0x%08x]\n", + i, S[a], S[b], S[c], S[d], S[e], f, k, W[i]); + + S[e] = rot_l_32(S[a], 5) + f + S[e] + k + W[i]; + S[b] = rot_l_32(S[b], 30); + + if (debug) + fprintf(stderr, "[Round %02d > a = 0x%08x, b = 0x%08x, c = 0x%08x, d = 0x%08x, e = 0x%08x]\n", + i, S[a], S[b], S[c], S[d], S[e]); + } + + for (int i = 0; i < 5; i++) + H[i] += S[i]; + + return HAL_OK; +} + +/* + * Software implementation of SHA-256 block algorithm; doesn't support truncated variants because + * the Cryptech Verilog implementation doesn't. + */ + +static hal_error_t sw_hash_core_sha256(hal_hash_state_t *state) +{ + static const uint32_t iv[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; + + if (state == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + uint32_t *H = (uint32_t *) state->core_state, S[8], W[64]; + + if (state->block_count == 0) + memcpy(H, iv, sizeof(iv)); + + memcpy(S, H, sizeof(S)); + + swytebop(W, state->block, 16 * sizeof(*W), sizeof(*W)); + + for (int i = 16; i < 64; i++) + W[i] = Gamma1_32(W[i - 2]) + W[i - 7] + Gamma0_32(W[i - 15]) + W[i - 16]; + + for (int i = 0; i < 64; i++) { + const int a = sha2_pos(i, 0), b = sha2_pos(i, 1), c = sha2_pos(i, 2), d = sha2_pos(i, 3); + const int e = sha2_pos(i, 4), f = sha2_pos(i, 5), g = sha2_pos(i, 6), h = sha2_pos(i, 7); + + const uint32_t t0 = S[h] + Sigma1_32(S[e]) + Choose_32(S[e], S[f], S[g]) + sha256_K[i] + W[i]; + const uint32_t t1 = Sigma0_32(S[a]) + Majority_32(S[a], S[b], S[c]); + + S[d] += t0; + S[h] = t0 + t1; + } + + for (int i = 0; i < 8; i++) + H[i] += S[i]; + + return HAL_OK; +} + +/* + * Software implementation of SHA-512 block algorithm, including support for same truncated variants + * that the Cryptech Verilog SHA-512 core supports. + */ + +static hal_error_t sw_hash_core_sha512(hal_hash_state_t *state) +{ + static const uint64_t + sha512_iv[8] = {0x6A09E667F3BCC908ULL, 0xBB67AE8584CAA73BULL, 0x3C6EF372FE94F82BULL, 0xA54FF53A5F1D36F1ULL, + 0x510E527FADE682D1ULL, 0x9B05688C2B3E6C1FULL, 0x1F83D9ABFB41BD6BULL, 0x5BE0CD19137E2179ULL}; + static const uint64_t + sha384_iv[8] = {0xCBBB9D5DC1059ED8ULL, 0x629A292A367CD507ULL, 0x9159015A3070DD17ULL, 0x152FECD8F70E5939ULL, + 0x67332667FFC00B31ULL, 0x8EB44A8768581511ULL, 0xDB0C2E0D64F98FA7ULL, 0x47B5481DBEFA4FA4ULL}; + static const uint64_t + sha512_224_iv[8] = {0x8C3D37C819544DA2ULL, 0x73E1996689DCD4D6ULL, 0x1DFAB7AE32FF9C82ULL, 0x679DD514582F9FCFULL, + 0x0F6D2B697BD44DA8ULL, 0x77E36F7304C48942ULL, 0x3F9D85A86A1D36C8ULL, 0x1112E6AD91D692A1ULL}; + static const uint64_t + sha512_256_iv[8] = {0x22312194FC2BF72CULL, 0x9F555FA3C84C64C2ULL, 0x2393B86B6F53B151ULL, 0x963877195940EABDULL, + 0x96283EE2A88EFFE3ULL, 0xBE5E1E2553863992ULL, 0x2B0199FC2C85B8AAULL, 0x0EB72DDC81C52CA2ULL}; + + if (state == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + uint64_t *H = (uint64_t *) state->core_state, S[8], W[80]; + + if (state->block_count == 0) { + switch (state->driver->ctrl_mode & MODE_SHA_MASK) { + case MODE_SHA_512_224: memcpy(H, sha512_224_iv, sizeof(sha512_224_iv)); break; + case MODE_SHA_512_256: memcpy(H, sha512_256_iv, sizeof(sha512_256_iv)); break; + case MODE_SHA_384: memcpy(H, sha384_iv, sizeof(sha384_iv)); break; + case MODE_SHA_512: memcpy(H, sha512_iv, sizeof(sha512_iv)); break; + default: return HAL_ERROR_IMPOSSIBLE; + } + } + + memcpy(S, H, sizeof(S)); + + swytebop(W, state->block, 16 * sizeof(*W), sizeof(*W)); + + for (int i = 16; i < 80; i++) + W[i] = Gamma1_64(W[i - 2]) + W[i - 7] + Gamma0_64(W[i - 15]) + W[i - 16]; + + for (int i = 0; i < 80; i++) { + const int a = sha2_pos(i, 0), b = sha2_pos(i, 1), c = sha2_pos(i, 2), d = sha2_pos(i, 3); + const int e = sha2_pos(i, 4), f = sha2_pos(i, 5), g = sha2_pos(i, 6), h = sha2_pos(i, 7); + + const uint64_t t0 = S[h] + Sigma1_64(S[e]) + Choose_64(S[e], S[f], S[g]) + sha512_K[i] + W[i]; + const uint64_t t1 = Sigma0_64(S[a]) + Majority_64(S[a], S[b], S[c]); + + S[d] += t0; + S[h] = t0 + t1; + } + + for (int i = 0; i < 8; i++) + H[i] += S[i]; + + return HAL_OK; +} + +#endif /* HAL_ENABLE_SOFTWARE_HASH_CORES */ + +/* * "Any programmer who fails to comply with the standard naming, formatting, * or commenting conventions should be shot. If it so happens that it is * inconvenient to shoot him, then he is to be politely requested to recode @@ -0,0 +1,302 @@ +/* + * ks.c + * ---- + * Keystore API. This is internal within libhal. + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <assert.h> + +#include "hal.h" +#include "hal_internal.h" + +#define KEK_LENGTH (bitsToBytes(256)) + +static inline int acceptable_key_type(const hal_key_type_t type) +{ + switch (type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PUBLIC: + case HAL_KEY_TYPE_EC_PRIVATE: + case HAL_KEY_TYPE_EC_PUBLIC: + return 1; + default: + return 0; + } +} + +hal_error_t hal_ks_store(const hal_key_type_t type, + const hal_curve_name_t curve, + const hal_key_flags_t flags, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + int *hint) +{ + if (name == NULL || name_len == 0 || der == NULL || der_len == 0 || !acceptable_key_type(type)) + return HAL_ERROR_BAD_ARGUMENTS; + + if (name_len > HAL_RPC_PKEY_NAME_MAX) + return HAL_ERROR_RESULT_TOO_LONG; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + hal_error_t err; + int hint_; + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if (hint == NULL) + hint = &hint_; + + *hint = -1; + + for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) { + if (!db->keys[i].in_use && *hint < 0) + *hint = i; + if (db->keys[i].in_use && + db->keys[i].type == type && + db->keys[i].name_len == name_len && memcmp(db->keys[i].name, name, name_len) == 0) + return HAL_ERROR_KEY_NAME_IN_USE; + } + + if (*hint < 0) + return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; + + hal_ks_key_t k; + memset(&k, 0, sizeof(k)); + k.der_len = sizeof(k.der); + + uint8_t kek[KEK_LENGTH]; + size_t kek_len; + + if ((err = hal_ks_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) + err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k.der, &k.der_len); + + memset(kek, 0, sizeof(kek)); + + if (err != HAL_OK) + return err; + + assert(name_len <= sizeof(k.name)); + memcpy(k.name, name, name_len); + k.name_len = name_len; + k.type = type; + k.curve = curve; + k.flags = flags; + + if ((err = hal_ks_set_keydb(&k, *hint)) != HAL_OK) + return err; + + return HAL_OK; +} + +static int find(const hal_ks_keydb_t * const db, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + int *hint) +{ + assert(db != NULL && name != NULL && name_len > 0 && acceptable_key_type(type)); + + if (hint != NULL && *hint >= 0 && *hint < sizeof(db->keys)/sizeof(*db->keys) && + db->keys[*hint].in_use && + db->keys[*hint].type == type && + db->keys[*hint].name_len == name_len && memcmp(db->keys[*hint].name, name, name_len) == 0) + return 1; + + for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) { + if (!db->keys[i].in_use || + (hint != NULL && i == *hint) || + db->keys[i].type != type || + db->keys[i].name_len != name_len || memcmp(db->keys[i].name, name, name_len) != 0) + continue; + if (hint != NULL) + *hint = i; + return 1; + } + + return 0; +} + +hal_error_t hal_ks_exists(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + int *hint) +{ + if (name == NULL || name_len == 0 || !acceptable_key_type(type)) + return HAL_ERROR_BAD_ARGUMENTS; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if (find(db, type, name, name_len, hint)) + return HAL_OK; + else + return HAL_ERROR_KEY_NOT_FOUND; +} + +hal_error_t hal_ks_fetch(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + hal_curve_name_t *curve, + hal_key_flags_t *flags, + uint8_t *der, size_t *der_len, const size_t der_max, + int *hint) +{ + if (name == NULL || name_len == 0 || !acceptable_key_type(type)) + return HAL_ERROR_BAD_ARGUMENTS; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + int hint_ = -1; + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if (hint == NULL) + hint = &hint_; + + if (!find(db, type, name, name_len, hint)) + return HAL_ERROR_KEY_NOT_FOUND; + + const hal_ks_key_t * const k = &db->keys[*hint]; + + if (curve != NULL) + *curve = k->curve; + + if (flags != NULL) + *flags = k->flags; + + if (der == NULL && der_len != NULL) + *der_len = k->der_len; + + if (der != NULL) { + uint8_t kek[KEK_LENGTH]; + size_t kek_len, der_len_; + hal_error_t err; + + if (der_len == NULL) + der_len = &der_len_; + + *der_len = der_max; + + if ((err = hal_ks_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK) + err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len); + + memset(kek, 0, sizeof(kek)); + + if (err != HAL_OK) + return err; + } + + return HAL_OK; +} + +hal_error_t hal_ks_delete(const hal_key_type_t type, + const uint8_t * const name, const size_t name_len, + int *hint) +{ + if (name == NULL || name_len == 0 || !acceptable_key_type(type)) + return HAL_ERROR_BAD_ARGUMENTS; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + int hint_ = -1; + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + if (hint == NULL) + hint = &hint_; + + if (!find(db, type, name, name_len, hint)) + return HAL_ERROR_KEY_NOT_FOUND; + + return hal_ks_del_keydb(*hint); +} + +hal_error_t hal_ks_list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max) +{ + if (result == NULL || result_len == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + *result_len = 0; + + for (int i = 0; i < sizeof(db->keys)/sizeof(*db->keys); i++) { + + if (!db->keys[i].in_use) + continue; + + if (*result_len == result_max) + return HAL_ERROR_RESULT_TOO_LONG; + + result[*result_len].type = db->keys[i].type; + result[*result_len].curve = db->keys[i].curve; + result[*result_len].flags = db->keys[i].flags; + result[*result_len].name_len = db->keys[i].name_len; + memcpy(result[*result_len].name, db->keys[i].name, db->keys[i].name_len); + ++result_len; + } + + return HAL_OK; +} + +hal_error_t hal_ks_get_pin(const hal_user_t user, + const hal_ks_pin_t **pin) +{ + if (pin == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + const hal_ks_keydb_t * const db = hal_ks_get_keydb(); + + if (db == NULL) + return HAL_ERROR_KEYSTORE_ACCESS; + + switch (user) { + case HAL_USER_WHEEL: *pin = &db->wheel_pin; break; + case HAL_USER_SO: *pin = &db->so_pin; break; + case HAL_USER_NORMAL: *pin = &db->user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; + } + + return HAL_OK; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/ks_flash.c b/ks_flash.c new file mode 100644 index 0000000..eee259b --- /dev/null +++ b/ks_flash.c @@ -0,0 +1,110 @@ +/* + * ks_flash.c + * ---------- + * Keystore implementation in flash memory. + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hal.h" +#include "hal_internal.h" + +static hal_ks_keydb_t *db; + +const hal_ks_keydb_t *hal_ks_get_keydb(void) +{ + +#error Not sure what goes here yet + +} + +hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key, + const int loc) +{ + if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || key->in_use) + return HAL_ERROR_BAD_ARGUMENTS; + +#error Not sure what goes here yet either + +} + +hal_error_t hal_ks_del_keydb(const int loc) +{ + if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys)) + return HAL_ERROR_BAD_ARGUMENTS; + +#error Or what goes here + +} + +hal_error_t hal_ks_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin) +{ + if (pin == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + hal_ks_pin_t *p = NULL; + + switch (user) { + case HAL_USER_WHEEL: p = &db->wheel_pin; break; + case HAL_USER_SO: p = &db->so_pin; break; + case HAL_USER_NORMAL: p = &db->user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; + } + +#error Or what goes here + + return HAL_OK; +} + + +hal_error_t hal_ks_get_kek(uint8_t *kek, + size_t *kek_len, + const size_t kek_max) +{ + if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) + return HAL_ERROR_BAD_ARGUMENTS; + + const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : + (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : + bitsToBytes(256)); + +#error Or what goes here + + return HAL_OK; +} + + + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/ks_mmap.c b/ks_mmap.c new file mode 100644 index 0000000..5eb2a13 --- /dev/null +++ b/ks_mmap.c @@ -0,0 +1,179 @@ +/* + * ks_mmap.c + * --------- + * Keystore implementation over POSIX mmap(). + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <string.h> +#include <sys/errno.h> +#include <unistd.h> + +#include "hal.h" +#include "hal_internal.h" + +#ifndef HAL_KS_MMAP_FILE +#define HAL_KS_MMAP_FILE ".cryptech_hal_keystore" +#endif + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +/* + * Storing the KEK in with the keys it's protecting is a bad idea, but we have no better + * place to put it (real protection requires dedicated hardware, which we don't have here). + */ + +#define KEKBUF_LEN (bitsToBytes(256)) + +static hal_ks_keydb_t *db; +static uint8_t *kekbuf; + +const hal_ks_keydb_t *hal_ks_get_keydb(void) +{ + if (db != NULL) + return db; + + const char * const env = getenv("CRYPTECH_KEYSTORE"); + const char * const home = getenv("HOME"); + const char * const base = HAL_KS_MMAP_FILE; + const long pagemask = sysconf(_SC_PAGESIZE) - 1; + const size_t len = (sizeof(hal_ks_keydb_t) + KEKBUF_LEN + pagemask) & ~pagemask; + + char fn_[strlen(base) + (home == NULL ? 0 : strlen(home)) + 2]; + const char *fn = fn_; + int fd; + + if (pagemask < 0) + return NULL; + + if (env != NULL) + fn = env; + else if (home == NULL) + fn = base; + else + strcat(strcat(strcpy(fn_, home), "/"), base); + + if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) { + uint8_t zeros[len]; + memset(zeros, 0, sizeof(zeros)); + (void) write(fd, zeros, sizeof(zeros)); + } + else if (errno == EEXIST) { + fd = open(fn, O_RDWR | O_CREAT, 0600); + } + + if (fd >= 0 && (db = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0)) != NULL) + kekbuf = (uint8_t *) (db + 1); + + (void) close(fd); + + return db; +} + +hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key, + const int loc) +{ + if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || key->in_use) + return HAL_ERROR_BAD_ARGUMENTS; + + db->keys[loc] = *key; + db->keys[loc].in_use = 1; + return HAL_OK; +} + +hal_error_t hal_ks_del_keydb(const int loc) +{ + if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys)) + return HAL_ERROR_BAD_ARGUMENTS; + + db->keys[loc].in_use = 0; + memset(&db->keys[loc], 0, sizeof(db->keys[loc])); + return HAL_OK; +} + +hal_error_t hal_ks_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin) +{ + if (pin == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + hal_ks_pin_t *p = NULL; + + switch (user) { + case HAL_USER_WHEEL: p = &db->wheel_pin; break; + case HAL_USER_SO: p = &db->so_pin; break; + case HAL_USER_NORMAL: p = &db->user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; + } + + *p = *pin; + return HAL_OK; +} + +hal_error_t hal_ks_get_kek(uint8_t *kek, + size_t *kek_len, + const size_t kek_max) +{ + if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) + return HAL_ERROR_BAD_ARGUMENTS; + + if (kekbuf == NULL) + return HAL_ERROR_IMPOSSIBLE; + + hal_error_t err; + + const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : + (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : + bitsToBytes(256)); + + uint8_t t = 0; + + for (int i = 0; i < KEKBUF_LEN; i++) + t |= kekbuf[i]; + + if (t == 0 && (err = hal_rpc_get_random(kekbuf, sizeof(KEKBUF_LEN))) != HAL_OK) + return err; + + memcpy(kek, kekbuf, len); + *kek_len = len; + return HAL_OK; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/ks_volatile.c b/ks_volatile.c new file mode 100644 index 0000000..9a47d52 --- /dev/null +++ b/ks_volatile.c @@ -0,0 +1,143 @@ +/* + * ks_volatile.c + * ------------- + * Keystore implementation in normal volatile internal memory. + * + * NB: This is only suitable for cases where you do not want the keystore + * to survive library exit, eg, for storing PKCS #11 session keys. + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +#include "hal.h" +#include "hal_internal.h" + +/* + * Splitting the different keystore backends out into separate files + * seemed like a good idea at the time, but the code is getting + * somewhat repetitive. Might want to re-merge and conditionalize in + * some other way. Deferred until we sort out ks_flash.c. + */ + +/* + * Use a one-element array here so that references can be pointer-based + * as in the other implementations, to ease re-merge at some later date. + */ + +static hal_ks_keydb_t db[1]; + +/* + * There's no good place to store the master key (KEK) in this volatile memory implementation. + * We might be able to add a bit of protection doing things like using locked physical memory, + * as gpg does, or obfuscating the KEK a bit to make it harder to pull out of a crash dump, + * but, really, there's not a lot we can do against a determined opponant in this case. + * + * For now, we just go through the motions. + */ + +static uint8_t kekbuf[bitsToBytes(256)]; + +const hal_ks_keydb_t *hal_ks_get_keydb(void) +{ + return db; +} + +hal_error_t hal_ks_set_keydb(const hal_ks_key_t * const key, + const int loc) +{ + if (key == NULL || loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys) || key->in_use) + return HAL_ERROR_BAD_ARGUMENTS; + + db->keys[loc] = *key; + db->keys[loc].in_use = 1; + return HAL_OK; +} + +hal_error_t hal_ks_del_keydb(const int loc) +{ + if (loc < 0 || loc >= sizeof(db->keys)/sizeof(*db->keys)) + return HAL_ERROR_BAD_ARGUMENTS; + + memset(&db->keys[loc], 0, sizeof(db->keys[loc])); + return HAL_OK; +} + +hal_error_t hal_ks_set_pin(const hal_user_t user, + const hal_ks_pin_t * const pin) +{ + if (pin == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + hal_ks_pin_t *p = NULL; + + switch (user) { + case HAL_USER_WHEEL: p = &db->wheel_pin; break; + case HAL_USER_SO: p = &db->so_pin; break; + case HAL_USER_NORMAL: p = &db->user_pin; break; + default: return HAL_ERROR_BAD_ARGUMENTS; + } + + *p = *pin; + return HAL_OK; +} + +hal_error_t hal_ks_get_kek(uint8_t *kek, + size_t *kek_len, + const size_t kek_max) +{ + if (kek == NULL || kek_len == NULL || kek_max < bitsToBytes(128)) + return HAL_ERROR_BAD_ARGUMENTS; + + hal_error_t err; + + const size_t len = ((kek_max < bitsToBytes(192)) ? bitsToBytes(128) : + (kek_max < bitsToBytes(256)) ? bitsToBytes(192) : + bitsToBytes(256)); + + uint8_t t = 0; + + for (int i = 0; i < sizeof(kekbuf); i++) + t |= kekbuf[i]; + + if (t == 0 && (err = hal_rpc_get_random(kekbuf, sizeof(kekbuf))) != HAL_OK) + return err; + + memcpy(kek, kekbuf, len); + *kek_len = len; + return HAL_OK; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ @@ -46,7 +46,7 @@ #include <assert.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" /* * Whether we want debug output. @@ -39,7 +39,7 @@ #include <stdint.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" /* * Utility to encapsulate the HMAC operations. May need refactoring diff --git a/rpc_api.c b/rpc_api.c new file mode 100644 index 0000000..b2701a5 --- /dev/null +++ b/rpc_api.c @@ -0,0 +1,323 @@ +/* + * hal_rpc.c + * --------- + * Remote procedure call public API implementation. + * + * Authors: Rob Austein + * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hal.h" +#include "hal_internal.h" + +const hal_hash_handle_t hal_hash_handle_none = {HAL_HANDLE_NONE}; + +static inline int check_pkey_type(const hal_key_type_t type) +{ + switch (type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PUBLIC: + case HAL_KEY_TYPE_EC_PRIVATE: + case HAL_KEY_TYPE_EC_PUBLIC: + return 1; + default: + return 0; + } +} + +static inline int check_pkey_flags(const hal_key_flags_t flags) +{ + return (flags &~ (HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT | + HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT)) == 0; +} + +static inline int check_pkey_type_curve_flags(const hal_key_type_t type, + const hal_curve_name_t curve, + const hal_key_flags_t flags) +{ + if (!check_pkey_flags(flags)) + return 0; + + switch (type) { + + case HAL_KEY_TYPE_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PUBLIC: + return curve == HAL_CURVE_NONE; + + case HAL_KEY_TYPE_EC_PRIVATE: + case HAL_KEY_TYPE_EC_PUBLIC: + switch (curve) { + case HAL_CURVE_P256: + case HAL_CURVE_P384: + case HAL_CURVE_P521: + return 1; + default: + return 0; + } + + default: + return 0; + } +} + + +hal_error_t hal_rpc_get_version(uint32_t *version) +{ + return hal_rpc_misc_dispatch->get_version(version); +} + +hal_error_t hal_rpc_get_random(void *buffer, const size_t length) +{ + if (buffer == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + if (length == 0) + return HAL_OK; + return hal_rpc_misc_dispatch->get_random(buffer, length); +} + +#warning Perhaps we should be enforcing a minimum PIN length here + +hal_error_t hal_rpc_set_pin(const hal_client_handle_t client, + const hal_user_t user, + const char * const newpin, const size_t newpin_len) +{ + if (newpin == NULL || newpin_len == 0 || (user != HAL_USER_NORMAL && user != HAL_USER_SO && user != HAL_USER_WHEEL)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_misc_dispatch->set_pin(client, user, newpin, newpin_len); +} + +hal_error_t hal_rpc_login(const hal_client_handle_t client, + const hal_user_t user, + const char * const pin, const size_t pin_len) +{ + if (pin == NULL || pin_len == 0 || (user != HAL_USER_NORMAL && user != HAL_USER_SO && user != HAL_USER_WHEEL)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_misc_dispatch->login(client, user, pin, pin_len); +} + +hal_error_t hal_rpc_logout(const hal_client_handle_t client) +{ + return hal_rpc_misc_dispatch->logout(client); +} + +hal_error_t hal_rpc_logout_all(void) +{ + return hal_rpc_misc_dispatch->logout_all(); +} + +hal_error_t hal_rpc_is_logged_in(const hal_client_handle_t client, + const hal_user_t user) +{ + if (user != HAL_USER_NORMAL && user != HAL_USER_SO && user != HAL_USER_WHEEL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_misc_dispatch->is_logged_in(client, user); +} + +hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, size_t *length) +{ + if (length == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_hash_dispatch->get_digest_length(alg, length); +} + +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) +{ + return hal_rpc_hash_dispatch->get_digest_algorithm_id(alg, id, len, len_max); +} + +hal_error_t hal_rpc_hash_get_algorithm(const hal_hash_handle_t hash, hal_digest_algorithm_t *alg) +{ + if (hash.handle == HAL_HANDLE_NONE || alg == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_hash_dispatch->get_algorithm(hash, alg); +} + +hal_error_t hal_rpc_hash_initialize(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_len) +{ + if (hash == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_hash_dispatch->initialize(client, session, hash, alg, key, key_len); +} + +hal_error_t hal_rpc_hash_update(const hal_hash_handle_t hash, + const uint8_t * data, const size_t length) +{ + if (hash.handle == HAL_HANDLE_NONE || data == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + if (length == 0) + return HAL_OK; + return hal_rpc_hash_dispatch->update(hash, data, length); +} + +hal_error_t hal_rpc_hash_finalize(const hal_hash_handle_t hash, + uint8_t *digest, const size_t length) +{ + if (hash.handle == HAL_HANDLE_NONE || digest == NULL || length == 0) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_hash_dispatch->finalize(hash, digest, length); +} + +hal_error_t hal_rpc_pkey_load(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const hal_curve_name_t curve, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + const hal_key_flags_t flags) +{ + if (pkey == NULL || + name == NULL || name_len == 0 || + der == NULL || der_len == 0 || + !check_pkey_type_curve_flags(type, curve, flags)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->load(client, session, pkey, type, curve, name, name_len, der, der_len, flags); +} + +hal_error_t hal_rpc_pkey_find(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len) +{ + if (pkey == NULL || name == NULL || name_len == 0 || !check_pkey_type(type)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->find(client, session, pkey, type, name, name_len); +} + +hal_error_t hal_rpc_pkey_generate_rsa(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const unsigned key_len, + const uint8_t * const exp, const size_t exp_len, + const hal_key_flags_t flags) +{ + if (pkey == NULL || name == NULL || name_len == 0 || key_len == 0 || (key_len & 7) != 0 || + exp == NULL || exp_len == 0 || !check_pkey_flags(flags)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->generate_rsa(client, session, pkey, name, name_len, key_len, exp, exp_len, flags); +} + +hal_error_t hal_rpc_pkey_generate_ec(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const hal_curve_name_t curve, + const hal_key_flags_t flags) +{ + if (pkey == NULL || name == NULL || name_len == 0 || + !check_pkey_type_curve_flags(HAL_KEY_TYPE_EC_PRIVATE, curve, flags)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->generate_ec(client, session, pkey, name, name_len, curve, flags); +} + +hal_error_t hal_rpc_pkey_close(const hal_pkey_handle_t pkey) +{ + return hal_rpc_pkey_dispatch->close(pkey); +} + +hal_error_t hal_rpc_pkey_delete(const hal_pkey_handle_t pkey) +{ + return hal_rpc_pkey_dispatch->delete(pkey); +} + +hal_error_t hal_rpc_pkey_get_key_type(const hal_pkey_handle_t pkey, + hal_key_type_t *type) +{ + if (type == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->get_key_type(pkey, type); +} + +hal_error_t hal_rpc_pkey_get_key_flags(const hal_pkey_handle_t pkey, + hal_key_flags_t *flags) +{ + if (flags == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->get_key_flags(pkey, flags); +} + +size_t hal_rpc_pkey_get_public_key_len(const hal_pkey_handle_t pkey) +{ + return hal_rpc_pkey_dispatch->get_public_key_len(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) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->get_public_key(pkey, der, der_len, der_max); +} + +hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + if (signature == NULL || signature_len == NULL || signature_max == 0 || + (hash.handle == HAL_HANDLE_NONE) == (input == NULL || input_len == 0)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->sign(session, pkey, hash, input, input_len, signature, signature_len, signature_max); +} + +hal_error_t hal_rpc_pkey_verify(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + if (signature == NULL || signature_len == 0 || + (hash.handle == HAL_HANDLE_NONE) == (input == NULL || input_len == 0)) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->verify(session, pkey, hash, input, input_len, signature, signature_len); +} + +hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max) +{ + if (result == NULL || result_len == NULL || result_max == 0) + return HAL_ERROR_BAD_ARGUMENTS; + return hal_rpc_pkey_dispatch->list(result, result_len, result_max); +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_client.c b/rpc_client.c new file mode 100644 index 0000000..5aededc --- /dev/null +++ b/rpc_client.c @@ -0,0 +1,813 @@ +/* + * rpc_client.c + * ------------ + * Remote procedure call client-side private API implementation. + * + * Authors: Rob Austein, Paul Selkirk + * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> + +#include "hal.h" +#include "hal_internal.h" +#include "xdr_internal.h" + +/* + * RPC calls. + */ + +#define check(op) do { const hal_error_t _err_ = (op); if (_err_ != HAL_OK) return _err_; } while (0) + +#define pad(n) (((n) + 3) & ~3) + +#define nargs(n) ((n) * 4) + +#if RPC_CLIENT != RPC_CLIENT_LOCAL + +static hal_error_t get_version(uint32_t *version) +{ + uint8_t outbuf[nargs(1)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_VERSION)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, version)); + } + return rpc_ret; +} + +static hal_error_t get_random(void *buffer, const size_t length) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(length)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t rcvlen = length; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_RANDOM)); + check(hal_xdr_encode_int(&optr, olimit, (uint32_t)length)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_buffer(&iptr, ilimit, buffer, &rcvlen)); + // XXX check rcvlen vs length + } + return rpc_ret; +} + +static hal_error_t set_pin(const hal_client_handle_t client, + const hal_user_t user, + const char * const pin, const size_t pin_len) +{ + uint8_t outbuf[nargs(4) + pad(pin_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_SET_PIN)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, user)); + check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +/* + * We may end up wanting to wrap a client-side cache around the + * login()/logout()/logout_all() calls and reimplement is_logged_in() + * on the client side using that cache, so that access checks don't + * need to cross the RPC boundary. Then again, we might not, if the + * RPC call is fast enough, so implementing all before the RPC would + * qualify as premature optimization. There aren't all that many + * things on the client side that would use this anyway, so the whole + * question may be moot. + * + * For now, we leave all of these as plain RPC calls, but we may want + * to revisit this if the is_logged_in() call turns into a bottleneck. + */ + +static hal_error_t login(const hal_client_handle_t client, + const hal_user_t user, + const char * const pin, const size_t pin_len) +{ + uint8_t outbuf[nargs(4) + pad(pin_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGIN)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, user)); + check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t logout(const hal_client_handle_t client) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t logout_all(void) +{ + uint8_t outbuf[nargs(1)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT_ALL)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t is_logged_in(const hal_client_handle_t client, + const hal_user_t user) +{ + uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_IS_LOGGED_IN)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, user)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t hash_get_digest_len(const hal_digest_algorithm_t alg, size_t *length) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t len32; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN)); + check(hal_xdr_encode_int(&optr, olimit, alg)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &len32)); + *length = (size_t)len32; + } + return rpc_ret; +} + +static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg, + uint8_t *id, size_t *len, const size_t len_max) +{ + uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(len_max)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t len32 = len_max; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN)); + check(hal_xdr_encode_int(&optr, olimit, alg)); + check(hal_xdr_encode_int(&optr, olimit, len_max)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_buffer(&iptr, ilimit, id, &len32)); + *len = len32; + } + return rpc_ret; +} + +static hal_error_t hash_get_algorithm(const hal_hash_handle_t hash, hal_digest_algorithm_t *alg) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t alg32; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_ALGORITHM)); + check(hal_xdr_encode_int(&optr, olimit, hash.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &alg32)); + *alg = (hal_digest_algorithm_t)alg32; + } + return rpc_ret; +} + +static hal_error_t hash_initialize(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_len) +{ + uint8_t outbuf[nargs(5) + pad(key_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_INITIALIZE)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_int(&optr, olimit, alg)); + check(hal_xdr_encode_buffer(&optr, olimit, key, key_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &hash->handle)); + } + return rpc_ret; +} + +static hal_error_t hash_update(const hal_hash_handle_t hash, + const uint8_t * data, const size_t length) +{ + uint8_t outbuf[nargs(3) + pad(length)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_UPDATE)); + check(hal_xdr_encode_int(&optr, olimit, hash.handle)); + check(hal_xdr_encode_buffer(&optr, olimit, data, length)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t hash_finalize(const hal_hash_handle_t hash, + uint8_t *digest, const size_t length) +{ + uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(length)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t digest_len = length; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_FINALIZE)); + check(hal_xdr_encode_int(&optr, olimit, hash.handle)); + check(hal_xdr_encode_int(&optr, olimit, length)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_buffer(&iptr, ilimit, digest, &digest_len)); + /* XXX check digest_len vs length */ + } + return rpc_ret; +} + +static hal_error_t pkey_load(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const hal_curve_name_t curve, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + const hal_key_flags_t flags) +{ + uint8_t outbuf[nargs(8) + pad(name_len) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_int(&optr, olimit, type)); + check(hal_xdr_encode_int(&optr, olimit, curve)); + check(hal_xdr_encode_buffer(&optr, olimit, name, name_len)); + check(hal_xdr_encode_buffer(&optr, olimit, der, der_len)); + check(hal_xdr_encode_int(&optr, olimit, flags)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) + check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle)); + + return rpc_ret; +} + +static hal_error_t pkey_find(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len) +{ + uint8_t outbuf[nargs(5) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_FIND)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_int(&optr, olimit, type)); + check(hal_xdr_encode_buffer(&optr, olimit, name, name_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) + check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle)); + + return rpc_ret; +} + +static hal_error_t pkey_generate_rsa(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const unsigned key_len, + const uint8_t * const exp, const size_t exp_len, + const hal_key_flags_t flags) +{ + uint8_t outbuf[nargs(7) + pad(name_len) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_buffer(&optr, olimit, name, name_len)); + check(hal_xdr_encode_int(&optr, olimit, key_len)); + check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len)); + check(hal_xdr_encode_int(&optr, olimit, flags)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) + check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle)); + + return rpc_ret; +} + +static hal_error_t pkey_generate_ec(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const hal_curve_name_t curve, + const hal_key_flags_t flags) +{ + uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC)); + check(hal_xdr_encode_int(&optr, olimit, client.handle)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_buffer(&optr, olimit, name, name_len)); + check(hal_xdr_encode_int(&optr, olimit, curve)); + check(hal_xdr_encode_int(&optr, olimit, flags)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) + check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle)); + + return rpc_ret; +} + +static hal_error_t pkey_close(const hal_pkey_handle_t pkey) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_CLOSE)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t pkey_delete(const hal_pkey_handle_t pkey) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t pkey_get_key_type(const hal_pkey_handle_t pkey, + hal_key_type_t *type) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t type32; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &type32)); + *type = (hal_key_type_t)type32; + } + return rpc_ret; +} + +static hal_error_t pkey_get_key_flags(const hal_pkey_handle_t pkey, + hal_key_flags_t *flags) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t flags32; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_FLAGS)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &flags32)); + *flags = (hal_key_flags_t)flags32; + } + return rpc_ret; +} + +static size_t pkey_get_public_key_len(const hal_pkey_handle_t pkey) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t len32; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_int(&iptr, ilimit, &len32)); + return (size_t)len32; + } + else + return 0; +} + +static hal_error_t pkey_get_public_key(const hal_pkey_handle_t pkey, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(der_max)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t dlen32 = der_max; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, der_max)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_buffer(&iptr, ilimit, der, &dlen32)); + *der_len = (size_t)dlen32; + } + return rpc_ret; +} + +static hal_error_t pkey_remote_sign(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + uint8_t outbuf[nargs(6) + pad(input_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(signature_max)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t slen32 = signature_max; + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_SIGN)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, hash.handle)); + check(hal_xdr_encode_buffer(&optr, olimit, input, input_len)); + check(hal_xdr_encode_int(&optr, olimit, signature_max)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + check(hal_xdr_decode_buffer(&iptr, ilimit, signature, &slen32)); + *signature_len = (size_t)slen32; + } + return rpc_ret; +} + +static hal_error_t pkey_remote_verify(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + uint8_t outbuf[nargs(6) + pad(input_len) + pad(signature_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(1)], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + hal_error_t rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_VERIFY)); + check(hal_xdr_encode_int(&optr, olimit, session.handle)); + check(hal_xdr_encode_int(&optr, olimit, pkey.handle)); + check(hal_xdr_encode_int(&optr, olimit, hash.handle)); + check(hal_xdr_encode_buffer(&optr, olimit, input, input_len)); + check(hal_xdr_encode_buffer(&optr, olimit, signature, signature_len)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + return rpc_ret; +} + +static hal_error_t hal_xdr_decode_pkey_info(uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info) +{ + uint32_t i32; + + check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->type = i32; + check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->curve = i32; + check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->flags = i32; + check(hal_xdr_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32; + return HAL_OK; +} + +static hal_error_t pkey_list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max) +{ + uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf); + uint8_t inbuf[nargs(2) + pad(result_max * sizeof(hal_pkey_info_t))], *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf); + size_t ilen = sizeof(inbuf); + uint32_t len; + hal_error_t ret, rpc_ret; + + check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LIST)); + check(hal_xdr_encode_int(&optr, olimit, result_max)); + check(hal_rpc_send(outbuf, optr - outbuf)); + + check(hal_rpc_recv(inbuf, &ilen)); + assert(ilen <= sizeof(inbuf)); + check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret)); + if (rpc_ret == HAL_OK) { + int i; + check(hal_xdr_decode_int(&iptr, ilimit, &len)); + *result_len = len; + for (i = 0; i < len; ++i) { + if ((ret = hal_xdr_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) { + *result_len = 0; + return ret; + } + } + } + return rpc_ret; +} + + +/* + * "Mixed" mode pkey operations, where the public key operation itself + * takes place on the HSM but the hashing takes place locally. If + * we're given a hash context in this case, it's local, so we have to + * pull the digest from the hash context and send that to the HSM. + */ + +static hal_error_t pkey_mixed_sign(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + if (input != NULL) + return pkey_remote_sign(session, pkey, hash, input, input_len, + signature, signature_len, signature_max); + + hal_digest_algorithm_t alg; + size_t digest_len; + hal_error_t err; + + if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK || + (err = hal_rpc_hash_get_digest_length(alg, &digest_len)) != HAL_OK) + return err; + + uint8_t digest[digest_len]; + + if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK) + return err; + + return pkey_remote_sign(session, pkey, hal_hash_handle_none, digest, digest_len, + signature, signature_len, signature_max); +} + +static hal_error_t pkey_mixed_verify(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + if (input != NULL) + return pkey_remote_verify(session, pkey, hash, input, input_len, + signature, signature_len); + + hal_digest_algorithm_t alg; + size_t digest_len; + hal_error_t err; + + if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK || + (err = hal_rpc_hash_get_digest_length(alg, &digest_len)) != HAL_OK) + return err; + + uint8_t digest[digest_len]; + + if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK) + return err; + + return pkey_remote_verify(session, pkey, hal_hash_handle_none, digest, digest_len, + signature, signature_len); +} + +/* + * Dispatch vectors. + */ + +const hal_rpc_misc_dispatch_t hal_rpc_remote_misc_dispatch = { + set_pin, login, logout, logout_all, is_logged_in, get_random, get_version +}; + +const hal_rpc_hash_dispatch_t hal_rpc_remote_hash_dispatch = { + hash_get_digest_len, hash_get_digest_algorithm_id, hash_get_algorithm, + hash_initialize, hash_update, hash_finalize +}; + +const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = { + pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_close, pkey_delete, + pkey_get_key_type, pkey_get_key_flags, pkey_get_public_key_len, pkey_get_public_key, + pkey_remote_sign, pkey_remote_verify, + pkey_list +}; + +const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = { + pkey_load, pkey_find, pkey_generate_rsa, pkey_generate_ec, pkey_close, pkey_delete, + pkey_get_key_type, pkey_get_key_flags, pkey_get_public_key_len, pkey_get_public_key, + pkey_mixed_sign, pkey_mixed_verify, + pkey_list +}; + +#endif /* RPC_CLIENT != RPC_CLIENT_LOCAL */ + +#if RPC_CLIENT == RPC_CLIENT_LOCAL +const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_local_misc_dispatch; +const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch; +const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispatch; +#elif RPC_CLIENT == RPC_CLIENT_REMOTE +const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch; +const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch; +const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_remote_pkey_dispatch; +#elif RPC_CLIENT == RPC_CLIENT_MIXED +const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch; +const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch; +const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_mixed_pkey_dispatch; +#endif + +hal_error_t hal_rpc_client_init(void) +{ +#if RPC_CLIENT == RPC_CLIENT_LOCAL + return HAL_OK; +#else + return hal_rpc_client_transport_init(); +#endif +} + +hal_error_t hal_rpc_client_close(void) +{ +#if RPC_CLIENT == RPC_CLIENT_LOCAL + return HAL_OK; +#else + return hal_rpc_client_transport_close(); +#endif +} + + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_client_loopback.c b/rpc_client_loopback.c new file mode 100644 index 0000000..b31bdd2 --- /dev/null +++ b/rpc_client_loopback.c @@ -0,0 +1,85 @@ +/* + * rpc_client_loopback.c + * --------------------- + * Remote procedure call transport over loopback socket. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> /* close */ + +#include "hal.h" +#include "hal_internal.h" + +static int sock = -1; + +hal_error_t hal_rpc_client_transport_init(void) +{ + struct sockaddr_in sin; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return perror("socket"), HAL_ERROR_RPC_TRANSPORT; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = 17425; + if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) != 0) + return perror("connect"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_client_transport_close(void) +{ + int ret = close(sock); + sock = -1; + if (ret != 0) + return perror("close"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len) +{ + if (send(sock, buf, len, 0) == -1) + return perror("send"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len) +{ + int ret; + + if ((ret = recv(sock, buf, *len, 0)) == -1) + return HAL_ERROR_RPC_TRANSPORT; + *len = ret; + return HAL_OK; +} diff --git a/rpc_client_serial.c b/rpc_client_serial.c new file mode 100644 index 0000000..d6bda1d --- /dev/null +++ b/rpc_client_serial.c @@ -0,0 +1,116 @@ +/* + * rpc_client_serial.c + * ------------------- + * Remote procedure call transport over serial line with SLIP framing. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> + +#include "hal.h" +#include "hal_internal.h" +#include "slip_internal.h" + +#define DEVICE "/dev/ttyUSB0" +#define SPEED B115200 + +static int fd = -1; + +hal_error_t hal_rpc_client_transport_init(void) +{ + struct termios tty; + + fd = open(DEVICE, O_RDWR | O_NOCTTY | O_SYNC); + if (fd == -1) + return perror("open"), HAL_ERROR_RPC_TRANSPORT; + + if (tcgetattr (fd, &tty) != 0) + return perror("tcgetattr"), HAL_ERROR_RPC_TRANSPORT; + + cfsetospeed (&tty, SPEED); + cfsetispeed (&tty, SPEED); + + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= (CS8 | CLOCAL | CREAD); + + tty.c_iflag = 0; + tty.c_oflag = 0; + tty.c_lflag = 0; + + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + if (tcsetattr (fd, TCSANOW, &tty) != 0) + return perror("tcsetattr"), HAL_ERROR_RPC_TRANSPORT; + + return HAL_OK; +} + +hal_error_t hal_rpc_client_transport_close(void) +{ + int ret = close(fd); + fd = -1; + if (ret != 0) + return perror("close"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_send(const uint8_t * const buf, const size_t len) +{ + if (hal_slip_send(buf, len) == -1) + return HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_recv(uint8_t * const buf, size_t * const len) +{ + int ret; + + if ((ret = hal_slip_recv(buf, *len)) == -1) + return HAL_ERROR_RPC_TRANSPORT; + *len = ret; + return HAL_OK; +} + +int hal_slip_send_char(const uint8_t c) +{ + return write(fd, &c, 1); +} + +int hal_slip_recv_char(uint8_t * const c) +{ + return read(fd, c, 1); +} diff --git a/rpc_hash.c b/rpc_hash.c new file mode 100644 index 0000000..3c4c79b --- /dev/null +++ b/rpc_hash.c @@ -0,0 +1,313 @@ +/* + * rpc_hash.c + * ---------- + * Remote procedure call server-side hash implementation. + * + * Authors: Rob Austein + * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +#include "hal.h" +#include "hal_internal.h" + +/* + * Need table and handle allocation, including some kind of in_use + * flag (perhaps just handle == none). + * + * Hash and HMAC aren't really things for which we need permission + * bits, so not sure we even care about login stuff here. + */ + +typedef struct { + hal_client_handle_t client_handle; + hal_session_handle_t session_handle; + hal_hash_handle_t hash_handle; + union { + hal_hash_state_t *hash; + hal_hmac_state_t *hmac; + } state; +} handle_slot_t; + +#ifndef HAL_STATIC_HASH_STATE_BLOCKS +#define HAL_STATIC_HASH_STATE_BLOCKS 0 +#endif + +#ifndef HAL_STATIC_HMAC_STATE_BLOCKS +#define HAL_STATIC_HMAC_STATE_BLOCKS 0 +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 +static handle_slot_t hash_handle[HAL_STATIC_HASH_STATE_BLOCKS]; +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 +static handle_slot_t hmac_handle[HAL_STATIC_HMAC_STATE_BLOCKS]; +#endif + +/* + * Handle allocation is simple: we look for an unused (state == NULL) + * slot in the appropriate table, and, assuming we find one, construct + * a composite handle consisting of a flag telling us which table this + * is, the index into the table, and a counter whose sole purpose is + * to keep the same handle from reoccurring anytime soon, to help + * identify use-after-free bugs in calling code. + */ + +#define HANDLE_FLAG_HMAC 0x80000000 + +static inline handle_slot_t *alloc_handle(const int is_hmac) +{ +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 || HAL_STATIC_HMAC_STATE_BLOCKS > 0 + static uint16_t next_glop = 0; + uint32_t glop = ++next_glop << 16; + next_glop %= 0x7FFF; +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + if (!is_hmac) { + for (int i = 0; i < sizeof(hash_handle)/sizeof(*hash_handle); i++) { + if (hash_handle[i].state.hash != NULL) + continue; + hash_handle[i].hash_handle.handle = i | glop; + return &hash_handle[i]; + } + } +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 + if (is_hmac) { + for (int i = 0; i < sizeof(hmac_handle)/sizeof(*hmac_handle); i++) { + if (hmac_handle[i].state.hmac != NULL) + continue; + hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC; + return &hmac_handle[i]; + } + } +#endif + + return NULL; +} + +/* + * Check a caller-supplied handle. Must be in range, in use, and have + * the right glop. Returns slot pointer on success, NULL otherwise. + */ + +static inline handle_slot_t *find_handle(const hal_hash_handle_t handle) +{ +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 || HAL_STATIC_HMAC_STATE_BLOCKS > 0 + const int i = (int) (handle.handle & 0xFFFF); + const int is_hmac = (handle.handle & HANDLE_FLAG_HMAC) != 0; +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + if (!is_hmac && i < sizeof(hash_handle)/sizeof(*hash_handle) && + hash_handle[i].hash_handle.handle == handle.handle && hash_handle[i].state.hash != NULL) + return &hash_handle[i]; +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 + if (is_hmac && i < sizeof(hmac_handle)/sizeof(*hmac_handle) && + hmac_handle[i].hash_handle.handle == handle.handle && hmac_handle[i].state.hmac != NULL) + return &hmac_handle[i]; +#endif + + return NULL; +} + +static inline void free_handle(handle_slot_t *slot) +{ + if (slot != NULL) + /* state is a union, so this this works for hash and hmac */ + slot->state.hash = NULL; +} + +/* + * Translate an algorithm number to a descriptor. + */ + +static inline const hal_hash_descriptor_t *alg_to_descriptor(const hal_digest_algorithm_t alg) +{ + switch (alg) { + case hal_digest_algorithm_sha1: return hal_hash_sha1; + case hal_digest_algorithm_sha256: return hal_hash_sha256; + case hal_digest_algorithm_sha512_224: return hal_hash_sha512_224; + case hal_digest_algorithm_sha512_256: return hal_hash_sha512_256; + case hal_digest_algorithm_sha384: return hal_hash_sha384; + case hal_digest_algorithm_sha512: return hal_hash_sha512; + default: return NULL; + } +} + +/* + * Given a slot pointer, fetch the descriptor. + */ + +static inline const hal_hash_descriptor_t *slot_to_descriptor(const handle_slot_t * const slot) +{ + if (slot == NULL) + return NULL; + + if ((slot->hash_handle.handle & HANDLE_FLAG_HMAC) == 0) + return hal_hash_get_descriptor(slot->state.hash); + else + return hal_hmac_get_descriptor(slot->state.hmac); +} + +/* + * Public API + */ + +static hal_error_t get_digest_length(const hal_digest_algorithm_t alg, size_t *length) +{ + const hal_hash_descriptor_t * const d = alg_to_descriptor(alg); + + if (d == NULL || length == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + *length = d->digest_length; + return HAL_OK; +} + +static hal_error_t get_digest_algorithm_id(const hal_digest_algorithm_t alg, + uint8_t *id, size_t *len, const size_t len_max) +{ + const hal_hash_descriptor_t * const d = alg_to_descriptor(alg); + + if (d == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (len != NULL) + *len = d->digest_algorithm_id_length; + + if (id == NULL) + return HAL_OK; + + if (len_max < d->digest_algorithm_id_length) + return HAL_ERROR_RESULT_TOO_LONG; + + memcpy(id, d->digest_algorithm_id, d->digest_algorithm_id_length); + return HAL_OK; +} + +static hal_error_t get_algorithm(const hal_hash_handle_t handle, hal_digest_algorithm_t *alg) +{ + handle_slot_t *slot = find_handle(handle); + const hal_hash_descriptor_t *descriptor = slot_to_descriptor(slot); + + if (slot == NULL || alg == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (descriptor == NULL) + return HAL_ERROR_IMPOSSIBLE; + + *alg = descriptor->digest_algorithm; + return HAL_OK; +} + +static hal_error_t initialize(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_len) +{ + const hal_hash_descriptor_t *descriptor; + handle_slot_t *slot; + hal_error_t err; + + if (hash == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((descriptor = alg_to_descriptor(alg)) == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((slot = alloc_handle(key_len != 0)) == NULL) + return HAL_ERROR_ALLOCATION_FAILURE; + + slot->client_handle = client; + slot->session_handle = session; + *hash = slot->hash_handle; + + if (key_len == 0) + err = hal_hash_initialize(NULL, descriptor, &slot->state.hash, NULL, 0); + else + err = hal_hmac_initialize(NULL, descriptor, &slot->state.hmac, NULL, 0, key, key_len); + if (err != HAL_OK) + free_handle(slot); + return err; +} + +static hal_error_t update(const hal_hash_handle_t handle, + const uint8_t * data, const size_t length) +{ + handle_slot_t *slot = find_handle(handle); + + if (slot == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((handle.handle & HANDLE_FLAG_HMAC) == 0) + return hal_hash_update(slot->state.hash, data, length); + else + return hal_hmac_update(slot->state.hmac, data, length); +} + +static hal_error_t finalize(const hal_hash_handle_t handle, + uint8_t *digest, const size_t length) +{ + handle_slot_t *slot = find_handle(handle); + hal_error_t err; + + if (slot == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((handle.handle & HANDLE_FLAG_HMAC) == 0) { + err = hal_hash_finalize(slot->state.hash, digest, length); + hal_hash_cleanup(&slot->state.hash); + } + + else { + err = hal_hmac_finalize(slot->state.hmac, digest, length); + hal_hmac_cleanup(&slot->state.hmac); + } + + free_handle(slot); + return err; +} + +const hal_rpc_hash_dispatch_t hal_rpc_local_hash_dispatch = { + get_digest_length, get_digest_algorithm_id, get_algorithm, initialize, update, finalize +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_misc.c b/rpc_misc.c new file mode 100644 index 0000000..c0558da --- /dev/null +++ b/rpc_misc.c @@ -0,0 +1,235 @@ +/* + * rpc_misc.c + * ---------- + * RPC interface to TRNG and PIN functions + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> + +#include "hal.h" +#include "hal_internal.h" + +static hal_error_t get_version(uint32_t *version) +{ + *version = RPC_VERSION; + return HAL_OK; +} + +static hal_error_t get_random(void *buffer, const size_t length) +{ + assert(buffer != NULL && length > 0); + + return hal_get_random(NULL, buffer, length); +} + +/* + * PINs, salt, and iteration count live in the keystore. + * + * We also need a client table in conventional memory (here, probably) + * to record login status. + * + * The USER and SO PINs correspond to PKCS #11. + * + * The WHEEL PIN is the one that's allowed to change the SO PIN. + * + * It's a bit unclear how we should manage changes to the WHEEL PIN. + * Implementing a factory default would be easy enough (just + * pre-compute and compile in a const hal_ks_pin_t), question is + * whether doing so provides anything useful. Certainly adds no real + * security, question is whether it would help prevent accidently + * bricking the HSM right out of the shrink wrap. + * + * More interesting question is whether we should ever allow the WHEEL + * PIN to be changed a second time without toasting the keystore. + */ + +#warning PIN code not yet fully implemented + +typedef struct { + hal_client_handle_t handle; + hal_user_t logged_in; +} client_slot_t; + +#ifndef HAL_PIN_MINIMUM_ITERATIONS +#define HAL_PIN_MINIMUM_ITERATIONS 10000 +#endif + +#ifndef HAL_PIN_DEFAULT_ITERATIONS +#define HAL_PIN_DEFAULT_ITERATIONS 20000 +#endif + +#ifndef HAL_STATIC_CLIENT_STATE_BLOCKS +#define HAL_STATIC_CLIENT_STATE_BLOCKS 10 +#endif + +#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0 +static client_slot_t client_handle[HAL_STATIC_CLIENT_STATE_BLOCKS]; +#endif + +/* + * Client handles are supplied by the application, we don't get to + * pick them, we just store them and associate a login state with + * them. HAL_USER_NONE indicates an empty slot in the table. + */ + +static inline client_slot_t *alloc_slot(void) +{ +#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0 + for (int i = 0; i < sizeof(client_handle)/sizeof(*client_handle); i++) + if (client_handle[i].logged_in == HAL_USER_NONE) + return &client_handle[i]; +#endif + + return NULL; +} + +static inline client_slot_t *find_handle(const hal_client_handle_t handle) +{ +#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0 + for (int i = 0; i < sizeof(client_handle)/sizeof(*client_handle); i++) + if (client_handle[i].logged_in != HAL_USER_NONE && client_handle[i].handle.handle == handle.handle) + return &client_handle[i]; +#endif + + return NULL; +} + +static hal_error_t set_pin(const hal_client_handle_t client, + const hal_user_t user, + const char * const newpin, const size_t newpin_len) +{ + assert(newpin != NULL && newpin_len != 0); + +#warning Need access control to decide who is allowed to set this PIN +#warning Need length checks (here or in caller) on supplied PIN + + const hal_ks_pin_t *pp; + hal_error_t err; + + if ((err = hal_ks_get_pin(user, &pp)) != HAL_OK) + return err; + + hal_ks_pin_t p = *pp; + + if (p.iterations == 0) + p.iterations = HAL_PIN_DEFAULT_ITERATIONS; + + if ((err = hal_get_random(NULL, p.salt, sizeof(p.salt))) != HAL_OK || + (err = hal_pbkdf2(NULL, hal_hash_sha256, + (const uint8_t *) newpin, newpin_len, + p.salt, sizeof(p.salt), + p.pin, sizeof(p.pin), p.iterations)) != HAL_OK || + (err = hal_ks_set_pin(user, &p)) != HAL_OK) + return err; + + return HAL_OK; +} + +static hal_error_t login(const hal_client_handle_t client, + const hal_user_t user, + const char * const pin, const size_t pin_len) +{ + assert(pin != NULL && pin_len != 0); + assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL); + + const hal_ks_pin_t *p; + hal_error_t err; + + if ((err = hal_ks_get_pin(user, &p)) != HAL_OK) + return err; + + uint8_t buf[sizeof(p->pin)]; + + if ((err = hal_pbkdf2(NULL, hal_hash_sha256, (const uint8_t *) pin, pin_len, + p->salt, sizeof(p->salt), buf, sizeof(buf), p->iterations)) != HAL_OK) + return err; + + unsigned diff = 0; + for (int i = 0; i < sizeof(buf); i++) + diff |= buf[i] ^ p->pin[i]; + + if (diff != 0) + return HAL_ERROR_PIN_INCORRECT; + + client_slot_t *slot = find_handle(client); + + if (slot == NULL && (slot = alloc_slot()) == NULL) + return HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE; + + slot->handle = client; + slot->logged_in = user; + + return HAL_OK; +} + +static hal_error_t is_logged_in(const hal_client_handle_t client, + const hal_user_t user) +{ + assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL); + + client_slot_t *slot = find_handle(client); + + if (slot == NULL || slot->logged_in != user) + return HAL_ERROR_FORBIDDEN; + + return HAL_OK; +} + +static hal_error_t logout(const hal_client_handle_t client) +{ + client_slot_t *slot = find_handle(client); + + if (slot != NULL) + slot->logged_in = HAL_USER_NONE; + + return HAL_OK; +} + +static hal_error_t logout_all(void) +{ +#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0 + for (int i = 0; i < sizeof(client_handle)/sizeof(*client_handle); i++) + client_handle[i].logged_in = HAL_USER_NONE; +#endif + + return HAL_OK; +} + +const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch = { + set_pin, login, logout, logout_all, is_logged_in, get_random, get_version +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_pkey.c b/rpc_pkey.c new file mode 100644 index 0000000..3ae8f2a --- /dev/null +++ b/rpc_pkey.c @@ -0,0 +1,837 @@ +/* + * rpc_pkey.c + * ---------- + * Remote procedure call server-side public key implementation. + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> +#include <assert.h> + +#include "hal.h" +#include "hal_internal.h" + +typedef struct { + hal_client_handle_t client_handle; + hal_session_handle_t session_handle; + hal_pkey_handle_t pkey_handle; + hal_key_type_t type; + hal_curve_name_t curve; + hal_key_flags_t flags; + uint8_t name[HAL_RPC_PKEY_NAME_MAX]; + size_t name_len; + int ks_hint; + /* + * This might be where we'd stash a (hal_core_t *) pointing to a + * core which has already been loaded with the key, if we were + * trying to be clever about using multiple signing cores. Moot + * point (ie, no way we could possibly test such a thing) as long as + * the FPGA is too small to hold more than one modexp core and ECDSA + * is entirely software, so skip it for now, but the implied + * semantics are interesting: a pkey handle starts to resemble an + * initialized signing core, and once all the cores are in use, one + * can't load another key without closing an existing pkey handle. + */ +} pkey_slot_t; + +#ifndef HAL_STATIC_PKEY_STATE_BLOCKS +#define HAL_STATIC_PKEY_STATE_BLOCKS 0 +#endif + +#if HAL_STATIC_PKEY_STATE_BLOCKS > 0 +static pkey_slot_t pkey_handle[HAL_STATIC_PKEY_STATE_BLOCKS]; +#endif + +/* + * Handle allocation is simple: we look for an unused (name_len == 0) + * slot in the table, and, assuming we find one, construct a composite + * handle consisting of the index into the table and a counter whose + * sole purpose is to keep the same handle from reoccurring anytime + * soon, to help identify use-after-free bugs in calling code. + */ + +static inline pkey_slot_t *alloc_slot(void) +{ +#if HAL_STATIC_PKEY_STATE_BLOCKS > 0 + static uint16_t next_glop = 0; + uint32_t glop = ++next_glop << 16; + next_glop %= 0xFFFF; + + for (int i = 0; i < sizeof(pkey_handle)/sizeof(*pkey_handle); i++) { + if (pkey_handle[i].name_len > 0) + continue; + pkey_handle[i].pkey_handle.handle = i | glop; + pkey_handle[i].ks_hint = -1; + return &pkey_handle[i]; + } +#endif + + return NULL; +} + +/* + * Check a caller-supplied handle. Must be in range, in use, and have + * the right glop. Returns slot pointer on success, NULL otherwise. + */ + +static inline pkey_slot_t *find_handle(const hal_pkey_handle_t handle) +{ +#if HAL_STATIC_PKEY_STATE_BLOCKS > 0 + const int i = (int) (handle.handle & 0xFFFF); + + if (i < sizeof(pkey_handle)/sizeof(*pkey_handle) && pkey_handle[i].pkey_handle.handle == handle.handle) + return &pkey_handle[i]; +#endif + + return NULL; +} + +/* + * Construct a PKCS #1 DigestInfo object. This requires some (very + * basic) ASN.1 encoding, which we perform inline. + */ + +static hal_error_t pkcs1_construct_digestinfo(const hal_hash_handle_t handle, + uint8_t *digest_info, size_t *digest_info_len, const size_t digest_info_max) +{ + assert(digest_info != NULL && digest_info_len != NULL); + + hal_digest_algorithm_t alg; + size_t len, alg_len; + hal_error_t err; + + if ((err = hal_rpc_hash_get_algorithm(handle, &alg)) != HAL_OK || + (err = hal_rpc_hash_get_digest_length(alg, &len)) != HAL_OK || + (err = hal_rpc_hash_get_digest_algorithm_id(alg, NULL, &alg_len, 0)) != HAL_OK) + return err; + + *digest_info_len = len + alg_len + 4; + + if (*digest_info_len >= digest_info_max) + return HAL_ERROR_RESULT_TOO_LONG; + + assert(*digest_info_len < 130); + + uint8_t *d = digest_info; + + *d++ = 0x30; /* SEQUENCE */ + *d++ = (uint8_t) (*digest_info_len - 2); + + if ((err = hal_rpc_hash_get_digest_algorithm_id(alg, d, NULL, alg_len)) != HAL_OK) + return err; + d += alg_len; + + *d++ = 0x04; /* OCTET STRING */ + *d++ = (uint8_t) len; + + assert(digest_info + *digest_info_len == d + len); + + return hal_rpc_hash_finalize(handle, d, len); +} + +/* + * Pad an octet string with PKCS #1.5 padding for use with RSA. + * + * For the moment, this only handles type 01 encryption blocks, thus + * is only suitable for use with signature and verification. If and + * when we add support for encryption and decryption, this function + * should be extended to take an argument specifying the block type + * and include support for generating type 02 encryption blocks. + * Other than the block type code, the only difference is the padding + * value: for type 01 it's constant (0xFF), for type 02 it should be + * non-zero random bytes from the CSPRNG. + * + * We use memmove() instead of memcpy() so that the caller can + * construct the data to be padded in the same buffer. + */ + +static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len, + uint8_t *block, const size_t block_len) +{ + assert(data != NULL && block != NULL); + + /* + * Congregation will now please turn to RFC 2313 8.1 as we + * construct a PKCS #1.5 type 01 encryption block. + */ + + if (data_len > block_len - 11) + return HAL_ERROR_RESULT_TOO_LONG; + + memmove(block + block_len - data_len, data, data_len); + + block[0] = 0x00; + block[1] = 0x01; + + /* This is where we'd use non-zero random bytes if constructing a type 02 block. */ + memset(block + 2, 0xFF, block_len - 3 - data_len); + + block[block_len - data_len - 1] = 0x00; + + return HAL_OK; +} + +/* + * Receive key from application, store it with supplied name, return a key handle. + */ + +static hal_error_t load(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const hal_curve_name_t curve, + const uint8_t * const name, const size_t name_len, + const uint8_t * const der, const size_t der_len, + const hal_key_flags_t flags) +{ + pkey_slot_t *slot; + hal_error_t err; + + assert(sizeof(slot->name) >= name_len && pkey != NULL); + + if ((slot = alloc_slot()) == NULL) + return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; + + if ((err = hal_ks_store(type, curve, flags, name, name_len, der, der_len, &slot->ks_hint)) != HAL_OK) + return err; + + memcpy(slot->name, name, name_len); + slot->client_handle = client; + slot->session_handle = session; + slot->type = type; + slot->curve = curve; + slot->flags = flags; + slot->name_len = name_len; + + *pkey = slot->pkey_handle; + return HAL_OK; +} + +/* + * Look up a key given its name, return a key handle. + */ + +static hal_error_t find(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const hal_key_type_t type, + const uint8_t * const name, const size_t name_len) +{ + pkey_slot_t *slot; + hal_error_t err; + + assert(sizeof(slot->name) >= name_len && pkey != NULL); + + if ((slot = alloc_slot()) == NULL) + return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; + + if ((err = hal_ks_fetch(type, name, name_len, &slot->curve, &slot->flags, NULL, NULL, 0, &slot->ks_hint)) != HAL_OK) + return err; + + memcpy(slot->name, name, name_len); + slot->client_handle = client; + slot->session_handle = session; + slot->type = type; + slot->name_len = name_len; + + *pkey = slot->pkey_handle; + return HAL_OK; +} + +/* + * Generate a new RSA key with supplied name, return a key handle. + */ + +static hal_error_t generate_rsa(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const unsigned key_length, + const uint8_t * const public_exponent, const size_t public_exponent_len, + const hal_key_flags_t flags) +{ + pkey_slot_t *slot; + hal_error_t err; + + assert(sizeof(slot->name) >= name_len && pkey != NULL && (key_length & 7) == 0); + + if ((slot = alloc_slot()) == NULL) + return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; + + uint8_t keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *key = NULL; + + if ((err = hal_rsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), key_length / 8, + public_exponent, public_exponent_len)) != HAL_OK) + return err; + + uint8_t der[hal_rsa_private_key_to_der_len(key)]; + size_t der_len; + + if ((err = hal_rsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK) + err = hal_ks_store(HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, flags, + name, name_len, der, der_len, &slot->ks_hint); + + memset(keybuf, 0, sizeof(keybuf)); + memset(der, 0, sizeof(der)); + + if (err != HAL_OK) + return err; + + memcpy(slot->name, name, name_len); + slot->client_handle = client; + slot->session_handle = session; + slot->type = HAL_KEY_TYPE_RSA_PRIVATE; + slot->curve = HAL_CURVE_NONE; + slot->flags = flags; + slot->name_len = name_len; + + *pkey = slot->pkey_handle; + return HAL_OK; +} + +/* + * Generate a new EC key with supplied name, return a key handle. + * At the moment, EC key == ECDSA key, but this is subject to change. + */ + +static hal_error_t generate_ec(const hal_client_handle_t client, + const hal_session_handle_t session, + hal_pkey_handle_t *pkey, + const uint8_t * const name, const size_t name_len, + const hal_curve_name_t curve, + const hal_key_flags_t flags) +{ + pkey_slot_t *slot; + hal_error_t err; + + assert(sizeof(slot->name) >= name_len && pkey != NULL); + + if ((slot = alloc_slot()) == NULL) + return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE; + + uint8_t keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *key = NULL; + + if ((err = hal_ecdsa_key_gen(NULL, &key, keybuf, sizeof(keybuf), curve)) != HAL_OK) + return err; + + uint8_t der[hal_ecdsa_private_key_to_der_len(key)]; + size_t der_len; + + if ((err = hal_ecdsa_private_key_to_der(key, der, &der_len, sizeof(der))) == HAL_OK) + err = hal_ks_store(HAL_KEY_TYPE_EC_PRIVATE, curve, flags, + name, name_len, der, der_len, &slot->ks_hint); + + memset(keybuf, 0, sizeof(keybuf)); + memset(der, 0, sizeof(der)); + + if (err != HAL_OK) + return err; + + memcpy(slot->name, name, name_len); + slot->client_handle = client; + slot->session_handle = session; + slot->type = HAL_KEY_TYPE_EC_PRIVATE; + slot->curve = curve; + slot->flags = flags; + slot->name_len = name_len; + + *pkey = slot->pkey_handle; + return HAL_OK; +} + +/* + * Discard key handle, leaving key intact. + */ + +static hal_error_t close(const hal_pkey_handle_t pkey) +{ + pkey_slot_t *slot; + + if ((slot = find_handle(pkey)) == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + memset(slot, 0, sizeof(*slot)); + + return HAL_OK; +} + +/* + * Delete a key from the store, given its key handle. + */ + +static hal_error_t delete(const hal_pkey_handle_t pkey) +{ + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_error_t err = hal_ks_delete(slot->type, slot->name, slot->name_len, &slot->ks_hint); + + if (err == HAL_OK || err == HAL_ERROR_KEY_NOT_FOUND) + memset(slot, 0, sizeof(*slot)); + + return err; +} + +/* + * Get type of key associated with handle. + */ + +static hal_error_t get_key_type(const hal_pkey_handle_t pkey, + hal_key_type_t *type) +{ + if (type == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + *type = slot->type; + + return HAL_OK; +} + +/* + * Get flags of key associated with handle. + */ + +static hal_error_t get_key_flags(const hal_pkey_handle_t pkey, + hal_key_flags_t *flags) +{ + if (flags == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + *flags = slot->flags; + + return HAL_OK; +} + +/* + * Get length of public key associated with handle. + */ + +static size_t get_public_key_len(const hal_pkey_handle_t pkey) +{ + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return 0; + + size_t result = 0; + + uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size]; + hal_rsa_key_t *rsa_key = NULL; + hal_ecdsa_key_t *ecdsa_key = NULL; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + size_t der_len; + + if (hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, + der, &der_len, sizeof(der), &slot->ks_hint) == HAL_OK) { + switch (slot->type) { + + case HAL_KEY_TYPE_RSA_PUBLIC: + case HAL_KEY_TYPE_EC_PUBLIC: + result = der_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; + + 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; + + default: + break; + } + } + + memset(keybuf, 0, sizeof(keybuf)); + memset(der, 0, sizeof(der)); + + return result; +} + +/* + * Get public key associated with handle. + */ + +static hal_error_t get_public_key(const hal_pkey_handle_t pkey, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size]; + hal_rsa_key_t *rsa_key = NULL; + hal_ecdsa_key_t *ecdsa_key = NULL; + uint8_t buf[HAL_KS_WRAPPED_KEYSIZE]; + size_t buf_len; + hal_error_t err; + + if ((err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, + buf, &buf_len, sizeof(buf), &slot->ks_hint)) == HAL_OK) { + switch (slot->type) { + + case HAL_KEY_TYPE_RSA_PUBLIC: + case HAL_KEY_TYPE_EC_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; + + default: + err = HAL_ERROR_UNSUPPORTED_KEY; + break; + } + } + + memset(keybuf, 0, sizeof(keybuf)); + memset(buf, 0, sizeof(buf)); + + return err; +} + +/* + * Sign something using private key associated with handle. + * + * RSA has enough quirks that it's simplest to split this out into + * algorithm-specific functions. + */ + +static hal_error_t sign_rsa(uint8_t *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * input, size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + hal_rsa_key_t *key = NULL; + hal_error_t err; + + assert(signature != NULL && signature_len != NULL); + assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0)); + + if ((err = hal_rsa_private_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK || + (err = hal_rsa_key_get_modulus(key, NULL, signature_len, 0)) != HAL_OK) + return err; + + if (*signature_len > signature_max) + return HAL_ERROR_RESULT_TOO_LONG; + + if (input == NULL) { + if ((err = pkcs1_construct_digestinfo(hash, signature, &input_len, *signature_len)) != HAL_OK) + return err; + input = signature; + } + + if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len)) != HAL_OK || + (err = hal_rsa_decrypt(NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK) + return err; + + return HAL_OK; +} + +static hal_error_t sign_ecdsa(uint8_t *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * input, size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + hal_ecdsa_key_t *key = NULL; + hal_error_t err; + + assert(signature != NULL && signature_len != NULL); + assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0)); + + if ((err = hal_ecdsa_private_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != HAL_OK) + return err; + + if (input == NULL) { + hal_digest_algorithm_t alg; + + if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK || + (err = hal_rpc_hash_get_digest_length(alg, &input_len)) != HAL_OK) + return err; + + if (input_len < signature_max) + return HAL_ERROR_RESULT_TOO_LONG; + + if ((err = hal_rpc_hash_finalize(hash, signature, input_len)) != HAL_OK) + return err; + + input = signature; + } + + if ((err = hal_ecdsa_sign(NULL, key, input, input_len, signature, signature_len, signature_max)) != HAL_OK) + return err; + + return HAL_OK; +} + +static hal_error_t sign(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max) +{ + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_error_t (*signer)(uint8_t *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + uint8_t * signature, size_t *signature_len, const size_t signature_max); + + switch (slot->type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + signer = sign_rsa; + break; + case HAL_KEY_TYPE_EC_PRIVATE: + signer = sign_ecdsa; + break; + default: + return HAL_ERROR_UNSUPPORTED_KEY; + } + + uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size]; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + size_t der_len; + hal_error_t err; + + err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint); + + if (err == HAL_OK) + err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len, signature_max); + + memset(keybuf, 0, sizeof(keybuf)); + memset(der, 0, sizeof(der)); + + return err; +} + +/* + * Verify something using public key associated with handle. + * + * RSA has enough quirks that it's simplest to split this out into + * algorithm-specific functions. + */ + +static hal_error_t verify_rsa(uint8_t *keybuf, const size_t keybuf_len, const hal_key_type_t type, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * input, size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + uint8_t expected[signature_len], received[signature_len]; + hal_rsa_key_t *key = NULL; + hal_error_t err; + + assert(signature != NULL && signature_len > 0); + assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0)); + + switch (type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + err = hal_rsa_private_key_from_der(&key, keybuf, keybuf_len, der, der_len); + break; + case HAL_KEY_TYPE_RSA_PUBLIC: + err = hal_rsa_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) { + if ((err = pkcs1_construct_digestinfo(hash, expected, &input_len, sizeof(expected))) != HAL_OK) + return err; + input = expected; + } + + if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected))) != HAL_OK || + (err = hal_rsa_encrypt(NULL, key, signature, signature_len, received, sizeof(received))) != HAL_OK) + return err; + + unsigned diff = 0; + for (int i = 0; i < signature_len; i++) + diff |= expected[i] ^ received[i]; + + if (diff != 0) + return HAL_ERROR_INVALID_SIGNATURE; + + return HAL_OK; +} + +static hal_error_t verify_ecdsa(uint8_t *keybuf, const size_t keybuf_len, const hal_key_type_t type, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * input, size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + uint8_t digest[signature_len]; + hal_ecdsa_key_t *key = NULL; + hal_error_t err; + + assert(signature != NULL && signature_len > 0); + assert((hash.handle == HAL_HANDLE_NONE) != (input == NULL || input_len == 0)); + + switch (type) { + case HAL_KEY_TYPE_EC_PRIVATE: + err = hal_ecdsa_private_key_from_der(&key, keybuf, keybuf_len, der, der_len); + break; + case HAL_KEY_TYPE_EC_PUBLIC: + err = hal_ecdsa_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) { + hal_digest_algorithm_t alg; + + if ((err = hal_rpc_hash_get_algorithm(hash, &alg)) != HAL_OK || + (err = hal_rpc_hash_get_digest_length(alg, &input_len)) != HAL_OK || + (err = hal_rpc_hash_finalize(hash, digest, sizeof(digest))) != HAL_OK) + return err; + + input = digest; + } + + if ((err = hal_ecdsa_verify(NULL, key, input, input_len, signature, signature_len)) != HAL_OK) + return err; + + return HAL_OK; +} + +static hal_error_t verify(const hal_session_handle_t session, + const hal_pkey_handle_t pkey, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len) +{ + pkey_slot_t *slot = find_handle(pkey); + + if (slot == NULL) + return HAL_ERROR_KEY_NOT_FOUND; + + hal_error_t (*verifier)(uint8_t *keybuf, const size_t keybuf_len, const hal_key_type_t type, + const uint8_t * const der, const size_t der_len, + const hal_hash_handle_t hash, + const uint8_t * const input, const size_t input_len, + const uint8_t * const signature, const size_t signature_len); + + switch (slot->type) { + case HAL_KEY_TYPE_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PUBLIC: + verifier = verify_rsa; + break; + case HAL_KEY_TYPE_EC_PRIVATE: + case HAL_KEY_TYPE_EC_PUBLIC: + verifier = verify_ecdsa; + break; + default: + return HAL_ERROR_UNSUPPORTED_KEY; + } + + uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size]; + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; + size_t der_len; + hal_error_t err; + + err = hal_ks_fetch(slot->type, slot->name, slot->name_len, NULL, NULL, der, &der_len, sizeof(der), &slot->ks_hint); + + if (err == HAL_OK) + err = verifier(keybuf, sizeof(keybuf), slot->type, der, der_len, hash, input, input_len, signature, signature_len); + + memset(keybuf, 0, sizeof(keybuf)); + memset(der, 0, sizeof(der)); + + return err; +} + + +/* + * List keys in the key store. + */ + +static hal_error_t list(hal_pkey_info_t *result, + unsigned *result_len, + const unsigned result_max) +{ + return hal_ks_list(result, result_len, result_max); +} + +const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = { + load, find, generate_rsa, generate_ec, close, delete, + get_key_type, get_key_flags, get_public_key_len, get_public_key, + sign, verify, list +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_server.c b/rpc_server.c new file mode 100644 index 0000000..65f3dfc --- /dev/null +++ b/rpc_server.c @@ -0,0 +1,736 @@ +/* + * rpc_server.c + * ------------ + * Remote procedure call server-side private API implementation. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hal.h" +#include "hal_internal.h" +#include "xdr_internal.h" + +/* + * RPC calls. + */ + +#define check(op) if ((ret = (op)) != HAL_OK) return ret; + +#define pad(n) (((n) + 3) & ~3) + +static hal_error_t get_version(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + uint32_t version; + hal_error_t ret; + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.get_version(&version); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, version)); + + return ret; +} + +static hal_error_t get_random(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + uint32_t length; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &length)); + /* sanity check length */ + if (length == 0 || length > olimit - *optr - 4) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + /* call the local function */ + /* get the data directly into the output buffer */ + check(hal_xdr_encode_int(optr, olimit, length)); + ret = hal_rpc_local_misc_dispatch.get_random(*optr, (size_t)length); + if (ret == HAL_OK) + *optr += pad(length); + else + /* don't return data if error */ + *optr -= 4; + + return ret; +} + +static hal_error_t set_pin(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + uint32_t user; + uint8_t *pin; + uint32_t pin_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &user)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len)); + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.set_pin(client, user, (const char * const)pin, pin_len); + return ret; +} + +static hal_error_t login(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + uint32_t user; + uint8_t *pin; + uint32_t pin_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &user)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &pin, &pin_len)); + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.login(client, user, (const char * const)pin, pin_len); + return ret; +} + +static hal_error_t logout(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.logout(client); + return ret; +} + +static hal_error_t logout_all(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_error_t ret; + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.logout_all(); + return ret; +} + +static hal_error_t is_logged_in(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + uint32_t user; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &user)); + + /* call the local function */ + ret = hal_rpc_local_misc_dispatch.is_logged_in(client, user); + return ret; +} + +static hal_error_t hash_get_digest_len(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + uint32_t alg; + size_t length; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &alg)); + + /* call the local function */ + ret = hal_rpc_local_hash_dispatch.get_digest_length(alg, &length); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, length)); + return ret; +} + +static hal_error_t hash_get_digest_algorithm_id(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + uint32_t alg; + size_t len; + uint32_t len_max; + uint8_t *optr_orig = *optr; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &alg)); + check(hal_xdr_decode_int(iptr, ilimit, &len_max)); + /* sanity check len_max */ + if (len_max > olimit - *optr - 4) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + /* call the local function */ + /* get the data directly into the output buffer */ + *optr += 4; /* reserve 4 bytes for length */ + ret = hal_rpc_local_hash_dispatch.get_digest_algorithm_id(alg, *optr, &len, (size_t)len_max); + if (ret == HAL_OK) { + *optr = optr_orig; + check(hal_xdr_encode_int(optr, olimit, len)); + *optr += pad(len); + } + else { + /* don't return data if error */ + *optr = optr_orig; + } + return ret; +} + +static hal_error_t hash_get_algorithm(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_hash_handle_t hash; + hal_digest_algorithm_t alg; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); + + /* call the local function */ + ret = hal_rpc_local_hash_dispatch.get_algorithm(hash, &alg); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, alg)); + return ret; +} + +static hal_error_t hash_initialize(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_session_handle_t session; + hal_hash_handle_t hash; + uint32_t alg; + uint8_t *key; + uint32_t key_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &alg)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &key, &key_len)); + + /* call the local function */ + ret = hal_rpc_local_hash_dispatch.initialize(client, session, &hash, (hal_digest_algorithm_t)alg, key, (size_t)key_len); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, hash.handle)); + return ret; +} + +static hal_error_t hash_update(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_hash_handle_t hash; + uint8_t *data; + uint32_t length; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &data, &length)); + + /* call the local function */ + ret = hal_rpc_local_hash_dispatch.update(hash, data, (size_t)length); + return ret; +} + +static hal_error_t hash_finalize(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_hash_handle_t hash; + uint32_t length; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &length)); + /* sanity check length */ + if (length == 0 || length > olimit - *optr - 4) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + /* call the local function */ + /* get the data directly into the output buffer */ + check(hal_xdr_encode_int(optr, olimit, length)); + ret = hal_rpc_local_hash_dispatch.finalize(hash, *optr, (size_t)length); + if (ret == HAL_OK) + *optr += pad(length); + else + /* don't return data if error */ + *optr -= 4; + return ret; +} + +static hal_error_t pkey_load(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_session_handle_t session; + hal_pkey_handle_t pkey; + uint32_t type; + uint32_t curve; + uint8_t *name, *der; + uint32_t name_len, der_len; + hal_key_flags_t flags; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &type)); + check(hal_xdr_decode_int(iptr, ilimit, &curve)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &der, &der_len)); + check(hal_xdr_decode_int(iptr, ilimit, &flags)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.load(client, session, &pkey, type, curve, name, name_len, der, der_len, flags); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, pkey.handle)); + return ret; +} + +static hal_error_t pkey_find(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_session_handle_t session; + hal_pkey_handle_t pkey; + uint32_t type; + uint8_t *name; + uint32_t name_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &type)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.find(client, session, &pkey, type, name, name_len); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, pkey.handle)); + return ret; +} + +static hal_error_t pkey_generate_rsa(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_session_handle_t session; + hal_pkey_handle_t pkey; + uint8_t *name; + uint32_t name_len; + uint32_t key_len; + uint8_t *exp; + uint32_t exp_len; + hal_key_flags_t flags; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len)); + check(hal_xdr_decode_int(iptr, ilimit, &key_len)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &exp, &exp_len)); + check(hal_xdr_decode_int(iptr, ilimit, &flags)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.generate_rsa(client, session, &pkey, name, name_len, key_len, exp, exp_len, flags); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, pkey.handle)); + return ret; +} + +static hal_error_t pkey_generate_ec(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_client_handle_t client; + hal_session_handle_t session; + hal_pkey_handle_t pkey; + uint8_t *name; + uint32_t name_len; + uint32_t curve; + hal_key_flags_t flags; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &client.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &name, &name_len)); + check(hal_xdr_decode_int(iptr, ilimit, &curve)); + check(hal_xdr_decode_int(iptr, ilimit, &flags)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.generate_ec(client, session, &pkey, name, name_len, curve, flags); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, pkey.handle)); + return ret; +} + +static hal_error_t pkey_close(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.close(pkey); + return ret; +} + +static hal_error_t pkey_delete(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.delete(pkey); + return ret; +} + +static hal_error_t pkey_get_key_type(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + hal_key_type_t type; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.get_key_type(pkey, &type); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, type)); + return ret; +} + +static hal_error_t pkey_get_key_flags(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + hal_key_flags_t flags; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.get_key_flags(pkey, &flags); + if (ret == HAL_OK) + check(hal_xdr_encode_int(optr, olimit, flags)); + return ret; +} + +static hal_error_t pkey_get_public_key_len(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + size_t len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + + /* call the local function */ + len = hal_rpc_local_pkey_dispatch.get_public_key_len(pkey); + check(hal_xdr_encode_int(optr, olimit, len)); + return HAL_OK; +} + +static hal_error_t pkey_get_public_key(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_pkey_handle_t pkey; + size_t len; + uint32_t len_max; + uint8_t *optr_orig = *optr; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &len_max)); + /* sanity check len_max */ + if (len_max > olimit - *optr - 4) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + /* call the local function */ + /* get the data directly into the output buffer */ + *optr += 4; /* reserve 4 bytes for length */ + ret = hal_rpc_local_pkey_dispatch.get_public_key(pkey, *optr, &len, len_max); + if (ret == HAL_OK) { + *optr = optr_orig; + check(hal_xdr_encode_int(optr, olimit, len)); + *optr += pad(len); + } + else { + /* don't return data if error */ + *optr = optr_orig; + } + return ret; +} + +static hal_error_t pkey_remote_sign(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_session_handle_t session; + hal_pkey_handle_t pkey; + hal_hash_handle_t hash; + uint8_t *input; + uint32_t input_len; + uint32_t sig_max; + size_t sig_len; + uint8_t *optr_orig = *optr; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len)); + check(hal_xdr_decode_int(iptr, ilimit, &sig_max)); + /* sanity check sig_max */ + if (sig_max > olimit - *optr - 4) + return HAL_ERROR_RPC_PACKET_OVERFLOW; + + /* call the local function */ + /* get the data directly into the output buffer */ + *optr += 4; /* reserve 4 bytes for length */ + ret = hal_rpc_local_pkey_dispatch.sign(session, pkey, hash, input, input_len, *optr, &sig_len, sig_max); + *optr = optr_orig; + if (ret == HAL_OK) { + check(hal_xdr_encode_int(optr, olimit, sig_len)); + *optr += pad(sig_len); + } + return ret; +} + +static hal_error_t pkey_remote_verify(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + hal_session_handle_t session; + hal_pkey_handle_t pkey; + hal_hash_handle_t hash; + uint8_t *input; + uint32_t input_len; + uint8_t *sig; + uint32_t sig_len; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &session.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle)); + check(hal_xdr_decode_int(iptr, ilimit, &hash.handle)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &input, &input_len)); + check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &sig, &sig_len)); + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.verify(session, pkey, hash, input, input_len, sig, sig_len); + return ret; +} + +static hal_error_t hal_xdr_encode_pkey_info(uint8_t **optr, const uint8_t * const olimit, const hal_pkey_info_t *info) +{ + uint8_t *optr_orig = *optr; + hal_error_t ret; + + if ((ret = hal_xdr_encode_int(optr, olimit, info->type)) != HAL_OK || + (ret = hal_xdr_encode_int(optr, olimit, info->curve)) != HAL_OK || + (ret = hal_xdr_encode_int(optr, olimit, info->flags)) != HAL_OK || + (ret = hal_xdr_encode_buffer(optr, olimit, (uint8_t *)&info->name[0], info->name_len)) != HAL_OK) + *optr = optr_orig; + return ret; +} + + +static hal_error_t pkey_list(uint8_t **iptr, const uint8_t * const ilimit, + uint8_t **optr, const uint8_t * const olimit) +{ + uint8_t *optr_orig = *optr; + uint32_t result_max; + hal_error_t ret; + + check(hal_xdr_decode_int(iptr, ilimit, &result_max)); + + hal_pkey_info_t result[result_max]; + unsigned result_len; + + /* call the local function */ + ret = hal_rpc_local_pkey_dispatch.list(result, &result_len, result_max); + if (ret == HAL_OK) { + int i; + check(hal_xdr_encode_int(optr, olimit, result_len)); + for (i = 0; i < result_len; ++i) { + if ((ret = hal_xdr_encode_pkey_info(optr, olimit, &result[i])) != HAL_OK) { + *optr = optr_orig; + break; + } + } + } + return ret; +} + +void hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen, uint8_t * const obuf, size_t * const olen) +{ + uint8_t * iptr = ibuf; + uint8_t * ilimit = ibuf + ilen; + uint8_t * optr = obuf + 4; /* reserve 4 bytes for return code */ + uint8_t * olimit = obuf + *olen; + uint32_t rpc_func_num; + hal_error_t ret; + + hal_xdr_decode_int(&iptr, ilimit, &rpc_func_num); + switch (rpc_func_num) { + case RPC_FUNC_GET_VERSION: + ret = get_version(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_GET_RANDOM: + ret = get_random(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_SET_PIN: + ret = set_pin(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_LOGIN: + ret = login(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_LOGOUT: + ret = logout(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_LOGOUT_ALL: + ret = logout_all(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_IS_LOGGED_IN: + ret = is_logged_in(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_GET_DIGEST_LEN: + ret = hash_get_digest_len(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_GET_DIGEST_ALGORITHM_ID: + ret = hash_get_digest_algorithm_id(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_GET_ALGORITHM: + ret = hash_get_algorithm(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_INITIALIZE: + ret = hash_initialize(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_UPDATE: + ret = hash_update(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_HASH_FINALIZE: + ret = hash_finalize(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_LOAD: + ret = pkey_load(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_FIND: + ret = pkey_find(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GENERATE_RSA: + ret = pkey_generate_rsa(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GENERATE_EC: + ret = pkey_generate_ec(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_CLOSE: + ret = pkey_close(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_DELETE: + ret = pkey_delete(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GET_KEY_TYPE: + ret = pkey_get_key_type(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GET_KEY_FLAGS: + ret = pkey_get_key_flags(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN: + ret = pkey_get_public_key_len(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_GET_PUBLIC_KEY: + ret = pkey_get_public_key(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_REMOTE_SIGN: + ret = pkey_remote_sign(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_REMOTE_VERIFY: + ret = pkey_remote_verify(&iptr, ilimit, &optr, olimit); + break; + case RPC_FUNC_PKEY_LIST: + ret = pkey_list(&iptr, ilimit, &optr, olimit); + break; + default: + ret = HAL_ERROR_RPC_BAD_FUNCTION; + break; + } + /* encode the return code at the beginning of the payload */ + *olen = optr - obuf; + optr = obuf; + hal_xdr_encode_int(&optr, olimit, ret); +} + +#define MAX_PKT_SIZE 4096 +#define interrupt 0 + +static uint8_t inbuf[MAX_PKT_SIZE], outbuf[MAX_PKT_SIZE]; + +void hal_rpc_server_main(void) +{ + size_t ilen, olen; + void *opaque; + hal_error_t ret; + + while (!interrupt) { + ilen = sizeof(inbuf); + ret = hal_rpc_recvfrom(inbuf, &ilen, &opaque); + if (ret == HAL_OK) { + olen = sizeof(outbuf); + hal_rpc_server_dispatch(inbuf, ilen, outbuf, &olen); + hal_rpc_sendto(outbuf, olen, opaque); + } + } +} + +/* + * Dispatch vectors. + */ + +const hal_rpc_misc_dispatch_t *hal_rpc_misc_dispatch = &hal_rpc_local_misc_dispatch; +const hal_rpc_hash_dispatch_t *hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch; +const hal_rpc_pkey_dispatch_t *hal_rpc_pkey_dispatch = &hal_rpc_local_pkey_dispatch; + +hal_error_t hal_rpc_server_init(void) +{ + return hal_rpc_server_transport_init(); +} + +hal_error_t hal_rpc_server_close(void) +{ + return hal_rpc_server_transport_close(); +} + + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_server_loopback.c b/rpc_server_loopback.c new file mode 100644 index 0000000..4ca7467 --- /dev/null +++ b/rpc_server_loopback.c @@ -0,0 +1,89 @@ +/* + * rpc_server_loopback.c + * --------------------- + * Remote procedure call transport over loopback socket. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> /* close */ + +#include "hal.h" +#include "hal_internal.h" + +static int fd; + +hal_error_t hal_rpc_server_transport_init(void) +{ + struct sockaddr_in sin; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) + return perror("socket"), HAL_ERROR_RPC_TRANSPORT; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = 17425; + if (bind(fd, (const struct sockaddr *)&sin, sizeof(sin)) != 0) + return perror("bind"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_server_transport_close(void) +{ + if (close(fd) != 0) + return perror("close"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)opaque; + int ret; + + if ((ret = sendto(fd, buf, len, 0, (struct sockaddr *)sin, sizeof(*sin))) == -1) + return perror("sendto"), HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque) +{ + static struct sockaddr_in sin; + socklen_t sin_len = sizeof(sin); + int ret; + + if ((ret = recvfrom(fd, buf, *len, 0, (struct sockaddr *)&sin, &sin_len)) == -1) + return HAL_ERROR_RPC_TRANSPORT; + *opaque = (void *)&sin; + *len = ret; + return HAL_OK; +} diff --git a/rpc_server_serial.c b/rpc_server_serial.c new file mode 100644 index 0000000..d896700 --- /dev/null +++ b/rpc_server_serial.c @@ -0,0 +1,79 @@ +/* + * rpc_server_serial.c + * ------------------- + * Remote procedure call transport over serial line with SLIP framing. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "hal.h" +#include "hal_internal.h" +#include "slip_internal.h" + +/* Don't include stm-uart.h to avoid conflicting definitions of HAL_OK. + */ +extern int uart_send_char(uint8_t ch); +extern int uart_recv_char(uint8_t *cp); + +hal_error_t hal_rpc_server_transport_init(void) +{ + return HAL_OK; +} + +hal_error_t hal_rpc_server_transport_close(void) +{ + return HAL_OK; +} + +hal_error_t hal_rpc_sendto(const uint8_t * const buf, const size_t len, void *opaque) +{ + if (hal_slip_send(buf, len) == -1) + return HAL_ERROR_RPC_TRANSPORT; + return HAL_OK; +} + +hal_error_t hal_rpc_recvfrom(uint8_t * const buf, size_t * const len, void **opaque) +{ + int ret; + + if ((ret = hal_slip_recv(buf, *len)) == -1) + return HAL_ERROR_RPC_TRANSPORT; + *len = ret; + return HAL_OK; +} + +int hal_slip_send_char(uint8_t c) +{ + return (uart_send_char(c) == 0) ? 0 : -1; +} + +int hal_slip_recv_char(uint8_t *c) +{ + return (uart_recv_char(c) == 0) ? 0 : -1; +} @@ -73,7 +73,7 @@ #include <assert.h> #include "hal.h" -#include "verilog_constants.h" +#include "hal_internal.h" #include <tfm.h> #include "asn1_internal.h" @@ -86,6 +86,10 @@ #define HAL_RSA_USE_MODEXP 1 #endif +#ifdef RPC_CLIENT +#define hal_get_random(core, buffer, length) hal_rpc_get_random(buffer, length) +#endif + /* * Whether we want debug output. */ @@ -116,7 +120,7 @@ void hal_rsa_set_blinding(const int onoff) */ struct hal_rsa_key { - hal_rsa_key_type_t type; /* What kind of key this is */ + hal_key_type_t type; /* What kind of key this is */ fp_int n[1]; /* The modulus */ fp_int e[1]; /* Public exponent */ fp_int d[1]; /* Private exponent */ @@ -256,7 +260,8 @@ int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d) * wait for the slow FPGA implementation. */ -static hal_error_t modexp(const fp_int * const msg, +static hal_error_t modexp(const hal_core_t *core, /* ignored */ + const fp_int * const msg, const fp_int * const exp, const fp_int * const mod, fp_int *res) @@ -454,7 +459,7 @@ void hal_rsa_key_clear(hal_rsa_key_t *key) * calculate everything else from them. */ -static hal_error_t load_key(const hal_rsa_key_type_t type, +static hal_error_t load_key(const hal_key_type_t type, hal_rsa_key_t **key_, void *keybuf, const size_t keybuf_len, const uint8_t * const n, const size_t n_len, @@ -477,12 +482,14 @@ static hal_error_t load_key(const hal_rsa_key_type_t type, #define _(x) do { fp_init(key->x); if (x == NULL) goto fail; fp_read_unsigned_bin(key->x, unconst_uint8_t(x), x##_len); } while (0) switch (type) { - case HAL_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PRIVATE: _(d); _(p); _(q); _(u); _(dP); _(dQ); - case HAL_RSA_PUBLIC: + case HAL_KEY_TYPE_RSA_PUBLIC: _(n); _(e); *key_ = key; return HAL_OK; + default: + goto fail; } #undef _ @@ -506,7 +513,7 @@ hal_error_t hal_rsa_key_load_private(hal_rsa_key_t **key_, const uint8_t * const dP, const size_t dP_len, const uint8_t * const dQ, const size_t dQ_len) { - return load_key(HAL_RSA_PRIVATE, key_, keybuf, keybuf_len, + return load_key(HAL_KEY_TYPE_RSA_PRIVATE, key_, keybuf, keybuf_len, n, n_len, e, e_len, d, d_len, p, p_len, q, q_len, u, u_len, dP, dP_len, dQ, dQ_len); } @@ -516,7 +523,7 @@ hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key_, const uint8_t * const n, const size_t n_len, const uint8_t * const e, const size_t e_len) { - return load_key(HAL_RSA_PUBLIC, key_, keybuf, keybuf_len, + return load_key(HAL_KEY_TYPE_RSA_PUBLIC, key_, keybuf, keybuf_len, n, n_len, e, e_len, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0); } @@ -526,7 +533,7 @@ hal_error_t hal_rsa_key_load_public(hal_rsa_key_t **key_, */ hal_error_t hal_rsa_key_get_type(const hal_rsa_key_t * const key, - hal_rsa_key_type_t *key_type) + hal_key_type_t *key_type) { if (key == NULL || key_type == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -625,7 +632,7 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core, return HAL_ERROR_BAD_ARGUMENTS; memset(keybuf, 0, keybuf_len); - key->type = HAL_RSA_PRIVATE; + key->type = HAL_KEY_TYPE_RSA_PRIVATE; fp_read_unsigned_bin(key->e, (uint8_t *) public_exponent, public_exponent_len); if (key_length < bitsToBytes(1024) || key_length > bitsToBytes(8192)) @@ -685,12 +692,12 @@ hal_error_t hal_rsa_key_gen(const hal_core_t *core, _(key->dQ); \ _(key->u); -hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key, - uint8_t *der, size_t *der_len, const size_t der_max) +hal_error_t hal_rsa_private_key_to_der(const hal_rsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max) { hal_error_t err = HAL_OK; - if (key == NULL || der_len == NULL || key->type != HAL_RSA_PRIVATE) + if (key == NULL || der_len == NULL || key->type != HAL_KEY_TYPE_RSA_PRIVATE) return HAL_ERROR_BAD_ARGUMENTS; fp_int version[1] = INIT_FP_INT; @@ -731,15 +738,15 @@ hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key, return HAL_OK; } -size_t hal_rsa_key_to_der_len(const hal_rsa_key_t * const key) +size_t hal_rsa_private_key_to_der_len(const hal_rsa_key_t * const key) { size_t len = 0; - return hal_rsa_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; + return hal_rsa_private_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; } -hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key_, - void *keybuf, const size_t keybuf_len, - const uint8_t *der, const size_t der_len) +hal_error_t hal_rsa_private_key_from_der(hal_rsa_key_t **key_, + void *keybuf, const size_t keybuf_len, + const uint8_t *der, const size_t der_len) { if (key_ == NULL || keybuf == NULL || keybuf_len < sizeof(hal_rsa_key_t) || der == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -748,7 +755,7 @@ hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key_, hal_rsa_key_t *key = keybuf; - key->type = HAL_RSA_PRIVATE; + key->type = HAL_KEY_TYPE_RSA_PRIVATE; hal_error_t err = HAL_OK; size_t hlen, vlen; @@ -773,6 +780,100 @@ hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key_, } /* + * ASN.1 public keys in SubjectPublicKeyInfo form, see RFCs 2313, 4055, and 5280. + */ + +static const uint8_t oid_rsaEncryption[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; + +hal_error_t hal_rsa_public_key_to_der(const hal_rsa_key_t * const key, + uint8_t *der, size_t *der_len, const size_t der_max) +{ + if (key == NULL || (key->type != HAL_KEY_TYPE_RSA_PRIVATE && + key->type != HAL_KEY_TYPE_RSA_PUBLIC)) + return HAL_ERROR_BAD_ARGUMENTS; + + size_t hlen, n_len, e_len; + hal_error_t err; + + if ((err = hal_asn1_encode_integer(key->n, NULL, &n_len, 0)) != HAL_OK || + (err = hal_asn1_encode_integer(key->e, NULL, &e_len, 0)) != HAL_OK) + return err; + + const size_t vlen = n_len + e_len; + + if ((err = hal_asn1_encode_header(ASN1_SEQUENCE, vlen, der, &hlen, der_max)) != HAL_OK) + return err; + + if (der != NULL) { + uint8_t * const n_out = der + hlen; + uint8_t * const e_out = n_out + n_len; + + if ((err = hal_asn1_encode_integer(key->n, n_out, NULL, der + der_max - n_out)) != HAL_OK || + (err = hal_asn1_encode_integer(key->e, e_out, NULL, der + der_max - e_out)) != HAL_OK) + return err; + } + + return hal_asn1_encode_spki(oid_rsaEncryption, sizeof(oid_rsaEncryption), + NULL, 0, der, hlen + vlen, + der, der_len, der_max); + +} + +size_t hal_rsa_public_key_to_der_len(const hal_rsa_key_t * const key) +{ + size_t len = 0; + return hal_rsa_public_key_to_der(key, NULL, &len, 0) == HAL_OK ? len : 0; +} + +hal_error_t hal_rsa_public_key_from_der(hal_rsa_key_t **key_, + void *keybuf, const size_t keybuf_len, + const uint8_t * const der, const size_t der_len) +{ + hal_rsa_key_t *key = keybuf; + + if (key_ == NULL || key == NULL || keybuf_len < sizeof(*key) || der == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + memset(keybuf, 0, keybuf_len); + + key->type = HAL_KEY_TYPE_RSA_PUBLIC; + + const uint8_t *alg_oid = NULL, *null = NULL, *pubkey = NULL; + size_t alg_oid_len, null_len, pubkey_len; + hal_error_t err; + + if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &null, &null_len, &pubkey, &pubkey_len, der, der_len)) != HAL_OK) + return err; + + if (null != NULL || null_len != 0 || alg_oid == NULL || + alg_oid_len != sizeof(oid_rsaEncryption) || memcmp(alg_oid, oid_rsaEncryption, alg_oid_len) != 0) + return HAL_ERROR_ASN1_PARSE_FAILED; + + size_t len, hlen, vlen; + + if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, pubkey, pubkey_len, &hlen, &vlen)) != HAL_OK) + return err; + + const uint8_t * const pubkey_end = pubkey + hlen + vlen; + const uint8_t *d = pubkey + hlen; + + if ((err = hal_asn1_decode_integer(key->n, d, &len, pubkey_end - d)) != HAL_OK) + return err; + d += len; + + if ((err = hal_asn1_decode_integer(key->e, d, &len, pubkey_end - d)) != HAL_OK) + return err; + d += len; + + if (d != pubkey_end) + return HAL_ERROR_ASN1_PARSE_FAILED; + + *key_ = key; + + return HAL_OK; +} + +/* * Local variables: * indent-tabs-mode: nil * End: @@ -0,0 +1,141 @@ +/* SLIP send/recv code, from RFC 1055 */ + +#include <stdio.h> /* perror */ + +#include "slip_internal.h" + +/* SLIP special character codes + */ +#define END 0300 /* indicates end of packet */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END data byte */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */ + +/* SLIP_SEND: sends a packet of length "len", starting at + * location "p". + */ +int hal_slip_send(const uint8_t * const ptr, const size_t len) +{ + int i; + uint8_t *p = (uint8_t *)ptr; + +#define check_send_char(c) if (hal_slip_send_char(c) == -1) return perror("write"), -1; + + /* send an initial END character to flush out any data that may + * have accumulated in the receiver due to line noise + */ + check_send_char(END); + + /* for each byte in the packet, send the appropriate character + * sequence + */ + for (i = 0; i < len; ++i) { + switch (*p) { + /* if it's the same code as an END character, we send a + * special two character code so as not to make the + * receiver think we sent an END + */ + case END: + check_send_char(ESC); + check_send_char(ESC_END); + break; + + /* if it's the same code as an ESC character, + * we send a special two character code so as not + * to make the receiver think we sent an ESC + */ + case ESC: + check_send_char(ESC); + check_send_char(ESC_ESC); + break; + + /* otherwise, we just send the character + */ + default: + check_send_char(*p); + } + + p++; + } + + /* tell the receiver that we're done sending the packet + */ + check_send_char(END); + + return 0; +#undef check_send_char +} + +/* SLIP_RECV: receives a packet into the buffer located at "p". + * If more than len bytes are received, the packet will + * be truncated. + * Returns the number of bytes stored in the buffer. + */ +int hal_slip_recv(uint8_t * const p, const size_t len) +{ + uint8_t c; + size_t received = 0; + +#define check_recv_char(c) if (hal_slip_recv_char(&c) == -1) return perror("read"), -1; + + /* sit in a loop reading bytes until we put together + * a whole packet. + * Make sure not to copy them into the packet if we + * run out of room. + */ + while (1) { + /* get a character to process + */ + check_recv_char(c); + + /* handle bytestuffing if necessary + */ + switch (c) { + + /* if it's an END character then we're done with + * the packet + */ + case END: + /* a minor optimization: if there is no + * data in the packet, ignore it. This is + * meant to avoid bothering IP with all + * the empty packets generated by the + * duplicate END characters which are in + * turn sent to try to detect line noise. + */ + if (received) + return received; + else + break; + + /* if it's the same code as an ESC character, wait + * and get another character and then figure out + * what to store in the packet based on that. + */ + case ESC: + check_recv_char(c); + + /* if "c" is not one of these two, then we + * have a protocol violation. The best bet + * seems to be to leave the byte alone and + * just stuff it into the packet + */ + switch(c) { + case ESC_END: + c = END; + break; + case ESC_ESC: + c = ESC; + break; + } + + /* here we fall into the default handler and let + * it store the character for us + */ + default: + if (received < len) + p[received++] = c; + } + } +#undef check_recv_char +} diff --git a/slip_internal.h b/slip_internal.h new file mode 100644 index 0000000..103f72d --- /dev/null +++ b/slip_internal.h @@ -0,0 +1,51 @@ +/* + * slip_internal.h + * --------------- + * Send/recv data over a serial connection with SLIP framing + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _HAL_SLIP_INTERNAL_H +#define _HAL_SLIP_INTERNAL_H + +#include "hal_internal.h" + +/* Defined in slip.c - send/recv a block of data with SLIP framing. + */ +extern int hal_slip_send(const uint8_t * const p, const size_t len); +extern int hal_slip_recv(uint8_t * const p, const size_t len); + +/* Defined in rpc_[client|server]_serial.c - send/recv one byte over a + * serial connection. + */ +extern int hal_slip_send_char(const uint8_t c); +extern int hal_slip_recv_char(uint8_t * const c); + +#endif /* _HAL_SLIP_INTERNAL_H */ diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 0e3ba34..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test-aes-key-wrap diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 596bf0f..65c7a25 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -29,14 +29,29 @@ INC = ../hal.h LIB = ../libhal.a -BIN = test-aes-key-wrap test-hash test-pbkdf2 test-rsa test-ecdsa test-bus test-trng +BIN := test-aes-key-wrap test-hash test-pbkdf2 test-ecdsa test-bus test-trng test-rsa +ifndef RPC_SERVER + ifdef RPC_CLIENT + ifneq (${RPC_CLIENT},local) + # If we're only building a remote RPC client lib, don't include + # tests that access the FPGA cores. + BIN := + endif + endif +endif +ifdef RPC_CLIENT + BIN += test-rpc_hash test-rpc_pkey test-rpc_get_version test-rpc_get_random +endif +ifdef RPC_SERVER + BIN += test-rpc_server +endif CFLAGS = -g3 -Wall -fPIC -std=c99 -I.. all: ${BIN} test: all - for i in ${BIN}; do ./$$i; done + for i in ${BIN}; do (set -x; ./$$i); done clean: rm -f *.o ${BIN} diff --git a/tests/test-bus.c b/tests/test-bus.c index 1c60e5d..b4a3e1c 100644 --- a/tests/test-bus.c +++ b/tests/test-bus.c @@ -91,7 +91,8 @@ static void _time_check(char *label, const struct timeval t0, const int err) t.tv_sec -= 1; } rounds = (float)TEST_NUM_ROUNDS/((float)t.tv_sec + ((float)t.tv_usec / 1000000)); - printf("%s%lu.%06lu seconds, %u/sec\n", label, t.tv_sec, t.tv_usec, (unsigned)rounds); + printf("%s%lu.%06lu seconds, %u/sec\n", label, + (unsigned long)t.tv_sec, (unsigned long)t.tv_usec, (unsigned)rounds); } #define time_check(_label_, _expr_) \ diff --git a/tests/test-ecdsa.c b/tests/test-ecdsa.c index ce8aee1..da2b367 100644 --- a/tests/test-ecdsa.c +++ b/tests/test-ecdsa.c @@ -49,6 +49,7 @@ #include <stdio.h> #include <stdint.h> #include <string.h> +#include <errno.h> #include <sys/time.h> @@ -103,7 +104,9 @@ static void set_next_random(const uint8_t * const data, const size_t length) static int test_against_static_vectors(const ecdsa_tc_t * const tc) { + char fn[sizeof("test-ecdsa-private-key-xxxxxx.der")]; hal_error_t err; + FILE *f; printf("Starting static test vector tests for P-%lu\n", (unsigned long) (tc->d_len * 8)); @@ -127,20 +130,34 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc) if (tc->Qy_len != Qy_len || memcmp(tc->Qy, Qy, Qy_len) != 0) return printf("Qy mismatch\n"), 0; - if (hal_ecdsa_key_to_der_len(key1) != tc->key_len) + if (hal_ecdsa_private_key_to_der_len(key1) != tc->key_len) return printf("DER Key length mismatch\n"), 0; - uint8_t keyder[tc->key_len]; - size_t keyder_len; + uint8_t der[tc->key_len]; + size_t der_len; - if ((err = hal_ecdsa_key_to_der(key1, keyder, &keyder_len, sizeof(keyder))) != HAL_OK) - return printf("hal_ecdsa_key_to_der() failed: %s\n", hal_error_string(err)), 0; + err = hal_ecdsa_private_key_to_der(key1, der, &der_len, sizeof(der)); + + snprintf(fn, sizeof(fn), "test-ecdsa-private-key-p%u.der", (unsigned) tc->d_len * 8); + + if ((f = fopen(fn, "wb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; + + if (fwrite(der, der_len, 1, f) != 1) + return printf("Length mismatch writing %s\n", fn), 0; + + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; + + /* Deferred error from hal_ecdsa_private_key_to_der() */ + if (err != HAL_OK) + return printf("hal_ecdsa_private_key_to_der() failed: %s\n", hal_error_string(err)), 0; uint8_t keybuf2[hal_ecdsa_key_t_size]; hal_ecdsa_key_t *key2 = NULL; - if ((err = hal_ecdsa_key_from_der(&key2, keybuf2, sizeof(keybuf2), keyder, keyder_len)) != HAL_OK) - return printf("hal_ecdsa_key_from_der() failed: %s\n", hal_error_string(err)), 0; + if ((err = hal_ecdsa_private_key_from_der(&key2, keybuf2, sizeof(keybuf2), der, der_len)) != HAL_OK) + return printf("hal_ecdsa_private_key_from_der() failed: %s\n", hal_error_string(err)), 0; if (memcmp(key1, key2, hal_ecdsa_key_t_size) != 0) return printf("Private key mismatch after read/write cycle\n"), 0; @@ -150,13 +167,13 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc) uint8_t sig[tc->sig_len + 4]; size_t sig_len; - if ((err = hal_ecdsa_sign(NULL, key1, tc->H, tc->H_len, sig, &sig_len, sizeof(sig), HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK) + if ((err = hal_ecdsa_sign(NULL, key1, tc->H, tc->H_len, sig, &sig_len, sizeof(sig))) != HAL_OK) return printf("hal_ecdsa_sign() failed: %s\n", hal_error_string(err)), 0; if (sig_len != tc->sig_len || memcmp(sig, tc->sig, tc->sig_len) != 0) return printf("Signature mismatch\n"), 0; - if ((err = hal_ecdsa_verify(NULL, key2, tc->H, tc->H_len, sig, sig_len, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK) + if ((err = hal_ecdsa_verify(NULL, key2, tc->H, tc->H_len, sig, sig_len)) != HAL_OK) return printf("hal_ecdsa_verify(private) failed: %s\n", hal_error_string(err)), 0; hal_ecdsa_key_clear(key2); @@ -176,7 +193,7 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc) tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len)) != HAL_OK) return printf("hal_ecdsa_load_public() failed: %s\n", hal_error_string(err)), 0; - if ((err = hal_ecdsa_verify(NULL, key2, tc->H, tc->H_len, sig, sig_len, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK) + if ((err = hal_ecdsa_verify(NULL, key2, tc->H, tc->H_len, sig, sig_len)) != HAL_OK) return printf("hal_ecdsa_verify(public) failed: %s\n", hal_error_string(err)), 0; uint8_t point[hal_ecdsa_key_to_ecpoint_len(key1)]; @@ -192,7 +209,36 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc) return printf("hal_ecdsa_key_from_point() failed: %s\n", hal_error_string(err)), 0; if (memcmp(key1, key2, hal_ecdsa_key_t_size) != 0) - return printf("Public key mismatch after read/write cycle\n"), 0; + return printf("Public key mismatch after first read/write cycle\n"), 0; + + hal_ecdsa_key_clear(key2); + key2 = NULL; + + err = hal_ecdsa_public_key_to_der(key1, der, &der_len, sizeof(der)); + + snprintf(fn, sizeof(fn), "test-ecdsa-public-key-p%u.der", (unsigned) tc->d_len * 8); + + if ((f = fopen(fn, "wb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; + + if (fwrite(der, der_len, 1, f) != 1) + return printf("Length mismatch writing %s\n", fn), 0; + + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; + + /* Deferred error from hal_ecdsa_public_key_to_der() */ + if (err != HAL_OK) + return printf("hal_ecdsa_public_key_to_der() failed: %s\n", hal_error_string(err)), 0; + + if ((err = hal_ecdsa_public_key_from_der(&key2, keybuf2, sizeof(keybuf2), der, der_len)) != HAL_OK) + return printf("hal_ecdsa_public_key_from_der() failed: %s\n", hal_error_string(err)), 0; + + if (memcmp(key1, key2, hal_ecdsa_key_t_size) != 0) + return printf("Public key mismatch after second read/write cycle\n"), 0; + + hal_ecdsa_key_clear(key1); + hal_ecdsa_key_clear(key2); return 1; } @@ -203,7 +249,7 @@ static int test_against_static_vectors(const ecdsa_tc_t * const tc) * Run one keygen/sign/verify test with a newly generated key. */ -static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve) +static int test_keygen_sign_verify(const hal_curve_name_t curve) { const hal_hash_descriptor_t *hash_descriptor = NULL; @@ -213,17 +259,17 @@ static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve) switch (curve) { - case HAL_ECDSA_CURVE_P256: + case HAL_CURVE_P256: printf("ECDSA P-256 key generation / signature / verification test\n"); hash_descriptor = hal_hash_sha256; break; - case HAL_ECDSA_CURVE_P384: + case HAL_CURVE_P384: printf("ECDSA P-384 key generation / signature / verification test\n"); hash_descriptor = hal_hash_sha384; break; - case HAL_ECDSA_CURVE_P521: + case HAL_CURVE_P521: printf("ECDSA P-521 key generation / signature / verification test\n"); hash_descriptor = hal_hash_sha512; break; @@ -263,13 +309,12 @@ static int test_keygen_sign_verify(const hal_ecdsa_curve_t curve) printf("Signing\n"); if ((err = hal_ecdsa_sign(NULL, key, hashbuf, sizeof(hashbuf), - sigbuf, &siglen, sizeof(sigbuf), HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK) + sigbuf, &siglen, sizeof(sigbuf))) != HAL_OK) return printf("hal_ecdsa_sign() failed: %s\n", hal_error_string(err)), 0; printf("Verifying\n"); - if ((err = hal_ecdsa_verify(NULL, key, hashbuf, sizeof(hashbuf), - sigbuf, siglen, HAL_ECDSA_SIGNATURE_FORMAT_ASN1)) != HAL_OK) + if ((err = hal_ecdsa_verify(NULL, key, hashbuf, sizeof(hashbuf), sigbuf, siglen)) != HAL_OK) return printf("hal_ecdsa_verify() failed: %s\n", hal_error_string(err)), 0; return 1; @@ -339,12 +384,12 @@ int main(int argc, char *argv[]) */ if (csprng_core != NULL && sha256_core != NULL) { - time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P256)); + time_check(test_keygen_sign_verify(HAL_CURVE_P256)); } if (csprng_core != NULL && sha512_core != NULL) { - time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P384)); - time_check(test_keygen_sign_verify(HAL_ECDSA_CURVE_P521)); + time_check(test_keygen_sign_verify(HAL_CURVE_P384)); + time_check(test_keygen_sign_verify(HAL_CURVE_P521)); } return !ok; diff --git a/tests/test-ecdsa.h b/tests/test-ecdsa.h index ca51858..9fafe18 100644 --- a/tests/test-ecdsa.h +++ b/tests/test-ecdsa.h @@ -89,13 +89,13 @@ static const uint8_t p256_s[] = { /* 32 bytes */ 0x92, 0xdb, 0xea, 0xa1, 0xaf, 0x2b, 0xc3, 0x67 }; -static const uint8_t p256_sig[] = { /* 70 bytes */ - 0x30, 0x44, 0x02, 0x20, 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd, - 0x39, 0xff, 0x2f, 0x80, 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf, - 0x86, 0xbb, 0x81, 0x56, 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c, - 0x02, 0x20, 0x7d, 0x1f, 0xf9, 0x61, 0x98, 0x0f, 0x96, 0x1b, 0xda, 0xa3, - 0x23, 0x3b, 0x62, 0x09, 0xf4, 0x01, 0x33, 0x17, 0xd3, 0xe3, 0xf9, 0xe1, - 0x49, 0x35, 0x92, 0xdb, 0xea, 0xa1, 0xaf, 0x2b, 0xc3, 0x67 +static const uint8_t p256_sig[] = { /* 64 bytes */ + 0x72, 0x14, 0xbc, 0x96, 0x47, 0x16, 0x0b, 0xbd, 0x39, 0xff, 0x2f, 0x80, + 0x53, 0x3f, 0x5d, 0xc6, 0xdd, 0xd7, 0x0d, 0xdf, 0x86, 0xbb, 0x81, 0x56, + 0x61, 0xe8, 0x05, 0xd5, 0xd4, 0xe6, 0xf2, 0x7c, 0x7d, 0x1f, 0xf9, 0x61, + 0x98, 0x0f, 0x96, 0x1b, 0xda, 0xa3, 0x23, 0x3b, 0x62, 0x09, 0xf4, 0x01, + 0x33, 0x17, 0xd3, 0xe3, 0xf9, 0xe1, 0x49, 0x35, 0x92, 0xdb, 0xea, 0xa1, + 0xaf, 0x2b, 0xc3, 0x67 }; static const uint8_t p256_u1[] = { /* 32 bytes */ @@ -223,16 +223,15 @@ static const uint8_t p384_s[] = { /* 48 bytes */ 0x67, 0xad, 0xad, 0xf1, 0x68, 0xeb, 0xbe, 0x80, 0x37, 0x94, 0xa4, 0x02 }; -static const uint8_t p384_sig[] = { /* 103 bytes */ - 0x30, 0x65, 0x02, 0x31, 0x00, 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d, - 0xea, 0x1e, 0x1b, 0xd2, 0xcc, 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34, - 0xed, 0x0c, 0x9f, 0x81, 0x31, 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8, - 0xdb, 0xed, 0x8d, 0xd5, 0x9f, 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1, - 0x4f, 0xe7, 0x2d, 0xe8, 0x56, 0x02, 0x30, 0x20, 0xab, 0x3f, 0x45, 0xb7, - 0x4f, 0x10, 0xb6, 0xe1, 0x1f, 0x96, 0xa2, 0xc8, 0xeb, 0x69, 0x4d, 0x20, - 0x6b, 0x9d, 0xda, 0x86, 0xd3, 0xc7, 0xe3, 0x31, 0xc2, 0x6b, 0x22, 0xc9, - 0x87, 0xb7, 0x53, 0x77, 0x26, 0x57, 0x76, 0x67, 0xad, 0xad, 0xf1, 0x68, - 0xeb, 0xbe, 0x80, 0x37, 0x94, 0xa4, 0x02 +static const uint8_t p384_sig[] = { /* 96 bytes */ + 0xa0, 0xc2, 0x7e, 0xc8, 0x93, 0x09, 0x2d, 0xea, 0x1e, 0x1b, 0xd2, 0xcc, + 0xfe, 0xd3, 0xcf, 0x94, 0x5c, 0x81, 0x34, 0xed, 0x0c, 0x9f, 0x81, 0x31, + 0x1a, 0x0f, 0x4a, 0x05, 0x94, 0x2d, 0xb8, 0xdb, 0xed, 0x8d, 0xd5, 0x9f, + 0x26, 0x74, 0x71, 0xd5, 0x46, 0x2a, 0xa1, 0x4f, 0xe7, 0x2d, 0xe8, 0x56, + 0x20, 0xab, 0x3f, 0x45, 0xb7, 0x4f, 0x10, 0xb6, 0xe1, 0x1f, 0x96, 0xa2, + 0xc8, 0xeb, 0x69, 0x4d, 0x20, 0x6b, 0x9d, 0xda, 0x86, 0xd3, 0xc7, 0xe3, + 0x31, 0xc2, 0x6b, 0x22, 0xc9, 0x87, 0xb7, 0x53, 0x77, 0x26, 0x57, 0x76, + 0x67, 0xad, 0xad, 0xf1, 0x68, 0xeb, 0xbe, 0x80, 0x37, 0x94, 0xa4, 0x02 }; static const uint8_t p384_u1[] = { /* 48 bytes */ @@ -264,7 +263,7 @@ static const uint8_t p384_w[] = { /* 48 bytes */ }; typedef struct { - hal_ecdsa_curve_t curve; + hal_curve_name_t curve; const uint8_t * H; size_t H_len; const uint8_t * M; size_t M_len; const uint8_t * Qx; size_t Qx_len; @@ -286,7 +285,7 @@ typedef struct { } ecdsa_tc_t; static const ecdsa_tc_t ecdsa_tc[] = { - { HAL_ECDSA_CURVE_P256, + { HAL_CURVE_P256, p256_H, sizeof(p256_H), p256_M, sizeof(p256_M), p256_Qx, sizeof(p256_Qx), @@ -306,7 +305,7 @@ static const ecdsa_tc_t ecdsa_tc[] = { p256_v, sizeof(p256_v), p256_w, sizeof(p256_w), }, - { HAL_ECDSA_CURVE_P384, + { HAL_CURVE_P384, p384_H, sizeof(p384_H), p384_M, sizeof(p384_M), p384_Qx, sizeof(p384_Qx), diff --git a/tests/test-ecdsa.py b/tests/test-ecdsa.py index 1ecfef9..efd96e3 100644 --- a/tests/test-ecdsa.py +++ b/tests/test-ecdsa.py @@ -50,38 +50,31 @@ from pyasn1.codec.der.decoder import decode as DER_Decode wrapper = TextWrapper(width = 78, initial_indent = " " * 2, subsequent_indent = " " * 2) -def long_to_bytes(l): +def long_to_bytes(number, order): # # This is just plain nasty. # - s = "%x" % l - return ("0" + s if len(s) & 1 else s).decode("hex") + s = "%x" % number + s = ("0" * (order/8 - len(s))) + s + return s.decode("hex") -def bytes_to_bits(b): +def bytes_to_bits(bytes): # # This, on the other hand, is not just plain nasty, this is fancy nasty. # This is nasty with raisins in it. # - bits = bin(long(b.encode("hex"), 16))[2:] - if len(bits) % 8: - bits = ("0" * (8 - len(bits) % 8)) + bits - return tuple(int(i) for i in bits) + s = bin(long(bytes.encode("hex"), 16))[2:] + if len(s) % 8: + s = ("0" * (8 - len(s) % 8)) + s + return tuple(int(i) for i in s) ### -class ECDSA_Sig_Value(Sequence): - componentType = NamedTypes( - NamedType("r", Integer()), - NamedType("s", Integer())) - -def encode_sig(r, s): - sig = ECDSA_Sig_Value() - sig["r"] = r - sig["s"] = s - return DER_Encode(sig) +def encode_sig(r, s, order): + return long_to_bytes(r, order) + long_to_bytes(s, order) -p256_sig = encode_sig(p256_r, p256_s) -p384_sig = encode_sig(p384_r, p384_s) +p256_sig = encode_sig(p256_r, p256_s, 256) +p384_sig = encode_sig(p384_r, p384_s, 384) ### @@ -93,9 +86,9 @@ class ECPrivateKey(Sequence): OptionalNamedType("parameters", ObjectIdentifier().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))), OptionalNamedType("publicKey", BitString().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1)))) -def encode_key(d, Qx, Qy, oid): - private_key = long_to_bytes(d) - public_key = bytes_to_bits(chr(0x04) + long_to_bytes(Qx) + long_to_bytes(Qy)) +def encode_key(d, Qx, Qy, order, oid): + private_key = long_to_bytes(d, order) + public_key = bytes_to_bits(chr(0x04) + long_to_bytes(Qx, order) + long_to_bytes(Qy, order)) parameters = oid key = ECPrivateKey() key["version"] = 1 @@ -104,8 +97,8 @@ def encode_key(d, Qx, Qy, oid): key["publicKey"] = public_key return DER_Encode(key) -p256_key = encode_key(p256_d, p256_Qx, p256_Qy, "1.2.840.10045.3.1.7") -p384_key = encode_key(p384_d, p384_Qx, p384_Qy, "1.3.132.0.34") +p256_key = encode_key(p256_d, p256_Qx, p256_Qy, 256, "1.2.840.10045.3.1.7") +p384_key = encode_key(p384_d, p384_Qx, p384_Qy, 384, "1.3.132.0.34") ### @@ -125,11 +118,12 @@ for name in dir(): vars = sorted(vars) for curve in curves: + order = int(curve[1:]) for var in vars: name = curve + "_" + var value = globals().get(name, None) if isinstance(value, (int, long)): - value = long_to_bytes(value) + value = long_to_bytes(value, order) if value is not None: print print "static const uint8_t %s[] = { /* %d bytes */" % (name, len(value)) @@ -138,14 +132,14 @@ for curve in curves: print print "typedef struct {" -print " hal_ecdsa_curve_t curve;" +print " hal_curve_name_t curve;" for var in vars: print " const uint8_t *%8s; size_t %8s_len;" % (var, var) print "} ecdsa_tc_t;" print print "static const ecdsa_tc_t ecdsa_tc[] = {" for curve in curves: - print " { HAL_ECDSA_CURVE_%s," % curve.upper() + print " { HAL_CURVE_%s," % curve.upper() for var in vars: name = curve + "_" + var if name in globals(): diff --git a/tests/test-hash.c b/tests/test-hash.c index 0cceb8a..e8c6a01 100644 --- a/tests/test-hash.c +++ b/tests/test-hash.c @@ -534,9 +534,6 @@ static int _test_hash(const hal_core_t *core, const uint8_t * const result, const size_t result_len, const char * const label) { - if (core == NULL) - return 1; - uint8_t statebuf[512], digest[512]; hal_hash_state_t *state = NULL; hal_error_t err; @@ -586,9 +583,6 @@ static int _test_hmac(const hal_core_t *core, const uint8_t * const result, const size_t result_len, const char * const label) { - if (core == NULL) - return 1; - uint8_t statebuf[1024], digest[512]; hal_hmac_state_t *state = NULL; hal_error_t err; diff --git a/tests/test-rpc_get_random.c b/tests/test-rpc_get_random.c new file mode 100644 index 0000000..9e9765d --- /dev/null +++ b/tests/test-rpc_get_random.c @@ -0,0 +1,69 @@ +/* + * test-rpc_get_random.c + * --------------------- + * Test code for RPC interface to Cryptech hash cores. + * + * Copyright (c) 2016, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <hal.h> + +#define DEFAULT_LEN 16 + +static void hexdump(uint8_t *buf, int len) +{ + for (int i = 0; i < len; ++i) + printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' '); + if ((len & 0x07) != 0) + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + int len = 0; + if (argc > 1) + len = atoi(argv[1]); + if (len <= 0) /* no arg, or bad arg */ + len = DEFAULT_LEN; + + uint8_t rnd[len]; + +#define check(op) { hal_error_t err; if ((err = (op)) != HAL_OK) { printf("%s: %s\n", #op, hal_error_string(err)); return 1; } } + + check(hal_rpc_client_init()); + check(hal_rpc_get_random(rnd, sizeof(rnd))); + + hexdump(rnd, len); + + return 0; +} diff --git a/tests/test-rpc_get_version.c b/tests/test-rpc_get_version.c new file mode 100644 index 0000000..ae1b745 --- /dev/null +++ b/tests/test-rpc_get_version.c @@ -0,0 +1,51 @@ +/* + * test-rpc_get_version.c + * ---------------------- + * Test code for RPC interface to Cryptech hash cores. + * + * Copyright (c) 2016, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include <hal.h> + +int main(int argc, char *argv[]) +{ + uint32_t version; + +#define check(op) { hal_error_t err; if ((err = (op)) != HAL_OK) { printf("%s: %s\n", #op, hal_error_string(err)); return 1; } } + + check(hal_rpc_client_init()); + check(hal_rpc_get_version(&version)); + printf("%08x\n", version); + + return 0; +} diff --git a/tests/test-rpc_hash.c b/tests/test-rpc_hash.c new file mode 100644 index 0000000..a0c571c --- /dev/null +++ b/tests/test-rpc_hash.c @@ -0,0 +1,715 @@ +/* + * test-rpc_hash.c + * --------------- + * Test code for RPC interface to Cryptech hash cores. + * + * Authors: Rob Austein, Paul Selkirk + * Copyright (c) 2015-2016, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include <hal.h> + +/* Usual NIST sample messages. */ + +/* "abc" */ +static const uint8_t nist_512_single[] = { /* 3 bytes */ + 0x61, 0x62, 0x63 +}; + +static const uint8_t sha1_single_digest[] = { /* 20 bytes */ + 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 0x25, 0x71, + 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d +}; + +static const uint8_t sha256_single_digest[] = { /* 32 bytes */ + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad +}; + +/* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */ +static const uint8_t nist_512_double[] = { /* 56 bytes */ + 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, + 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, + 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b, 0x69, 0x6a, 0x6b, 0x6c, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f, + 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71 +}; + +static const uint8_t sha1_double_digest[] = { /* 20 bytes */ + 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae, 0x4a, 0xa1, + 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 +}; + +static const uint8_t sha256_double_digest[] = { /* 32 bytes */ + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, + 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 +}; + +/* "abc" */ +static const uint8_t nist_1024_single[] = { /* 3 bytes */ + 0x61, 0x62, 0x63 +}; + +static const uint8_t sha512_224_single_digest[] = { /* 28 bytes */ + 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54, 0xda, 0xae, 0x75, 0x30, + 0x46, 0x08, 0x42, 0xe2, 0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4, + 0x3e, 0x89, 0x24, 0xaa +}; + +static const uint8_t sha512_256_single_digest[] = { /* 32 bytes */ + 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, 0x9b, 0x2e, 0x29, 0xb7, + 0x6b, 0x4c, 0x7d, 0xab, 0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46, + 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23 +}; + +static const uint8_t sha384_single_digest[] = { /* 48 bytes */ + 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69, + 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b, + 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 +}; + +static const uint8_t sha512_single_digest[] = { /* 64 bytes */ + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, + 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, + 0xa5, 0x4c, 0xa4, 0x9f +}; + +/* "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" */ +static const uint8_t nist_1024_double[] = { /* 112 bytes */ + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, + 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x68, 0x69, 0x6a, 0x6b, + 0x6c, 0x6d, 0x6e, 0x6f, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x6b, 0x6c, 0x6d, 0x6e, + 0x6f, 0x70, 0x71, 0x72, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x6e, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75 +}; + +static const uint8_t sha512_224_double_digest[] = { /* 28 bytes */ + 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23, 0x30, 0x81, 0x92, 0x64, + 0x0b, 0x0c, 0x45, 0x33, 0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72, + 0x68, 0x67, 0x4a, 0xf9 +}; + +static const uint8_t sha512_256_double_digest[] = { /* 32 bytes */ + 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8, 0x40, 0xda, 0x39, 0x88, + 0x12, 0x1d, 0x31, 0xbe, 0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14, + 0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a +}; + +static const uint8_t sha384_double_digest[] = { /* 48 bytes */ + 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, 0x3d, 0x19, 0x2f, 0xc7, + 0x82, 0xcd, 0x1b, 0x47, 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, + 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, 0xfc, 0xc7, 0xc7, 0x1a, + 0x55, 0x7e, 0x2d, 0xb9, 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 +}; + +static const uint8_t sha512_double_digest[] = { /* 64 bytes */ + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7, 0x28, + 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50, 0x1d, 0x28, 0x9e, + 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b, + 0x87, 0x4b, 0xe9, 0x09 +}; + +/* HMAC-SHA-1 test cases from RFC 2202. */ + +static const uint8_t hmac_sha1_tc_1_key[] = { /* 20 bytes */ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b +}; + +/* 'Hi There' */ +static const uint8_t hmac_sha1_tc_1_data[] = { /* 8 bytes */ + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 +}; + +static const uint8_t hmac_sha1_tc_1_result_sha1[] = { /* 20 bytes */ + 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b, 0xc0, 0xb6, + 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00 +}; + +/* 'Jefe' */ +static const uint8_t hmac_sha1_tc_2_key[] = { /* 4 bytes */ + 0x4a, 0x65, 0x66, 0x65 +}; + +/* 'what do ya want for nothing?' */ +static const uint8_t hmac_sha1_tc_2_data[] = { /* 28 bytes */ + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, + 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f +}; + +static const uint8_t hmac_sha1_tc_2_result_sha1[] = { /* 20 bytes */ + 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74, 0x16, 0xd5, + 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79 +}; + +static const uint8_t hmac_sha1_tc_3_key[] = { /* 20 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +static const uint8_t hmac_sha1_tc_3_data[] = { /* 50 bytes */ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; + +static const uint8_t hmac_sha1_tc_3_result_sha1[] = { /* 20 bytes */ + 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, 0x91, 0xa3, 0x9a, 0xf4, + 0x8a, 0xa1, 0x7b, 0x4f, 0x63, 0xf1, 0x75, 0xd3 +}; + +static const uint8_t hmac_sha1_tc_4_key[] = { /* 25 bytes */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 +}; + +static const uint8_t hmac_sha1_tc_4_data[] = { /* 50 bytes */ + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd +}; + +static const uint8_t hmac_sha1_tc_4_result_sha1[] = { /* 20 bytes */ + 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, 0xbc, 0x84, 0x14, 0xf9, + 0xbf, 0x50, 0xc8, 0x6c, 0x2d, 0x72, 0x35, 0xda +}; + +static const uint8_t hmac_sha1_tc_5_key[] = { /* 20 bytes */ + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c +}; + +/* 'Test With Truncation' */ +static const uint8_t hmac_sha1_tc_5_data[] = { /* 20 bytes */ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72, + 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e +}; + +static const uint8_t hmac_sha1_tc_5_result_sha1[] = { /* 20 bytes */ + 0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2, 0x7b, 0xe1, + 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04 +}; + +static const uint8_t hmac_sha1_tc_6_key[] = { /* 80 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +/* 'Test Using Larger Than Block-Size Key - Hash Key First' */ +static const uint8_t hmac_sha1_tc_6_data[] = { /* 54 bytes */ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, + 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 +}; + +static const uint8_t hmac_sha1_tc_6_result_sha1[] = { /* 20 bytes */ + 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, 0x95, 0x70, 0x56, 0x37, + 0xce, 0x8a, 0x3b, 0x55, 0xed, 0x40, 0x21, 0x12 +}; + +static const uint8_t hmac_sha1_tc_7_key[] = { /* 80 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +/* 'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data' */ +static const uint8_t hmac_sha1_tc_7_data[] = { /* 73 bytes */ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x4f, 0x6e, 0x65, 0x20, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61 +}; + +static const uint8_t hmac_sha1_tc_7_result_sha1[] = { /* 20 bytes */ + 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, 0x6b, 0xba, 0xa7, + 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91 +}; + +/* HMAC-SHA-2 test cases from RFC 4231. */ + +static const uint8_t hmac_sha2_tc_1_key[] = { /* 20 bytes */ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b +}; + +/* 'Hi There' */ +static const uint8_t hmac_sha2_tc_1_data[] = { /* 8 bytes */ + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 +}; + +static const uint8_t hmac_sha2_tc_1_result_sha256[] = { /* 32 bytes */ + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, + 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 +}; + +static const uint8_t hmac_sha2_tc_1_result_sha384[] = { /* 48 bytes */ + 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4, + 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, + 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9, + 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 +}; + +static const uint8_t hmac_sha2_tc_1_result_sha512[] = { /* 64 bytes */ + 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, + 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, + 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, + 0xd6, 0xb8, 0xa7, 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, + 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, + 0x3a, 0x12, 0x68, 0x54 +}; + +/* 'Jefe' */ +static const uint8_t hmac_sha2_tc_2_key[] = { /* 4 bytes */ + 0x4a, 0x65, 0x66, 0x65 +}; + +/* 'what do ya want for nothing?' */ +static const uint8_t hmac_sha2_tc_2_data[] = { /* 28 bytes */ + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, + 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f +}; + +static const uint8_t hmac_sha2_tc_2_result_sha256[] = { /* 32 bytes */ + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, + 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 +}; + +static const uint8_t hmac_sha2_tc_2_result_sha384[] = { /* 48 bytes */ + 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2, + 0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, + 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca, + 0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 +}; + +static const uint8_t hmac_sha2_tc_2_result_sha512[] = { /* 64 bytes */ + 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, + 0x3b, 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, + 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, + 0xc0, 0x5a, 0x99, 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, + 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, + 0x38, 0xbc, 0xe7, 0x37 +}; + +static const uint8_t hmac_sha2_tc_3_key[] = { /* 20 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +static const uint8_t hmac_sha2_tc_3_data[] = { /* 50 bytes */ + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd +}; + +static const uint8_t hmac_sha2_tc_3_result_sha256[] = { /* 32 bytes */ + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, + 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe +}; + +static const uint8_t hmac_sha2_tc_3_result_sha384[] = { /* 48 bytes */ + 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0, + 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, + 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d, + 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27 +}; + +static const uint8_t hmac_sha2_tc_3_result_sha512[] = { /* 64 bytes */ + 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, + 0x6c, 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, + 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, + 0x79, 0xa7, 0x22, 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, + 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, + 0xe1, 0x32, 0x92, 0xfb +}; + +static const uint8_t hmac_sha2_tc_4_key[] = { /* 25 bytes */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 +}; + +static const uint8_t hmac_sha2_tc_4_data[] = { /* 50 bytes */ + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd +}; + +static const uint8_t hmac_sha2_tc_4_result_sha256[] = { /* 32 bytes */ + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, + 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b +}; + +static const uint8_t hmac_sha2_tc_4_result_sha384[] = { /* 48 bytes */ + 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62, + 0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c, + 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23, + 0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb +}; + +static const uint8_t hmac_sha2_tc_4_result_sha512[] = { /* 64 bytes */ + 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, + 0xf6, 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, + 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, + 0x1a, 0xa2, 0x5e, 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, + 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, + 0x10, 0xa2, 0x98, 0xdd +}; + +/* Skipping HMAC-SHA-2 test case 5. */ + +static const uint8_t hmac_sha2_tc_6_key[] = { /* 131 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +/* 'Test Using Larger Than Block-Size Key - Hash Key First' */ +static const uint8_t hmac_sha2_tc_6_data[] = { /* 54 bytes */ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, + 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 +}; + +static const uint8_t hmac_sha2_tc_6_result_sha256[] = { /* 32 bytes */ + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, + 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 +}; + +static const uint8_t hmac_sha2_tc_6_result_sha384[] = { /* 48 bytes */ + 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a, + 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, + 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab, + 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 +}; + +static const uint8_t hmac_sha2_tc_6_result_sha512[] = { /* 64 bytes */ + 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, + 0xdd, 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, + 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, + 0xe0, 0x5f, 0x25, 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, + 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, + 0x5d, 0x78, 0x65, 0x98 +}; + +static const uint8_t hmac_sha2_tc_7_key[] = { /* 131 bytes */ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +/* 'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.' */ +static const uint8_t hmac_sha2_tc_7_data[] = { /* 152 bytes */ + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e +}; + +static const uint8_t hmac_sha2_tc_7_result_sha256[] = { /* 32 bytes */ + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, + 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 +}; + +static const uint8_t hmac_sha2_tc_7_result_sha384[] = { /* 48 bytes */ + 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25, + 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, + 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31, + 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e +}; + +static const uint8_t hmac_sha2_tc_7_result_sha512[] = { /* 64 bytes */ + 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, + 0x6e, 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, + 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, + 0x3c, 0x49, 0x82, 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, + 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, + 0xfa, 0x8c, 0x6a, 0x58 +}; + +static int _test_hash(const hal_digest_algorithm_t alg, + const uint8_t * const data, const size_t data_len, + const uint8_t * const result, const size_t result_len, + const char * const label) +{ + uint8_t digest[512]; + hal_error_t err; + static hal_digest_algorithm_t last_alg = -1; + static hal_error_t last_err = -1; + + if (last_alg == alg && last_err == HAL_ERROR_CORE_NOT_FOUND) + return 1; + + assert(data != NULL && result != NULL && label != NULL); + assert(result_len <= sizeof(digest)); + + printf("Starting %s test\n", label); + + hal_client_handle_t client = {0}; + hal_session_handle_t session = {0}; + hal_hash_handle_t hash; + + err = hal_rpc_hash_initialize(client, session, &hash, alg, NULL, 0); + last_alg = alg; + last_err = err; + if (err != HAL_OK) { + printf("Failed while initializing hash: %s\n", hal_error_string(err)); + return 0; + } + + if ((err = hal_rpc_hash_update(hash, data, data_len)) != HAL_OK) { + printf("Failed while updating hash: %s\n", hal_error_string(err)); + return 0; + } + + if ((err = hal_rpc_hash_finalize(hash, digest, sizeof(digest))) != HAL_OK) { + printf("Failed while finalizing hash: %s\n", hal_error_string(err)); + return 0; + } + + printf("Comparing result with known value\n"); + if (memcmp(result, digest, result_len)) { + size_t i; + printf("MISMATCH\nExpected:"); + for (i = 0; i < result_len; i++) + printf(" %02x", result[i]); + printf("\nGot: "); + for (i = 0; i < result_len; i++) + printf(" %02x", digest[i]); + printf("\n"); + return 0; + } + + printf("OK\n"); + last_err = err; + return 1; +} + +static int _test_hmac(const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_len, + const uint8_t * const data, const size_t data_len, + const uint8_t * const result, const size_t result_len, + const char * const label) +{ + uint8_t digest[512]; + hal_error_t err; + static hal_digest_algorithm_t last_alg = -1; + static hal_error_t last_err = -1; + + if (last_alg == alg && last_err == HAL_ERROR_CORE_NOT_FOUND) + return 1; + + assert(data != NULL && result != NULL && label != NULL); + assert(result_len <= sizeof(digest)); + + printf("Starting %s test\n", label); + + hal_client_handle_t client = {0}; + hal_session_handle_t session = {0}; + hal_hash_handle_t hash; + + err = hal_rpc_hash_initialize(client, session, &hash, alg, key, key_len); + last_alg = alg; + last_err = err; + if (err != HAL_OK) { + printf("Failed while initializing HMAC: %s\n", hal_error_string(err)); + return 0; + } + + if ((err = hal_rpc_hash_update(hash, data, data_len)) != HAL_OK) { + printf("Failed while updating HMAC: %s\n", hal_error_string(err)); + return 0; + } + + if ((err = hal_rpc_hash_finalize(hash, digest, sizeof(digest))) != HAL_OK) { + printf("Failed while finalizing HMAC: %s\n", hal_error_string(err)); + return 0; + } + + printf("Comparing result with known value\n"); + if (memcmp(result, digest, result_len)) { + size_t i; + printf("MISMATCH\nExpected:"); + for (i = 0; i < result_len; i++) + printf(" %02x", result[i]); + printf("\nGot: "); + for (i = 0; i < result_len; i++) + printf(" %02x", digest[i]); + printf("\n"); + return 0; + } + + printf("OK\n"); + return 1; +} + +#define test_hash(_alg_, _data_, _result_, _label_) \ + _test_hash(_alg_, _data_, sizeof(_data_), _result_, sizeof(_result_), _label_) + +#define test_hmac(_alg_, _key_, _data_, _result_, _label_) \ + _test_hmac(_alg_, _key_, sizeof(_key_), _data_, sizeof(_data_), _result_, sizeof(_result_), _label_) + +int main (int argc, char *argv[]) +{ + int ok = 1; + + ok &= hal_rpc_client_init(); + + ok &= test_hash(hal_digest_algorithm_sha1, nist_512_single, sha1_single_digest, "SHA-1 single block"); + ok &= test_hash(hal_digest_algorithm_sha1, nist_512_double, sha1_double_digest, "SHA-1 double block"); + + ok &= test_hash(hal_digest_algorithm_sha256, nist_512_single, sha256_single_digest, "SHA-256 single block"); + ok &= test_hash(hal_digest_algorithm_sha256, nist_512_double, sha256_double_digest, "SHA-256 double block"); + + ok &= test_hash(hal_digest_algorithm_sha512_224, nist_1024_single, sha512_224_single_digest, "SHA-512/224 single block"); + ok &= test_hash(hal_digest_algorithm_sha512_224, nist_1024_double, sha512_224_double_digest, "SHA-512/224 double block"); + + ok &= test_hash(hal_digest_algorithm_sha512_256, nist_1024_single, sha512_256_single_digest, "SHA-512/256 single block"); + ok &= test_hash(hal_digest_algorithm_sha512_256, nist_1024_double, sha512_256_double_digest, "SHA-512/256 double block"); + + ok &= test_hash(hal_digest_algorithm_sha384, nist_1024_single, sha384_single_digest, "SHA-384 single block"); + ok &= test_hash(hal_digest_algorithm_sha384, nist_1024_double, sha384_double_digest, "SHA-384 double block"); + + ok &= test_hash(hal_digest_algorithm_sha512, nist_1024_single, sha512_single_digest, "SHA-512 single block"); + ok &= test_hash(hal_digest_algorithm_sha512, nist_1024_double, sha512_double_digest, "SHA-512 double block"); + + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_1_key, hmac_sha1_tc_1_data, hmac_sha1_tc_1_result_sha1, "HMAC-SHA-1 test case 1"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_2_key, hmac_sha1_tc_2_data, hmac_sha1_tc_2_result_sha1, "HMAC-SHA-1 test case 2"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_3_key, hmac_sha1_tc_3_data, hmac_sha1_tc_3_result_sha1, "HMAC-SHA-1 test case 3"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_4_key, hmac_sha1_tc_4_data, hmac_sha1_tc_4_result_sha1, "HMAC-SHA-1 test case 4"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_5_key, hmac_sha1_tc_5_data, hmac_sha1_tc_5_result_sha1, "HMAC-SHA-1 test case 5"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_6_key, hmac_sha1_tc_6_data, hmac_sha1_tc_6_result_sha1, "HMAC-SHA-1 test case 6"); + ok &= test_hmac(hal_digest_algorithm_sha1, hmac_sha1_tc_7_key, hmac_sha1_tc_7_data, hmac_sha1_tc_7_result_sha1, "HMAC-SHA-1 test case 7"); + + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha256, "HMAC-SHA-256 test case 1"); + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha256, "HMAC-SHA-256 test case 2"); + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha256, "HMAC-SHA-256 test case 3"); + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha256, "HMAC-SHA-256 test case 4"); + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha256, "HMAC-SHA-256 test case 6"); + ok &= test_hmac(hal_digest_algorithm_sha256, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha256, "HMAC-SHA-256 test case 7"); + + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha384, "HMAC-SHA-384 test case 1"); + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha384, "HMAC-SHA-384 test case 2"); + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha384, "HMAC-SHA-384 test case 3"); + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha384, "HMAC-SHA-384 test case 4"); + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha384, "HMAC-SHA-384 test case 6"); + ok &= test_hmac(hal_digest_algorithm_sha384, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha384, "HMAC-SHA-384 test case 7"); + + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_1_key, hmac_sha2_tc_1_data, hmac_sha2_tc_1_result_sha512, "HMAC-SHA-512 test case 1"); + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_2_key, hmac_sha2_tc_2_data, hmac_sha2_tc_2_result_sha512, "HMAC-SHA-512 test case 2"); + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_3_key, hmac_sha2_tc_3_data, hmac_sha2_tc_3_result_sha512, "HMAC-SHA-512 test case 3"); + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_4_key, hmac_sha2_tc_4_data, hmac_sha2_tc_4_result_sha512, "HMAC-SHA-512 test case 4"); + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_6_key, hmac_sha2_tc_6_data, hmac_sha2_tc_6_result_sha512, "HMAC-SHA-512 test case 6"); + ok &= test_hmac(hal_digest_algorithm_sha512, hmac_sha2_tc_7_key, hmac_sha2_tc_7_data, hmac_sha2_tc_7_result_sha512, "HMAC-SHA-512 test case 7"); + + ok &= hal_rpc_client_close(); + + return !ok; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/test-rpc_pkey.c b/tests/test-rpc_pkey.c new file mode 100644 index 0000000..f5374b3 --- /dev/null +++ b/tests/test-rpc_pkey.c @@ -0,0 +1,344 @@ +/* + * test-rpc_pkey.c + * --------------- + * Test code for RPC interface to Cryptech public key operations. + * + * Authors: Rob Austein, Paul Selkirk + * Copyright (c) 2015-2016, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include <hal.h> + +#include "test-rsa.h" +#include "test-ecdsa.h" + +static inline const char *ecdsa_curve_to_string(const hal_curve_name_t curve) +{ + switch (curve) { + case HAL_CURVE_P256: return "P-256"; + case HAL_CURVE_P384: return "P-384"; + case HAL_CURVE_P521: return "P-521"; + default: return "?????"; + } +} + +static int test_rsa_testvec(const rsa_tc_t * const tc) +{ + const hal_client_handle_t client = {0}; + const hal_session_handle_t session = {0}; + hal_pkey_handle_t private_key, public_key; + hal_error_t err; + size_t len; + + assert(tc != NULL); + + printf("Starting %lu-bit RSA test vector tests\n", (unsigned long) tc->size); + + uint8_t tc_keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *tc_key = NULL; + + if ((err = hal_rsa_key_load_private(&tc_key, + tc_keybuf, sizeof(tc_keybuf), + tc->n.val, tc->n.len, + tc->e.val, tc->e.len, + tc->d.val, tc->d.len, + tc->p.val, tc->p.len, + tc->q.val, tc->q.len, + tc->u.val, tc->u.len, + tc->dP.val, tc->dP.len, + tc->dQ.val, tc->dQ.len)) != HAL_OK) + return printf("Could not load RSA private key from test vector: %s\n", hal_error_string(err)), 0; + + const uint8_t private_label[] = "RSA private key", public_label[] = "RSA public key"; + + uint8_t private_der[hal_rsa_private_key_to_der_len(tc_key)]; + uint8_t public_der[hal_rsa_public_key_to_der_len(tc_key)]; + + if ((err = hal_rsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK) + return printf("Could not DER encode private key from test vector: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(private_der)); + + if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, + private_label, sizeof(private_label), private_der, sizeof(private_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load private key into RPC: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK) + return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(public_der)); + + if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, + public_label, sizeof(public_label), public_der, sizeof(public_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0; + + uint8_t sig[tc->s.len]; + + /* + * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo. + */ + assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff); + const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2); + assert(digestinfo != NULL); + const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo; + + if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none, + digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK) + return printf("Could not sign: %s\n", hal_error_string(err)), 0; + + if (tc->s.len != len || memcmp(sig, tc->s.val, tc->s.len) != 0) + return printf("MISMATCH\n"), 0; + + if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none, + digestinfo, digestinfo_len, tc->s.val, tc->s.len)) != HAL_OK) + return printf("Could not verify: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK) + return printf("Could not delete private key: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) + return printf("Could not delete public key: %s\n", hal_error_string(err)), 0; + + printf("OK\n"); + return 1; +} + +static int test_ecdsa_testvec(const ecdsa_tc_t * const tc) +{ + const hal_client_handle_t client = {0}; + const hal_session_handle_t session = {0}; + hal_pkey_handle_t private_key, public_key; + hal_error_t err; + size_t len; + + assert(tc != NULL); + + printf("Starting ECDSA %s test vector tests\n", ecdsa_curve_to_string(tc->curve)); + + uint8_t tc_keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *tc_key = NULL; + + if ((err = hal_ecdsa_key_load_private(&tc_key, tc_keybuf, sizeof(tc_keybuf), tc->curve, + tc->Qx, tc->Qx_len, tc->Qy, tc->Qy_len, + tc->d, tc->d_len)) != HAL_OK) + return printf("Could not load ECDSA private key from test vector: %s\n", hal_error_string(err)), 0; + + const uint8_t private_label[] = "ECDSA private key", public_label[] = "ECDSA public key"; + + uint8_t private_der[hal_ecdsa_private_key_to_der_len(tc_key)]; + uint8_t public_der[hal_ecdsa_public_key_to_der_len(tc_key)]; + + if ((err = hal_ecdsa_private_key_to_der(tc_key, private_der, &len, sizeof(private_der))) != HAL_OK) + return printf("Could not DER encode private key from test vector: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(private_der)); + + if ((err = hal_rpc_pkey_load(client, session, &private_key, HAL_KEY_TYPE_EC_PRIVATE, tc->curve, + private_label, sizeof(private_label), private_der, sizeof(private_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load private key into RPC: %s\n", hal_error_string(err)), 0; + + if ((err = hal_ecdsa_public_key_to_der(tc_key, public_der, &len, sizeof(public_der))) != HAL_OK) + return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(public_der)); + + if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve, + public_label, sizeof(public_label), public_der, sizeof(public_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none, + tc->H, tc->H_len, tc->sig, tc->sig_len)) != HAL_OK) + return printf("Could not verify signature from test vector: %s\n", hal_error_string(err)), 0; + + uint8_t sig[tc->sig_len + 4]; + + if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none, + tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK) + return printf("Could not sign: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none, + tc->H, tc->H_len, sig, len)) != HAL_OK) + return printf("Could not verify own signature: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK) + return printf("Could not delete private key: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) + return printf("Could not delete public key: %s\n", hal_error_string(err)), 0; + + printf("OK\n"); + return 1; +} + +static int test_rsa_generate(const rsa_tc_t * const tc) +{ + const hal_client_handle_t client = {0}; + const hal_session_handle_t session = {0}; + hal_pkey_handle_t private_key, public_key; + hal_error_t err; + size_t len; + + assert(tc != NULL); + + printf("Starting %lu-bit RSA key generation tests\n", (unsigned long) tc->size); + + const uint8_t private_label[] = "Generated RSA private key", public_label[] = "Generated RSA public key"; + + if ((err = hal_rpc_pkey_generate_rsa(client, session, &private_key, private_label, sizeof(private_label), + tc->size, tc->e.val, tc->e.len, + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not generate RSA private key: %s\n", hal_error_string(err)), 0; + + uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)]; + + if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK) + return printf("Could not DER encode RPC RSA public key from RPC RSA private key: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(public_der)); + + if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_RSA_PUBLIC, HAL_CURVE_NONE, + public_label, sizeof(public_label), public_der, sizeof(public_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0; + + uint8_t sig[tc->s.len]; + + /* + * Raw RSA test cases include PKCS #1.5 padding, we need to drill down to the DigestInfo. + */ + assert(tc->m.len > 4 && tc->m.val[0] == 0x00 && tc->m.val[1] == 0x01 && tc->m.val[2] == 0xff); + const uint8_t *digestinfo = memchr(tc->m.val + 2, 0x00, tc->m.len - 2); + assert(digestinfo != NULL); + const size_t digestinfo_len = tc->m.val + tc->m.len - ++digestinfo; + + if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none, + digestinfo, digestinfo_len, sig, &len, sizeof(sig))) != HAL_OK) + return printf("Could not sign: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none, + digestinfo, digestinfo_len, sig, len)) != HAL_OK) + return printf("Could not verify: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK) + return printf("Could not delete private key: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) + return printf("Could not delete public key: %s\n", hal_error_string(err)), 0; + + printf("OK\n"); + return 1; +} + +static int test_ecdsa_generate(const ecdsa_tc_t * const tc) +{ + const hal_client_handle_t client = {0}; + const hal_session_handle_t session = {0}; + hal_pkey_handle_t private_key, public_key; + hal_error_t err; + size_t len; + + assert(tc != NULL); + + printf("Starting ECDSA %s key generation tests\n", ecdsa_curve_to_string(tc->curve)); + + const uint8_t private_label[] = "Generated ECDSA private key", public_label[] = "Generated ECDSA public key"; + + if ((err = hal_rpc_pkey_generate_ec(client, session, &private_key, + private_label, sizeof(private_label), + tc->curve, HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not generate EC key pair: %s\n", hal_error_string(err)), 0; + + uint8_t public_der[hal_rpc_pkey_get_public_key_len(private_key)]; + + if ((err = hal_rpc_pkey_get_public_key(private_key, public_der, &len, sizeof(public_der))) != HAL_OK) + return printf("Could not DER encode public key from test vector: %s\n", hal_error_string(err)), 0; + + assert(len == sizeof(public_der)); + + if ((err = hal_rpc_pkey_load(client, session, &public_key, HAL_KEY_TYPE_EC_PUBLIC, tc->curve, + public_label, sizeof(public_label), public_der, sizeof(public_der), + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)) != HAL_OK) + return printf("Could not load public key into RPC: %s\n", hal_error_string(err)), 0; + + uint8_t sig[tc->sig_len + 4]; + + if ((err = hal_rpc_pkey_sign(session, private_key, hal_hash_handle_none, + tc->H, tc->H_len, sig, &len, sizeof(sig))) != HAL_OK) + return printf("Could not sign: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_verify(session, public_key, hal_hash_handle_none, + tc->H, tc->H_len, sig, len)) != HAL_OK) + return printf("Could not verify own signature: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(private_key)) != HAL_OK) + return printf("Could not delete private key: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rpc_pkey_delete(public_key)) != HAL_OK) + return printf("Could not delete public key: %s\n", hal_error_string(err)), 0; + + printf("OK\n"); + return 1; +} + +int main (int argc, char *argv[]) +{ + int ok = 1; + + hal_rpc_client_init(); + + for (int i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++) + ok &= test_rsa_testvec(&rsa_tc[i]); + + for (int i = 0; i < (sizeof(ecdsa_tc)/sizeof(*ecdsa_tc)); i++) + ok &= test_ecdsa_testvec(&ecdsa_tc[i]); + + for (int i = 0; i < (sizeof(rsa_tc)/sizeof(*rsa_tc)); i++) + ok &= test_rsa_generate(&rsa_tc[i]); + + for (int i = 0; i < (sizeof(ecdsa_tc)/sizeof(*ecdsa_tc)); i++) + ok &= test_ecdsa_generate(&ecdsa_tc[i]); + + return !ok; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/test-rpc_server.c b/tests/test-rpc_server.c new file mode 100644 index 0000000..eb11f6d --- /dev/null +++ b/tests/test-rpc_server.c @@ -0,0 +1,10 @@ +#include <hal.h> + +int main (int argc, char *argv[]) +{ + if (hal_rpc_server_init() != HAL_OK) + return 1; + + hal_rpc_server_main(); + return 0; +} diff --git a/tests/test-rsa.c b/tests/test-rsa.c index e7e831e..1fc516b 100644 --- a/tests/test-rsa.c +++ b/tests/test-rsa.c @@ -1,13 +1,7 @@ /* * test-rsa.c * ---------- - * First stumblings towards a test harness for RSA using Cryptech - * ModExp core. - * - * For the moment this just does modular exponentiation tests using - * RSA keys and pre-formatted data-to-be-signed, without attempting - * CRT or any of the other clever stuff we should be doing. This is - * not usable for any sane purpose other than testing. + * Test harness for RSA using Cryptech ModExp core. * * Authors: Rob Austein * Copyright (c) 2015, NORDUnet A/S @@ -67,15 +61,11 @@ static int test_modexp(const hal_core_t *core, printf("%s test for %lu-bit RSA key\n", kind, (unsigned long) tc->size); if (hal_modexp(core, msg->val, msg->len, exp->val, exp->len, - tc->n.val, tc->n.len, result, sizeof(result)) != HAL_OK) { - printf("ModExp failed\n"); - return 0; - } + tc->n.val, tc->n.len, result, sizeof(result)) != HAL_OK) + return printf("ModExp failed\n"), 0; - if (memcmp(result, val->val, val->len)) { - printf("MISMATCH\n"); - return 0; - } + if (memcmp(result, val->val, val->len)) + return printf("MISMATCH\n"), 0; return 1; } @@ -103,10 +93,8 @@ static int test_decrypt(const hal_core_t *core, tc->q.val, tc->q.len, tc->u.val, tc->u.len, tc->dP.val, tc->dP.len, - tc->dQ.val, tc->dQ.len)) != HAL_OK) { - printf("RSA CRT key load failed: %s\n", hal_error_string(err)); - return 0; - } + tc->dQ.val, tc->dQ.len)) != HAL_OK) + return printf("RSA CRT key load failed: %s\n", hal_error_string(err)), 0; uint8_t result[tc->n.len]; @@ -133,7 +121,7 @@ static int test_gen(const hal_core_t *core, { printf("%s test for %lu-bit RSA key\n", kind, (unsigned long) tc->size); - char fn[sizeof("test-rsa-key-xxxxxx.der")]; + char fn[sizeof("test-rsa-private-key-xxxxxx.der")]; uint8_t keybuf1[hal_rsa_key_t_size], keybuf2[hal_rsa_key_t_size]; hal_rsa_key_t *key1 = NULL, *key2 = NULL; hal_error_t err = HAL_OK; @@ -141,52 +129,39 @@ static int test_gen(const hal_core_t *core, const uint8_t f4[] = { 0x01, 0x00, 0x01 }; - if ((err = hal_rsa_key_gen(core, &key1, keybuf1, sizeof(keybuf1), bitsToBytes(tc->size), f4, sizeof(f4))) != HAL_OK) { - printf("RSA key generation failed: %s\n", hal_error_string(err)); - return 0; - } + if ((err = hal_rsa_key_gen(core, &key1, keybuf1, sizeof(keybuf1), bitsToBytes(tc->size), f4, sizeof(f4))) != HAL_OK) + return printf("RSA key generation failed: %s\n", hal_error_string(err)), 0; size_t der_len = 0; - if ((err = hal_rsa_key_to_der(key1, NULL, &der_len, 0)) != HAL_OK) { - printf("Getting DER length of RSA key failed: %s\n", hal_error_string(err)); - return 0; - } + if ((err = hal_rsa_private_key_to_der(key1, NULL, &der_len, 0)) != HAL_OK) + return printf("Getting DER length of RSA key failed: %s\n", hal_error_string(err)), 0; uint8_t der[der_len]; - if ((err = hal_rsa_key_to_der(key1, der, &der_len, sizeof(der))) != HAL_OK) { - printf("Converting RSA key to DER failed: %s\n", hal_error_string(err)); - return 0; - } + err = hal_rsa_private_key_to_der(key1, der, &der_len, sizeof(der)); - if ((err = hal_rsa_key_from_der(&key2, keybuf2, sizeof(keybuf2), der, sizeof(der))) != HAL_OK) { - printf("Converting RSA key back from DER failed: %s\n", hal_error_string(err)); - return 0; - } + snprintf(fn, sizeof(fn), "test-rsa-private-key-%04lu.der", (unsigned long) tc->size); + printf("Writing %s\n", fn); - if (memcmp(keybuf1, keybuf2, hal_rsa_key_t_size) != 0) { - printf("RSA key mismatch after conversion to and back from DER\n"); - return 0; - } + if ((f = fopen(fn, "wb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; - snprintf(fn, sizeof(fn), "test-rsa-key-%04lu.der", (unsigned long) tc->size); - printf("Writing %s\n", fn); + if (fwrite(der, der_len, 1, f) != 1) + return printf("Length mismatch writing %s\n", fn), 0; - if ((f = fopen(fn, "wb")) == NULL) { - printf("Couldn't open %s: %s\n", fn, strerror(errno)); - return 0; - } + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; - if (fwrite(der, der_len, 1, f) != 1) { - printf("Length mismatch writing %s\n", fn); - return 0; - } + /* Deferred error from hal_rsa_private_key_to_der() */ + if (err != HAL_OK) + return printf("Converting RSA private key to DER failed: %s\n", hal_error_string(err)), 0; - if (fclose(f) == EOF) { - printf("Couldn't close %s: %s\n", fn, strerror(errno)); - return 0; - } + if ((err = hal_rsa_private_key_from_der(&key2, keybuf2, sizeof(keybuf2), der, sizeof(der))) != HAL_OK) + return printf("Converting RSA key back from DER failed: %s\n", hal_error_string(err)), 0; + + if (memcmp(keybuf1, keybuf2, hal_rsa_key_t_size) != 0) + return printf("RSA private key mismatch after conversion to and back from DER\n"), 0; uint8_t result[tc->n.len]; @@ -196,31 +171,70 @@ static int test_gen(const hal_core_t *core, snprintf(fn, sizeof(fn), "test-rsa-sig-%04lu.der", (unsigned long) tc->size); printf("Writing %s\n", fn); - if ((f = fopen(fn, "wb")) == NULL) { - printf("Couldn't open %s: %s\n", fn, strerror(errno)); - return 0; - } + if ((f = fopen(fn, "wb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; - if (fwrite(result, sizeof(result), 1, f) != 1) { - printf("Length mismatch writing %s key\n", fn); - return 0; - } + if (fwrite(result, sizeof(result), 1, f) != 1) + return printf("Length mismatch writing %s\n", fn), 0; - if (fclose(f) == EOF) { - printf("Couldn't close %s: %s\n", fn, strerror(errno)); - return 0; - } + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; if (err != HAL_OK) /* Deferred failure from hal_rsa_decrypt(), above */ return 0; if ((err = hal_rsa_encrypt(core, key1, result, sizeof(result), result, sizeof(result))) != HAL_OK) - printf("RSA signature check failed: %s\n", hal_error_string(err)); + printf("First RSA signature check failed: %s\n", hal_error_string(err)); - const int mismatch = (err == HAL_OK && memcmp(result, tc->m.val, tc->m.len) != 0); + int mismatch = 0; - if (mismatch) - printf("MISMATCH\n"); + if (err == HAL_OK && memcmp(result, tc->m.val, tc->m.len) != 0) + mismatch = (printf("MISMATCH\n"), 1); + + hal_rsa_key_clear(key2); + key2 = NULL; + + if ((f = fopen(fn, "rb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; + + if (fread(result, sizeof(result), 1, f) != 1) + return printf("Length mismatch reading %s\n", fn), 0; + + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; + + err = hal_rsa_public_key_to_der(key1, der, &der_len, sizeof(der)); + + snprintf(fn, sizeof(fn), "test-rsa-public-key-%04lu.der", (unsigned long) tc->size); + printf("Writing %s\n", fn); + + if ((f = fopen(fn, "wb")) == NULL) + return printf("Couldn't open %s: %s\n", fn, strerror(errno)), 0; + + if (fwrite(der, der_len, 1, f) != 1) + return printf("Length mismatch writing %s\n", fn), 0; + + if (fclose(f) == EOF) + return printf("Couldn't close %s: %s\n", fn, strerror(errno)), 0; + + /* Deferred error from hal_rsa_public_key_to_der() */ + if (err != HAL_OK) + return printf("Converting RSA public key to DER failed: %s\n", hal_error_string(err)), 0; + + if ((err = hal_rsa_public_key_from_der(&key2, keybuf2, sizeof(keybuf2), der, der_len)) != HAL_OK) + return printf("Converting RSA public key back from DER failed: %s\n", hal_error_string(err)), 0; + + /* + * Can't directly compare private key with public key. We could + * extract and compare the public key components, not much point if + * the public key passes the signature verification test below. + */ + + if ((err = hal_rsa_encrypt(core, key2, result, sizeof(result), result, sizeof(result))) != HAL_OK) + return printf("Second RSA signature check failed: %s\n", hal_error_string(err)), 0; + + if (err == HAL_OK && memcmp(result, tc->m.val, tc->m.len) != 0) + mismatch = (printf("MISMATCH\n"), 1); hal_rsa_key_clear(key1); hal_rsa_key_clear(key2); diff --git a/utils/cores.c b/utils/cores.c index d59f834..18e994d 100644 --- a/utils/cores.c +++ b/utils/cores.c @@ -49,7 +49,7 @@ int main(int argc, char *argv[]) for (core = hal_core_iterate(NULL); core != NULL; core = hal_core_iterate(core)) { info = hal_core_info(core); - printf("%08lx: %8.8s %4.4s\n", info->base, info->name, info->version); + printf("%08lx: %8.8s %4.4s\n", (unsigned long)info->base, info->name, info->version); } return 0; diff --git a/verilog_constants.h b/verilog_constants.h index 879d2af..dfd102a 100644 --- a/verilog_constants.h +++ b/verilog_constants.h @@ -8,7 +8,7 @@ * hand-edited. * * Authors: Joachim Strombergson, Paul Selkirk, Rob Austein - * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -81,6 +81,7 @@ #define MODE_SHA_512_256 (1 << 2) #define MODE_SHA_384 (2 << 2) #define MODE_SHA_512 (3 << 2) +#define MODE_SHA_MASK (3 << 2) /* * RNG cores. @@ -0,0 +1,260 @@ +/* + * xdr.c + * ----- + * Serialization/deserialization routines, using XDR (RFC 4506) encoding. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> /* memcpy, memset */ + +#ifndef STM32F4XX +#include <arpa/inet.h> /* htonl/ntohl */ +#else +/* htonl is not available in arm-none-eabi headers or libc */ +#ifdef __ARMEL__ /* little endian */ +static inline uint32_t htonl(uint32_t w) +{ + return + ((w & 0x000000ff) << 24) + + ((w & 0x0000ff00) << 8) + + ((w & 0x00ff0000) >> 8) + + ((w & 0xff000000) >> 24); +} +#else +#define htonl(x) (x) +#endif +#define ntohl htonl +#endif + +#include "hal.h" +#include "xdr_internal.h" + +/* encode/decode_int. This covers int, unsigned int, enum, and bool types, + * which are all encoded as 32-bit big-endian fields. Signed integers are + * defined to use two's complement, but that's universal these days, yes? + */ + +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; + + /* buffer overflow check */ + if (limit - *outbuf < sizeof(value)) + return HAL_ERROR_XDR_BUFFER_OVERFLOW; + + **(uint32_t **)outbuf = htonl(value); + *outbuf += sizeof(value); + return HAL_OK; +} + +hal_error_t hal_xdr_decode_int(uint8_t **inbuf, const uint8_t * const limit, uint32_t *value) +{ + /* arg checks */ + if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + /* buffer overflow check */ + if (limit - *inbuf < sizeof(*value)) + return HAL_ERROR_XDR_BUFFER_OVERFLOW; + + *value = ntohl(**(uint32_t **)inbuf); + *inbuf += sizeof(*value); + return HAL_OK; +} + +/* encode/decode_buffer. This covers variable-length string and opaque types. + * The data is preceded by a 4-byte length word (encoded as above), and padded + * to a multiple of 4 bytes as necessary. + */ + +hal_error_t hal_xdr_encode_buffer(uint8_t **outbuf, const uint8_t * const limit, const uint8_t *value, const uint32_t len) +{ + hal_error_t ret; + + /* arg checks */ + if (outbuf == NULL || *outbuf == NULL || limit == NULL || + (value == NULL && len != 0)) + return HAL_ERROR_BAD_ARGUMENTS; + + /* buffer overflow check */ + if ((limit - *outbuf) < (((len + 3) & ~3) + sizeof(len))) + return HAL_ERROR_XDR_BUFFER_OVERFLOW; + + /* encode length */ + if ((ret = hal_xdr_encode_int(outbuf, limit, len)) != HAL_OK) + return ret; + + /* write the string or opaque data */ + memcpy(*outbuf, value, len); + *outbuf += len; + + /* pad if necessary */ + if (len & 3) { + size_t n = 4 - (len & 3); + memset(*outbuf, 0, n); + *outbuf += n; + } + + return HAL_OK; +} + +/* This version returns a pointer to the data in the input buffer. + * It is used in the rpc server. + */ +hal_error_t hal_xdr_decode_buffer_in_place(uint8_t **inbuf, const uint8_t * const limit, uint8_t ** const value, uint32_t * const len) +{ + hal_error_t ret; + uint32_t xdr_len; + uint8_t *orig_inbuf = *inbuf; + + /* arg checks */ + if (inbuf == NULL || *inbuf == NULL || limit == NULL || value == NULL || len == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + /* decode the length */ + if ((ret = hal_xdr_decode_int(inbuf, limit, &xdr_len)) != HAL_OK) + return ret; + + /* input and output buffer overflow checks vs decoded length */ + + /* decoded length is past the end of the input buffer; + * we're probably out of sync, but nothing we can do now + */ + if (limit - *inbuf < xdr_len) { + /* undo read of length */ + *inbuf = orig_inbuf; + return HAL_ERROR_XDR_BUFFER_OVERFLOW; + } + + /* return a pointer to the string or opaque data */ + *value = *inbuf; + *len = xdr_len; + + /* update the buffer pointer, skipping any padding bytes */ + *inbuf += (xdr_len + 3) & ~3; + + return HAL_OK; +} + +/* This version copies the data to the user-supplied buffer. + * It is used in the rpc client. + */ +hal_error_t hal_xdr_decode_buffer(uint8_t **inbuf, const uint8_t * const limit, uint8_t * const value, uint32_t * const len) +{ + hal_error_t ret; + uint8_t *vptr; + uint8_t *orig_inbuf = *inbuf; + uint32_t xdr_len; + + if ((ret = hal_xdr_decode_buffer_in_place(inbuf, limit, &vptr, &xdr_len)) == HAL_OK) { + *len = xdr_len; + if (*len < xdr_len) { + /* user buffer is too small, undo read of length */ + *inbuf = orig_inbuf; + return HAL_ERROR_XDR_BUFFER_OVERFLOW; + } + + memcpy(value, vptr, *len); + } + return ret; +} + +/* ---------------------------------------------------------------- */ + +#ifdef TEST +static void hexdump(uint8_t *buf, uint32_t len) +{ + for (uint32_t i = 0; i < len; ++i) + printf("%02x%c", buf[i], ((i & 0x07) == 0x07) ? '\n' : ' '); + if ((len & 0x07) != 0) + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + uint32_t i; + uint8_t buf[64] = {0}; + uint8_t *bufptr = buf, *readptr; + uint8_t *limit = buf + sizeof(buf); + hal_error_t ret; + uint8_t alphabet[] = "abcdefghijklmnopqrstuvwxyz"; + uint8_t readbuf[64] = {0}; + + printf("hal_xdr_encode_int: work to failure\n"); + for (i = 1; i < 100; ++i) { + if ((ret = hal_xdr_encode_int(&bufptr, limit, i)) != HAL_OK) { + printf("%d: %s\n", i, hal_error_string(ret)); + break; + } + } + hexdump(buf, ((uint8_t *)bufptr - buf)); + + printf("\nhal_xdr_decode_int:\n"); + readptr = buf; + while (readptr < bufptr) { + if ((ret = hal_xdr_decode_int(&readptr, limit, &i)) != HAL_OK) { + printf("%s\n", hal_error_string(ret)); + break; + } + printf("%u ", i); + } + printf("\n"); + + printf("\nhal_xdr_encode_buffer: work to failure\n"); + memset(buf, 0, sizeof(buf)); + bufptr = buf; + for (i = 1; i < 10; ++i) { + if ((ret = hal_xdr_encode_buffer(&bufptr, limit, alphabet, i)) != HAL_OK) { + printf("%d: %s\n", i, hal_error_string(ret)); + break; + } + } + hexdump(buf, ((uint8_t *)bufptr - buf)); + + printf("\nhal_xdr_decode_buffer:\n"); + readptr = buf; + i = sizeof(readbuf); + while (readptr < bufptr) { + if ((ret = hal_xdr_decode_buffer(&readptr, limit, readbuf, &i)) != HAL_OK) { + printf("%s\n", hal_error_string(ret)); + break; + } + printf("%u: ", i); for (int j = 0; j < i; ++j) putchar(readbuf[j]); putchar('\n'); + i = sizeof(readbuf); + memset(readbuf, 0, sizeof(readbuf)); + } + + return 0; +} +#endif diff --git a/xdr_internal.h b/xdr_internal.h new file mode 100644 index 0000000..00793b0 --- /dev/null +++ b/xdr_internal.h @@ -0,0 +1,66 @@ +/* + * xdr_internal.h + * -------------- + * Serialization/deserialization routines, using XDR (RFC 4506) encoding. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XDR_INTERNAL_H +#define _XDR_INTERNAL_H + + /* + * RPC serialization/deserialization routines, using XDR (RFC 4506) encoding. + */ + +hal_error_t hal_xdr_encode_int(uint8_t ** const outbuf, + const uint8_t * const limit, + const uint32_t value); + +hal_error_t hal_xdr_decode_int(uint8_t ** const inbuf, + const uint8_t * const limit, + uint32_t * const value); + +hal_error_t hal_xdr_encode_buffer(uint8_t ** const outbuf, + const uint8_t * const limit, + const uint8_t * const value, + const uint32_t len); + +hal_error_t hal_xdr_decode_buffer_in_place(uint8_t ** const inbuf, + const uint8_t * const limit, + uint8_t ** const vptr, + uint32_t * const len); + +hal_error_t hal_xdr_decode_buffer(uint8_t ** const inbuf, + const uint8_t * const limit, + uint8_t * const value, + uint32_t * const len); + + +#endif /* _XDR_INTERNAL_H*/ |