aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--GNUmakefile168
-rw-r--r--aes_keywrap.c2
-rw-r--r--asn1.c166
-rw-r--r--asn1_internal.h27
-rw-r--r--core.c2
-rw-r--r--csprng.c2
-rw-r--r--ecdsa.c290
-rw-r--r--hal.h356
-rw-r--r--hal_internal.h397
-rw-r--r--hal_io_eim.c2
-rw-r--r--hal_io_fmc.c207
-rw-r--r--hal_io_i2c.c2
-rw-r--r--hash.c485
-rw-r--r--ks.c302
-rw-r--r--ks_flash.c110
-rw-r--r--ks_mmap.c179
-rw-r--r--ks_volatile.c143
-rw-r--r--modexp.c2
-rw-r--r--pbkdf2.c2
-rw-r--r--rpc_api.c323
-rw-r--r--rpc_client.c813
-rw-r--r--rpc_client_loopback.c85
-rw-r--r--rpc_client_serial.c116
-rw-r--r--rpc_hash.c313
-rw-r--r--rpc_misc.c235
-rw-r--r--rpc_pkey.c837
-rw-r--r--rpc_server.c736
-rw-r--r--rpc_server_loopback.c89
-rw-r--r--rpc_server_serial.c79
-rw-r--r--rsa.c139
-rw-r--r--slip.c141
-rw-r--r--slip_internal.h51
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/GNUmakefile19
-rw-r--r--tests/test-bus.c3
-rw-r--r--tests/test-ecdsa.c87
-rw-r--r--tests/test-ecdsa.h39
-rw-r--r--tests/test-ecdsa.py50
-rw-r--r--tests/test-hash.c6
-rw-r--r--tests/test-rpc_get_random.c69
-rw-r--r--tests/test-rpc_get_version.c51
-rw-r--r--tests/test-rpc_hash.c715
-rw-r--r--tests/test-rpc_pkey.c344
-rw-r--r--tests/test-rpc_server.c10
-rw-r--r--tests/test-rsa.c154
-rw-r--r--utils/cores.c2
-rw-r--r--verilog_constants.h3
-rw-r--r--xdr.c260
-rw-r--r--xdr_internal.h66
50 files changed, 8264 insertions, 423 deletions
diff --git a/.gitignore b/.gitignore
index cdc0f27..6919235 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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.
diff --git a/asn1.c b/asn1.c
index 0794537..2206ec3 100644
--- a/asn1.c
+++ b/asn1.c
@@ -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:
diff --git a/core.c b/core.c
index 44cf3f0..b7bf3b0 100644
--- a/core.c
+++ b/core.c
@@ -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
diff --git a/csprng.c b/csprng.c
index 31a59d9..c6ae4e1 100644
--- a/csprng.c
+++ b/csprng.c
@@ -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
diff --git a/ecdsa.c b/ecdsa.c
index de382fd..e46904d 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -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
diff --git a/hal.h b/hal.h
index eb1e253..9f25e62 100644
--- a/hal.h
+++ b/hal.h
@@ -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
diff --git a/hash.c b/hash.c
index 2f8fa35..daa7e3a 100644
--- a/hash.c
+++ b/hash.c
@@ -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
diff --git a/ks.c b/ks.c
new file mode 100644
index 0000000..d1ce089
--- /dev/null
+++ b/ks.c
@@ -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:
+ */
diff --git a/modexp.c b/modexp.c
index 72da95f..b84c51b 100644
--- a/modexp.c
+++ b/modexp.c
@@ -46,7 +46,7 @@
#include <assert.h>
#include "hal.h"
-#include "verilog_constants.h"
+#include "hal_internal.h"
/*
* Whether we want debug output.
diff --git a/pbkdf2.c b/pbkdf2.c
index 2020f2d..f361328 100644
--- a/pbkdf2.c
+++ b/pbkdf2.c
@@ -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;
+}
diff --git a/rsa.c b/rsa.c
index a03b41a..bf52e8a 100644
--- a/rsa.c
+++ b/rsa.c
@@ -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:
diff --git a/slip.c b/slip.c
new file mode 100644
index 0000000..3b448f4
--- /dev/null
+++ b/slip.c
@@ -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.
diff --git a/xdr.c b/xdr.c
new file mode 100644
index 0000000..0d54f1b
--- /dev/null
+++ b/xdr.c
@@ -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*/