aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile38
-rw-r--r--asn1_internal.h17
-rw-r--r--ecdsa.c155
-rw-r--r--hal.h276
-rw-r--r--hal_internal.h294
-rw-r--r--hash.c102
-rw-r--r--ks.c280
-rw-r--r--ks_flash.c71
-rw-r--r--ks_mmap.c123
-rw-r--r--ks_volatile.c74
-rw-r--r--rpc.c330
-rw-r--r--rpc_client.c298
-rw-r--r--rpc_hash.c300
-rw-r--r--rpc_pkey.c734
-rw-r--r--rsa.c22
-rw-r--r--tests/test-bus.c3
-rw-r--r--tests/test-ecdsa.c25
-rw-r--r--tests/test-ecdsa.h39
-rw-r--r--tests/test-ecdsa.py50
-rw-r--r--utils/cores.c2
20 files changed, 2970 insertions, 263 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 769d11f..e0b4730 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -27,21 +27,47 @@
# 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
-
+ modexp.o rsa.o ecdsa.o asn1.o errorstrings.o ${RPC_OBJ} ${KS_OBJ}
IO_OBJ_EIM = hal_io_eim.o novena-eim.o
IO_OBJ_I2C = hal_io_i2c.o
# Default I/O bus is EIM, override this to use I2C instead
IO_OBJ = ${IO_OBJ_EIM}
+RPC_OBJ_COMMON = rpc.o rpc_hash.o
+RPC_OBJ_CLIENT = ${RPC_OBJ_COMMON} rpc_client.o
+RPC_OBJ_SERVER = ${RPC_OBJ_COMMON} rpc_misc.o rpc_pkey.o
+
+# Default should be to build the RPC server code, but we haven't
+# written even the skeleton of that yet. We'll probably end up
+# needing a makefile conditional to handle all this properly
+RPC_OBJ = ${RPC_OBJ_CLIENT}
+
+# XXX temporary
+$(warning TEMPORARY KLUDGE TO TEST rpc_pkey)
+RPC_OBJ += rpc_pkey.o
+
+# XXX temporary
+KS_OBJ = ks.o ks_mmap.o
+
TFMDIR := $(abspath ../thirdparty/libtfm)
CFLAGS += -g3 -Wall -fPIC -std=c99 -I${TFMDIR} -DHAL_ECDSA_DEBUG_ONLY_STATIC_TEST_VECTOR_RANDOM=1
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}' $@
cd utils; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@
@@ -51,9 +77,9 @@ ${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
test: all
cd tests; ${MAKE} -k $@
diff --git a/asn1_internal.h b/asn1_internal.h
index bfe9372..18d4852 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,7 @@ 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_ */
+#endif /* _HAL_ASN1_INTERNAL_H_ */
/*
* Local variables:
diff --git a/ecdsa.c b/ecdsa.c
index eeab252..c568a74 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -150,8 +150,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 +181,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,10 +230,10 @@ 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;
}
}
@@ -831,7 +831,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 +842,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 +859,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 +873,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 +929,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 +941,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 +966,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 +980,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 +1052,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 +1060,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;
@@ -1106,7 +1106,7 @@ hal_error_t hal_ecdsa_key_from_ecpoint(hal_ecdsa_key_t **key_,
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)
{
- 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);
@@ -1215,7 +1215,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,7 +1248,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++)
+ for (key->curve = HAL_CURVE_NONE; (curve = get_curve(++key->curve)) != NULL; )
if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0)
break;
if (curve == NULL)
@@ -1345,89 +1345,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 +1413,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 +1431,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 +1463,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..3fcf813 100644
--- a/hal.h
+++ b/hal.h
@@ -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,10 @@
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") \
END_OF_HAL_ERROR_LIST
/* Marker to forestall silly line continuation errors */
@@ -125,24 +133,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 +191,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.
*/
/*
@@ -221,7 +226,17 @@ typedef struct hal_hash_driver hal_hash_driver_t;
* problem.
*/
+typedef enum {
+ 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 +299,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 +345,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 +392,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,
@@ -399,12 +435,6 @@ extern hal_error_t hal_rsa_key_from_der(hal_rsa_key_t **key,
* ECDSA.
*/
-typedef enum { HAL_ECDSA_PRIVATE, HAL_ECDSA_PUBLIC } hal_ecdsa_key_type_t;
-
-typedef enum { HAL_ECDSA_CURVE_P256, HAL_ECDSA_CURVE_P384, HAL_ECDSA_CURVE_P521 } hal_ecdsa_curve_t;
-
-typedef enum { HAL_ECDSA_SIGNATURE_FORMAT_ASN1, HAL_ECDSA_SIGNATURE_FORMAT_PKCS11 } hal_ecdsa_signature_format_t;
-
typedef struct hal_ecdsa_key hal_ecdsa_key_t;
extern const size_t hal_ecdsa_key_t_size;
@@ -413,22 +443,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,7 +469,7 @@ 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_key_to_der(const hal_ecdsa_key_t * const key,
uint8_t *der, size_t *der_len, const size_t der_max);
@@ -458,19 +488,203 @@ 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.
+ */
+
+typedef struct { uint32_t handle; } hal_rpc_client_handle_t;
+typedef struct { uint32_t handle; } hal_rpc_session_handle_t;
+
+typedef enum { HAL_RPC_USER_NONE, HAL_RPC_USER_NORMAL, HAL_RPC_USER_SO } hal_rpc_user_t;
+
+extern hal_error_t hal_rpc_set_pin(const hal_rpc_user_t which,
+ const char * const newpin, const size_t newpin_len);
+
+extern hal_error_t hal_rpc_login(const hal_rpc_client_handle_t client,
+ const hal_rpc_user_t user,
+ const char * const pin, const size_t pin_len);
+
+extern hal_error_t hal_rpc_logout(const hal_rpc_client_handle_t client);
+
+/*
+ * 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_rpc_hash_handle_t;
+
+extern const hal_rpc_hash_handle_t hal_rpc_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_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_hash_handle_t hash,
+ const uint8_t * data, const size_t length);
+
+extern hal_error_t hal_rpc_hash_finalize(const hal_rpc_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_rpc_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_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_delete(const hal_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
+ hal_key_type_t *type);
+
+extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
+ hal_key_flags_t *flags);
+
+extern size_t hal_rpc_pkey_get_public_key_len(const hal_rpc_pkey_handle_t pkey);
+
+extern hal_error_t hal_rpc_pkey_get_public_key(const hal_rpc_pkey_handle_t pkey,
+ uint8_t *der, size_t *der_len, const size_t der_len_max);
+
+extern hal_error_t hal_rpc_pkey_sign(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_pkey_key_info_t;
+
+extern hal_error_t hal_rpc_pkey_list(hal_rpc_pkey_key_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max);
#endif /* _HAL_H_ */
diff --git a/hal_internal.h b/hal_internal.h
new file mode 100644
index 0000000..3f7f600
--- /dev/null
+++ b/hal_internal.h
@@ -0,0 +1,294 @@
+/*
+ * 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"
+
+/*
+ * 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. Access from outside of libhal
+ * should use the public hal_rpc_*() API.
+ *
+ * In particular, 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_rpc_user_t which,
+ const char * const newpin, const size_t newpin_len);
+
+ hal_error_t (*login)(const hal_rpc_client_handle_t client,
+ const hal_rpc_user_t user,
+ const char * const newpin, const size_t newpin_len);
+
+ hal_error_t (*logout)(const hal_rpc_client_handle_t client);
+
+ hal_error_t (*get_random)(void *buffer, const size_t length);
+
+} 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_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg);
+
+ hal_error_t (*initialize)(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_hash_handle_t hash,
+ const uint8_t * data, const size_t length);
+
+ hal_error_t (*finalize)(const hal_rpc_hash_handle_t hash,
+ uint8_t *digest, const size_t length);
+} hal_rpc_hash_dispatch_t;
+
+
+typedef struct {
+
+ hal_error_t (*load)(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_pkey_handle_t pkey);
+
+ hal_error_t (*delete)(const hal_rpc_pkey_handle_t pkey);
+
+ hal_error_t (*get_key_type)(const hal_rpc_pkey_handle_t pkey,
+ hal_key_type_t *key_type);
+
+ hal_error_t (*get_key_flags)(const hal_rpc_pkey_handle_t pkey,
+ hal_key_flags_t *flags);
+
+ size_t (*get_public_key_len)(const hal_rpc_pkey_handle_t pkey);
+
+ hal_error_t (*get_public_key)(const hal_rpc_pkey_handle_t pkey,
+ uint8_t *der, size_t *der_len, const size_t der_len_max);
+
+ hal_error_t (*sign)(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_pkey_key_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;
+extern const hal_rpc_hash_dispatch_t hal_rpc_local_hash_dispatch, hal_rpc_remote_hash_dispatch;
+extern const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch, hal_rpc_remote_pkey_dispatch, hal_rpc_mixed_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()).
+ */
+
+#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;
+
+typedef struct {
+#if HAL_STATIC_PKEY_STATE_BLOCKS > 0
+ hal_ks_key_t keys[HAL_STATIC_PKEY_STATE_BLOCKS];
+#endif
+} 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_rpc_pkey_key_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max);
+
+#endif /* _HAL_INTERNAL_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/hash.c b/hash.c
index 2f8fa35..9ddc191 100644
--- a/hash.c
+++ b/hash.c
@@ -54,13 +54,6 @@
* 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 {
@@ -105,10 +98,6 @@ 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 = {
@@ -165,6 +154,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 +162,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 +170,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 +178,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 +186,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 +194,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 +202,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 +240,38 @@ 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 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 +279,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,8 +289,8 @@ 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)
{
assert(descriptor != NULL && descriptor->driver != NULL);
return hal_core_check_name(core, descriptor->core_name);
@@ -264,7 +318,7 @@ hal_error_t hal_hash_initialize(const hal_core_t *core,
if ((err = check_core(&core, descriptor)) != 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));
@@ -295,7 +349,6 @@ void hal_hash_cleanup(hal_hash_state_t **state_)
return;
memset(state, 0, state->descriptor->hash_state_length);
- free(state);
*state_ = NULL;
}
@@ -542,7 +595,7 @@ hal_error_t hal_hmac_initialize(const hal_core_t *core,
if ((err = check_core(&core, descriptor)) != 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 +692,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 +742,20 @@ 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;
+}
+
+/*
* "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..072c624
--- /dev/null
+++ b/ks.c
@@ -0,0 +1,280 @@
+/*
+ * 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));
+
+ 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_rpc_pkey_key_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;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_flash.c b/ks_flash.c
new file mode 100644
index 0000000..ad9d2fe
--- /dev/null
+++ b/ks_flash.c
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_mmap.c b/ks_mmap.c
new file mode 100644
index 0000000..7fef400
--- /dev/null
+++ b/ks_mmap.c
@@ -0,0 +1,123 @@
+/*
+ * 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
+
+static hal_ks_keydb_t *db;
+
+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) + 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);
+
+ (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;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_volatile.c b/ks_volatile.c
new file mode 100644
index 0000000..756cd13
--- /dev/null
+++ b/ks_volatile.c
@@ -0,0 +1,74 @@
+/*
+ * 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 "hal.h"
+#include "hal_internal.h"
+
+static hal_ks_keydb_t db;
+
+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;
+}
+
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/rpc.c b/rpc.c
new file mode 100644
index 0000000..e0cb869
--- /dev/null
+++ b/rpc.c
@@ -0,0 +1,330 @@
+/*
+ * hal_rpc.c
+ * ---------
+ * Remote procedure call public API 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 "hal.h"
+#include "hal_internal.h"
+
+#ifndef HAL_RPC_IS_CLIENT
+#warning HAL_RPC_IS_CLIENT not set, assuming we're building for the HSM
+#define HAL_RPC_IS_CLIENT 0
+#endif
+
+/*
+ * Maybe we'll let the client configure this at runtime, later. For
+ * now, wire in the obvious defaults: hashing is done locally,
+ * everything else is done via RPC. For the server everything is
+ * always done locally.
+ */
+
+#if HAL_RPC_IS_CLIENT
+
+static const hal_rpc_misc_dispatch_t * const misc_dispatch = &hal_rpc_remote_misc_dispatch;
+static const hal_rpc_hash_dispatch_t * const hash_dispatch = &hal_rpc_remote_hash_dispatch;
+static const hal_rpc_pkey_dispatch_t * const pkey_dispatch = &hal_rpc_mixed_pkey_dispatch;
+
+#else
+
+static const hal_rpc_misc_dispatch_t * const misc_dispatch = &hal_rpc_local_misc_dispatch;
+static const hal_rpc_hash_dispatch_t * const hash_dispatch = &hal_rpc_local_hash_dispatch;
+static const hal_rpc_pkey_dispatch_t * const pkey_dispatch = &hal_rpc_local_pkey_dispatch;
+
+#endif
+
+const hal_rpc_hash_handle_t hal_rpc_hash_handle_none = {0};
+
+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_random(void *buffer, const size_t length)
+{
+ if (buffer == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ if (length == 0)
+ return HAL_OK;
+ return 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_rpc_user_t which,
+ const char * const newpin, const size_t newpin_len)
+{
+ if (newpin == NULL || newpin_len == 0 || (which != HAL_RPC_USER_NORMAL && which != HAL_RPC_USER_SO))
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return misc_dispatch->set_pin(which, newpin, newpin_len);
+}
+
+hal_error_t hal_rpc_login(const hal_rpc_client_handle_t client,
+ const hal_rpc_user_t user,
+ const char * const pin, const size_t pin_len)
+{
+ if (pin == NULL || pin_len == 0 || (user != HAL_RPC_USER_NORMAL && user != HAL_RPC_USER_SO))
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return misc_dispatch->login(client, user, pin, pin_len);
+}
+
+hal_error_t hal_rpc_logout(const hal_rpc_client_handle_t client)
+{
+ return misc_dispatch->logout(client);
+}
+
+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 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 hash_dispatch->get_digest_algorithm_id(alg, id, len, len_max);
+}
+
+hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg)
+{
+ if (hash.handle == hal_rpc_hash_handle_none.handle || alg == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hash_dispatch->get_algorithm(hash, alg);
+}
+
+hal_error_t hal_rpc_hash_initialize(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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 hash_dispatch->initialize(client, session, hash, alg, key, key_len);
+}
+
+hal_error_t hal_rpc_hash_update(const hal_rpc_hash_handle_t hash,
+ const uint8_t * data, const size_t length)
+{
+ if (hash.handle == hal_rpc_hash_handle_none.handle || data == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ if (length == 0)
+ return HAL_OK;
+ return hash_dispatch->update(hash, data, length);
+}
+
+hal_error_t hal_rpc_hash_finalize(const hal_rpc_hash_handle_t hash,
+ uint8_t *digest, const size_t length)
+{
+ if (hash.handle == hal_rpc_hash_handle_none.handle || digest == NULL || length == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hash_dispatch->finalize(hash, digest, length);
+}
+
+hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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 pkey_dispatch->load(client, session, pkey, type, curve, name, name_len, der, der_len, flags);
+}
+
+hal_error_t hal_rpc_pkey_find(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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 pkey_dispatch->find(client, session, pkey, type, name, name_len);
+}
+
+hal_error_t hal_rpc_pkey_generate_rsa(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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 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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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 pkey_dispatch->generate_ec(client, session, pkey, name, name_len, curve, flags);
+}
+
+hal_error_t hal_rpc_pkey_close(const hal_rpc_pkey_handle_t pkey)
+{
+ return pkey_dispatch->close(pkey);
+}
+
+hal_error_t hal_rpc_pkey_delete(const hal_rpc_pkey_handle_t pkey)
+{
+ return pkey_dispatch->delete(pkey);
+}
+
+hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
+ hal_key_type_t *type)
+{
+ if (type == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return pkey_dispatch->get_key_type(pkey, type);
+}
+
+hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
+ hal_key_flags_t *flags)
+{
+ if (flags == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return pkey_dispatch->get_key_flags(pkey, flags);
+}
+
+size_t hal_rpc_pkey_get_public_key_len(const hal_rpc_pkey_handle_t pkey)
+{
+ return pkey_dispatch->get_public_key_len(pkey);
+}
+
+hal_error_t hal_rpc_pkey_get_public_key(const hal_rpc_pkey_handle_t pkey,
+ uint8_t *der, size_t *der_len, const size_t der_len_max)
+{
+ if (der == NULL || der_len == NULL || der_len_max == 0)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return pkey_dispatch->get_public_key(pkey, der, der_len, der_len_max);
+}
+
+hal_error_t hal_rpc_pkey_sign(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_hash_handle_none.handle) == (input == NULL || input_len == 0))
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return pkey_dispatch->sign(session, pkey, hash, input, input_len, signature, signature_len, signature_max);
+}
+
+hal_error_t hal_rpc_pkey_verify(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_hash_handle_none.handle) == (input == NULL || input_len == 0))
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return pkey_dispatch->verify(session, pkey, hash, input, input_len, signature, signature_len);
+}
+
+hal_error_t hal_rpc_pkey_list(hal_rpc_pkey_key_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 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..0b13e58
--- /dev/null
+++ b/rpc_client.c
@@ -0,0 +1,298 @@
+/*
+ * rpc_client.c
+ * ------------
+ * Remote procedure call client-side private API 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 "hal.h"
+#include "hal_internal.h"
+
+/*
+ * RPC calls. Not implemented yet.
+ */
+
+#warning These are all placeholders, waiting to be filled in with the real RPC calls
+
+static hal_error_t get_random(void *buffer, const size_t length)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t set_pin(const hal_rpc_user_t which,
+ const char * const newpin, const size_t newpin_len)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t login(const hal_rpc_client_handle_t client,
+ const hal_rpc_user_t user,
+ const char * const pin, const size_t pin_len)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t logout(const hal_rpc_client_handle_t client)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t hash_get_digest_len(const hal_digest_algorithm_t alg, size_t *length)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+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)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t hash_initialize(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_hash_handle_t *hash,
+ const hal_digest_algorithm_t alg,
+ const uint8_t * const key, const size_t key_len)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t hash_update(const hal_rpc_hash_handle_t hash,
+ const uint8_t * data, const size_t length)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t hash_finalize(const hal_rpc_hash_handle_t hash,
+ uint8_t *digest, const size_t length)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_load(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_find(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_pkey_handle_t *pkey,
+ const hal_key_type_t type,
+ const uint8_t * const name, const size_t name_len)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_generate_rsa(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_generate_ec(const hal_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_close(const hal_rpc_pkey_handle_t pkey)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_delete(const hal_rpc_pkey_handle_t pkey)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_get_key_type(const hal_rpc_pkey_handle_t pkey,
+ hal_key_type_t *type)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey,
+ hal_key_flags_t *flags)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static size_t pkey_get_public_key_len(const hal_rpc_pkey_handle_t pkey)
+{
+ return 0;
+}
+
+static hal_error_t pkey_get_public_key(const hal_rpc_pkey_handle_t pkey,
+ uint8_t *der, size_t *der_len, const size_t der_len_max)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_remote_sign(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_remote_verify(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_hash_handle_t hash,
+ const uint8_t * const input, const size_t input_len,
+ const uint8_t * const signature, const size_t signature_len)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t pkey_list(hal_rpc_pkey_key_info_t *result,
+ unsigned *result_len,
+ const unsigned result_max)
+{
+ return HAL_ERROR_IMPOSSIBLE;
+}
+
+
+/*
+ * "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_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_hash_handle_none, digest, digest_len,
+ signature, signature_len, signature_max);
+}
+
+static hal_error_t pkey_mixed_verify(const hal_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_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, get_random
+};
+
+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
+};
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/rpc_hash.c b/rpc_hash.c
new file mode 100644
index 0000000..86b8ae0
--- /dev/null
+++ b/rpc_hash.c
@@ -0,0 +1,300 @@
+/*
+ * rpc_hash.c
+ * ----------
+ * Remote procedure call server-side hash 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 "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_rpc_client_handle_t client_handle;
+ hal_rpc_session_handle_t session_handle;
+ hal_rpc_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_rpc_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;
+}
+
+/*
+ * 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_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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;
+
+ 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 != NULL)) == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+
+ slot->client_handle = client;
+ slot->session_handle = session;
+
+ if (key == NULL)
+ return hal_hash_initialize(NULL, descriptor, &slot->state.hash, NULL, 0);
+ else
+ return hal_hmac_initialize(NULL, descriptor, &slot->state.hmac, NULL, 0, key, key_len);
+}
+
+static hal_error_t update(const hal_rpc_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_rpc_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);
+ }
+
+ return err;
+}
+
+const hal_rpc_hash_dispatch_t hal_rpc_remote_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_pkey.c b/rpc_pkey.c
new file mode 100644
index 0000000..d286497
--- /dev/null
+++ b/rpc_pkey.c
@@ -0,0 +1,734 @@
+/*
+ * 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_rpc_client_handle_t client_handle;
+ hal_rpc_session_handle_t session_handle;
+ hal_rpc_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_rpc_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_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_key_to_der_len(key)];
+ size_t der_len;
+
+ if ((err = hal_rsa_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_rpc_client_handle_t client,
+ const hal_rpc_session_handle_t session,
+ hal_rpc_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_key_to_der_len(key)];
+ size_t der_len;
+
+ if ((err = hal_ecdsa_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_rpc_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_rpc_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_rpc_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_rpc_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_rpc_pkey_handle_t pkey)
+{
+ return 0;
+}
+
+/*
+ * Get public key associated with handle.
+ */
+
+static hal_error_t get_public_key(const hal_rpc_pkey_handle_t pkey,
+ uint8_t *der, size_t *der_len, const size_t der_len_max)
+{
+ /*
+ * Still missing some of the public key format ASN.1 stuff, apparently. Feh.
+ */
+ return HAL_ERROR_IMPOSSIBLE;
+#warning get_public_key() not implemented
+}
+
+/*
+ * 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_rpc_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_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+ if ((err = hal_rsa_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_rpc_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_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+ if ((err = hal_ecdsa_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_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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_rpc_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 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 verify_rsa(uint8_t *keybuf, const size_t keybuf_len,
+ const uint8_t * const der, const size_t der_len,
+ const hal_rpc_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_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+ if ((err = hal_rsa_key_from_der(&key, keybuf, keybuf_len, der, der_len)) != 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 uint8_t * const der, const size_t der_len,
+ const hal_rpc_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_rpc_hash_handle_none.handle) != (input == NULL || input_len == 0));
+
+ if ((err = hal_ecdsa_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 ||
+ (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_rpc_session_handle_t session,
+ const hal_rpc_pkey_handle_t pkey,
+ const hal_rpc_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 uint8_t * const der, const size_t der_len,
+ const hal_rpc_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), 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_rpc_pkey_key_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/rsa.c b/rsa.c
index a03b41a..a901b24 100644
--- a/rsa.c
+++ b/rsa.c
@@ -116,7 +116,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 */
@@ -454,7 +454,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 +477,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 +508,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 +518,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 +528,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 +627,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))
@@ -690,7 +692,7 @@ hal_error_t hal_rsa_key_to_der(const hal_rsa_key_t * const key,
{
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;
@@ -748,7 +750,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;
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..98b3d70 100644
--- a/tests/test-ecdsa.c
+++ b/tests/test-ecdsa.c
@@ -150,13 +150,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 +176,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)];
@@ -203,7 +203,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 +213,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 +263,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 +338,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/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;