diff options
-rw-r--r-- | GNUmakefile | 38 | ||||
-rw-r--r-- | asn1_internal.h | 17 | ||||
-rw-r--r-- | ecdsa.c | 155 | ||||
-rw-r--r-- | hal.h | 276 | ||||
-rw-r--r-- | hal_internal.h | 294 | ||||
-rw-r--r-- | hash.c | 102 | ||||
-rw-r--r-- | ks.c | 280 | ||||
-rw-r--r-- | ks_flash.c | 71 | ||||
-rw-r--r-- | ks_mmap.c | 123 | ||||
-rw-r--r-- | ks_volatile.c | 74 | ||||
-rw-r--r-- | rpc.c | 330 | ||||
-rw-r--r-- | rpc_client.c | 298 | ||||
-rw-r--r-- | rpc_hash.c | 300 | ||||
-rw-r--r-- | rpc_pkey.c | 734 | ||||
-rw-r--r-- | rsa.c | 22 | ||||
-rw-r--r-- | tests/test-bus.c | 3 | ||||
-rw-r--r-- | tests/test-ecdsa.c | 25 | ||||
-rw-r--r-- | tests/test-ecdsa.h | 39 | ||||
-rw-r--r-- | tests/test-ecdsa.py | 50 | ||||
-rw-r--r-- | utils/cores.c | 2 |
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: @@ -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 @@ -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: + */ @@ -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 @@ -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: + */ @@ -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: + */ @@ -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; |