diff options
-rw-r--r-- | GNUmakefile | 24 | ||||
-rw-r--r-- | ecdsa.c | 42 | ||||
-rw-r--r-- | hal.h | 254 | ||||
-rw-r--r-- | hal_internal.h (renamed from rpc_internal.h) | 137 | ||||
-rw-r--r-- | hal_rpc.h | 243 | ||||
-rw-r--r-- | ks.c | 280 | ||||
-rw-r--r-- | ks_flash.c | 71 | ||||
-rw-r--r-- | ks_mmap.c | 115 | ||||
-rw-r--r-- | ks_volatile.c | 74 | ||||
-rw-r--r-- | rpc.c (renamed from hal_rpc.c) | 82 | ||||
-rw-r--r-- | rpc_client.c | 53 | ||||
-rw-r--r-- | rpc_hash.c | 30 | ||||
-rw-r--r-- | rpc_pkey.c | 736 | ||||
-rw-r--r-- | rsa.c | 22 | ||||
-rw-r--r-- | tests/test-ecdsa.c | 14 | ||||
-rw-r--r-- | tests/test-ecdsa.h | 6 |
16 files changed, 1776 insertions, 407 deletions
diff --git a/GNUmakefile b/GNUmakefile index 8fc0d14..e0b4730 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -27,22 +27,24 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Number of static hash and HMAC state blocks to allocate +# 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 +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 ${RPC_OBJ} + 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 = hal_rpc.o rpc_hash.o +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 @@ -51,12 +53,20 @@ RPC_OBJ_SERVER = ${RPC_OBJ_COMMON} rpc_misc.o rpc_pkey.o # 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}' $@ @@ -67,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 $@ @@ -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_name_t) 0; (curve = get_curve(key->curve)) != NULL; key->curve++) if (vlen == curve->oid_len && memcmp(d, curve->oid, vlen) == 0) break; if (curve == NULL) @@ -1427,7 +1427,7 @@ hal_error_t hal_ecdsa_sign(const hal_core_t *core, uint8_t *signature, size_t *signature_len, const size_t signature_max, const hal_ecdsa_signature_format_t signature_format) { - 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); @@ -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. */ /* @@ -340,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; @@ -370,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, @@ -413,10 +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; @@ -427,22 +445,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, @@ -453,7 +471,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); @@ -472,7 +490,7 @@ 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, @@ -486,6 +504,192 @@ extern hal_error_t hal_ecdsa_verify(const hal_core_t *core, const uint8_t * const signature, const size_t signature_len, const hal_ecdsa_signature_format_t signature_format); +/* + * 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/rpc_internal.h b/hal_internal.h index b861ec7..3f7f600 100644 --- a/rpc_internal.h +++ b/hal_internal.h @@ -1,7 +1,7 @@ /* - * rpc_internal.h + * hal_internal.h * -------------- - * Internal (not public API) declarations for HAL RPC mechanism. + * Internal API declarations for libhal. * * Authors: Rob Austein, Paul Selkirk * Copyright (c) 2015, NORDUnet A/S All rights reserved. @@ -33,10 +33,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _HAL_RPC_INTERNAL_H_ -#define _HAL_RPC_INTERNAL_H_ +#ifndef _HAL_INTERNAL_H_ +#define _HAL_INTERNAL_H_ -#include "hal_rpc.h" +#include "hal.h" /* * Everything in this file is part of the internal API, that is, @@ -119,16 +119,16 @@ 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_rpc_pkey_key_type_t type, - const hal_rpc_pkey_curve_t curve, + 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_rpc_pkey_flags_t flags); + 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_rpc_pkey_key_type_t type, + 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, @@ -137,22 +137,24 @@ typedef struct { 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_rpc_pkey_flags_t flags); + 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_rpc_pkey_curve_t curve, - const hal_rpc_pkey_flags_t flags); + 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_rpc_pkey_key_type_t *key_type); + hal_key_type_t *key_type); hal_error_t (*get_key_flags)(const hal_rpc_pkey_handle_t pkey, - hal_rpc_pkey_flags_t *flags); + hal_key_flags_t *flags); size_t (*get_public_key_len)(const hal_rpc_pkey_handle_t pkey); @@ -163,13 +165,13 @@ typedef struct { 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 * output, const size_t output_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, - uint8_t * output, const size_t output_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, @@ -182,7 +184,108 @@ extern const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch, hal_rpc_remote 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; -#endif /* _HAL_RPC_INTERNAL_H_ */ +/* + * 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: diff --git a/hal_rpc.h b/hal_rpc.h deleted file mode 100644 index 553fb6b..0000000 --- a/hal_rpc.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * hal_rpc.h - * --------- - * Remote procedure call API to extrude libhal across the green/yellow boundary. - * - * 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_RPC_H_ -#define _HAL_RPC_H_ - -#include <stdint.h> -#include <stdlib.h> -#include "hal.h" - -/* - * 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 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 enum { - HAL_RPC_PKEY_RSA_PRIVATE, - HAL_RPC_PKEY_RSA_PUBLIC, - HAL_RPC_PKEY_ECDSA_PRIVATE, - HAL_RPC_PKEY_ECDSA_PUBLIC -} hal_rpc_pkey_key_type_t; - -typedef enum { - HAL_RPC_PKEY_CURVE_NONE, - HAL_RPC_PKEY_CURVE_ECDSA_P256, - HAL_RPC_PKEY_CURVE_ECDSA_P384, - HAL_RPC_PKEY_CURVE_ECDSA_P521 -} hal_rpc_pkey_curve_t; - -typedef struct { uint32_t handle; } hal_rpc_pkey_handle_t; - -typedef uint32_t hal_rpc_pkey_flags_t; - -#define HAL_RPC_PKEY_FLAG_USAGE_DIGITALSIGNATURE (1 << 0) -#define HAL_RPC_PKEY_FLAG_USAGE_KEYENCIPHERMENT (1 << 1) -#define HAL_RPC_PKEY_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_rpc_pkey_key_type_t type, - const hal_rpc_pkey_curve_t curve, - const uint8_t * const name, const size_t name_len, - const uint8_t * const der, const size_t der_len, - const hal_rpc_pkey_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_rpc_pkey_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_rpc_pkey_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_rpc_pkey_curve_t curve, - const hal_rpc_pkey_flags_t flags); - -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_rpc_pkey_key_type_t *type); - -extern hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey, - hal_rpc_pkey_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 * output, const size_t output_len); - -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, - uint8_t * output, const size_t output_len); - -typedef struct { - hal_rpc_pkey_key_type_t type; - hal_rpc_pkey_curve_t curve; - hal_rpc_pkey_flags_t flags; - char name[HAL_RPC_PKEY_NAME_MAX]; - /* ... */ -} 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_RPC_H_ */ - -/* - * Local variables: - * indent-tabs-mode: nil - * End: - */ @@ -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..3ff06a3 --- /dev/null +++ b/ks_mmap.c @@ -0,0 +1,115 @@ +/* + * 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 "hal.h" +#include "hal_internal.h" + +#ifndef HAL_KS_MMAP_FILE +#define HAL_KS_MMAP_FILE ".cryptech_hal_keystore" +#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 unsigned pagemask = getpagesize() - 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 (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: + */ @@ -33,7 +33,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "rpc_internal.h" +#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 @@ -63,45 +64,45 @@ static const hal_rpc_pkey_dispatch_t * const pkey_dispatch = &hal_rpc_local_pkey const hal_rpc_hash_handle_t hal_rpc_hash_handle_none = {0}; -static inline int check_pkey_type(const hal_rpc_pkey_key_type_t type) +static inline int check_pkey_type(const hal_key_type_t type) { switch (type) { - case HAL_RPC_PKEY_RSA_PRIVATE: - case HAL_RPC_PKEY_RSA_PUBLIC: - case HAL_RPC_PKEY_ECDSA_PRIVATE: - case HAL_RPC_PKEY_ECDSA_PUBLIC: + 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_rpc_pkey_flags_t flags) +static inline int check_pkey_flags(const hal_key_flags_t flags) { - return (flags &~ (HAL_RPC_PKEY_FLAG_USAGE_DIGITALSIGNATURE | - HAL_RPC_PKEY_FLAG_USAGE_KEYENCIPHERMENT | - HAL_RPC_PKEY_FLAG_USAGE_DATAENCIPHERMENT)) == 0; + 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_rpc_pkey_key_type_t type, - const hal_rpc_pkey_curve_t curve, - const hal_rpc_pkey_flags_t flags) +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_RPC_PKEY_RSA_PRIVATE: - case HAL_RPC_PKEY_RSA_PUBLIC: - return curve == HAL_RPC_PKEY_CURVE_NONE; + case HAL_KEY_TYPE_RSA_PRIVATE: + case HAL_KEY_TYPE_RSA_PUBLIC: + return curve == HAL_CURVE_NONE; - case HAL_RPC_PKEY_ECDSA_PRIVATE: - case HAL_RPC_PKEY_ECDSA_PUBLIC: + case HAL_KEY_TYPE_EC_PRIVATE: + case HAL_KEY_TYPE_EC_PUBLIC: switch (curve) { - case HAL_RPC_PKEY_CURVE_ECDSA_P256: - case HAL_RPC_PKEY_CURVE_ECDSA_P384: - case HAL_RPC_PKEY_CURVE_ECDSA_P521: + case HAL_CURVE_P256: + case HAL_CURVE_P384: + case HAL_CURVE_P521: return 1; default: return 0; @@ -198,11 +199,11 @@ hal_error_t hal_rpc_hash_finalize(const hal_rpc_hash_handle_t hash, 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_rpc_pkey_key_type_t type, - const hal_rpc_pkey_curve_t curve, + 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_rpc_pkey_flags_t flags) + const hal_key_flags_t flags) { if (pkey == NULL || name == NULL || name_len == 0 || @@ -215,7 +216,7 @@ hal_error_t hal_rpc_pkey_load(const hal_rpc_client_handle_t client, 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_rpc_pkey_key_type_t type, + 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)) @@ -229,9 +230,9 @@ hal_error_t hal_rpc_pkey_generate_rsa(const hal_rpc_client_handle_t client, 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_rpc_pkey_flags_t flags) + const hal_key_flags_t flags) { - if (pkey == NULL || name == NULL || name_len == 0 || key_len == 0 || + 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); @@ -241,22 +242,27 @@ 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_rpc_pkey_curve_t curve, - const hal_rpc_pkey_flags_t flags) + 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_RPC_PKEY_ECDSA_PRIVATE, curve, flags)) + !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_rpc_pkey_key_type_t *type) + hal_key_type_t *type) { if (type == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -264,7 +270,7 @@ hal_error_t hal_rpc_pkey_get_key_type(const hal_rpc_pkey_handle_t pkey, } hal_error_t hal_rpc_pkey_get_key_flags(const hal_rpc_pkey_handle_t pkey, - hal_rpc_pkey_flags_t *flags) + hal_key_flags_t *flags) { if (flags == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -288,24 +294,24 @@ 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 * output, const size_t output_len) + uint8_t * signature, size_t *signature_len, const size_t signature_max) { - if (output == NULL || output_len == 0 || + 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, output, output_len); + 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, - uint8_t * output, const size_t output_len) + const uint8_t * const signature, const size_t signature_len) { - if (output == NULL || output_len == 0 || + 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, output, output_len); + 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, diff --git a/rpc_client.c b/rpc_client.c index 20cc26f..0b13e58 100644 --- a/rpc_client.c +++ b/rpc_client.c @@ -33,7 +33,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "rpc_internal.h" +#include "hal.h" +#include "hal_internal.h" /* * RPC calls. Not implemented yet. @@ -104,11 +105,11 @@ static hal_error_t hash_finalize(const hal_rpc_hash_handle_t hash, 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_rpc_pkey_key_type_t type, - const hal_rpc_pkey_curve_t curve, + 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_rpc_pkey_flags_t flags) + const hal_key_flags_t flags) { return HAL_ERROR_IMPOSSIBLE; } @@ -116,7 +117,7 @@ static hal_error_t pkey_load(const hal_rpc_client_handle_t client, 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_rpc_pkey_key_type_t type, + const hal_key_type_t type, const uint8_t * const name, const size_t name_len) { return HAL_ERROR_IMPOSSIBLE; @@ -128,7 +129,7 @@ static hal_error_t pkey_generate_rsa(const hal_rpc_client_handle_t client, 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_rpc_pkey_flags_t flags) + const hal_key_flags_t flags) { return HAL_ERROR_IMPOSSIBLE; } @@ -137,8 +138,13 @@ 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_rpc_pkey_curve_t curve, - const hal_rpc_pkey_flags_t flags) + 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; } @@ -149,13 +155,13 @@ static hal_error_t pkey_delete(const hal_rpc_pkey_handle_t pkey) } static hal_error_t pkey_get_key_type(const hal_rpc_pkey_handle_t pkey, - hal_rpc_pkey_key_type_t *type) + 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_rpc_pkey_flags_t *flags) + hal_key_flags_t *flags) { return HAL_ERROR_IMPOSSIBLE; } @@ -175,7 +181,7 @@ 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 * output, const size_t output_len) + uint8_t * signature, size_t *signature_len, const size_t signature_max) { return HAL_ERROR_IMPOSSIBLE; } @@ -184,7 +190,7 @@ 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, - uint8_t * output, const size_t output_len) + const uint8_t * const signature, const size_t signature_len) { return HAL_ERROR_IMPOSSIBLE; } @@ -208,10 +214,11 @@ 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 * output, const size_t output_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, output, output_len); + return pkey_remote_sign(session, pkey, hash, input, input_len, + signature, signature_len, signature_max); hal_digest_algorithm_t alg; size_t digest_len; @@ -226,17 +233,19 @@ static hal_error_t pkey_mixed_sign(const hal_rpc_session_handle_t session, 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, output, output_len); + 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, - uint8_t * output, const size_t output_len) + const uint8_t * const signature, const size_t signature_len) { if (input != NULL) - return pkey_remote_verify(session, pkey, hash, input, input_len, output, output_len); + return pkey_remote_verify(session, pkey, hash, input, input_len, + signature, signature_len); hal_digest_algorithm_t alg; size_t digest_len; @@ -251,7 +260,8 @@ static hal_error_t pkey_mixed_verify(const hal_rpc_session_handle_t session, 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, output, output_len); + return pkey_remote_verify(session, pkey, hal_rpc_hash_handle_none, digest, digest_len, + signature, signature_len); } /* @@ -263,18 +273,19 @@ const hal_rpc_misc_dispatch_t hal_rpc_remote_misc_dispatch = { }; 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 + 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_delete, + 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_delete, + 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 @@ -36,7 +36,7 @@ #include <string.h> #include "hal.h" -#include "rpc_internal.h" +#include "hal_internal.h" /* * Need table and handle allocation, including some kind of in_use @@ -94,10 +94,10 @@ static inline handle_slot_t *alloc_handle(const int is_hmac) #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) { - hash_handle[i].hash_handle.handle = i | glop; - return &hash_handle[i]; - } + if (hash_handle[i].state.hash != NULL) + continue; + hash_handle[i].hash_handle.handle = i | glop; + return &hash_handle[i]; } } #endif @@ -105,10 +105,10 @@ static inline handle_slot_t *alloc_handle(const int is_hmac) #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) { - hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC; - return &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 @@ -134,7 +134,7 @@ static inline handle_slot_t *find_handle(const hal_rpc_hash_handle_t handle) return &hash_handle[i]; #endif -#if HAL_STATIC_HASH_STATE_BLOCKS > 0 +#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]; @@ -227,10 +227,10 @@ static hal_error_t get_algorithm(const hal_rpc_hash_handle_t handle, hal_digest_ } 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_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; @@ -254,7 +254,7 @@ static hal_error_t initialize(const hal_rpc_client_handle_t client, } static hal_error_t update(const hal_rpc_hash_handle_t handle, - const uint8_t * data, const size_t length) + const uint8_t * data, const size_t length) { handle_slot_t *slot = find_handle(handle); diff --git a/rpc_pkey.c b/rpc_pkey.c new file mode 100644 index 0000000..8fece44 --- /dev/null +++ b/rpc_pkey.c @@ -0,0 +1,736 @@ +/* + * 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_ECDSA_SIGNATURE_FORMAT_PKCS11)) != 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_ECDSA_SIGNATURE_FORMAT_PKCS11)) != 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-ecdsa.c b/tests/test-ecdsa.c index ce8aee1..ae99616 100644 --- a/tests/test-ecdsa.c +++ b/tests/test-ecdsa.c @@ -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; @@ -339,12 +339,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..a607d97 100644 --- a/tests/test-ecdsa.h +++ b/tests/test-ecdsa.h @@ -264,7 +264,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 +286,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 +306,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), |