From c60b4bbd62865c4fe891dcbf7586c4718082d626 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sun, 13 Dec 2015 00:43:11 -0500 Subject: Add rpc_hash.c. Convert dynamic allocator in hash.c to use private pool of pre-configured state blocks, suitable for an embedded system. --- GNUmakefile | 19 +++- hal.h | 14 +++ hal_rpc.c | 8 +- hal_rpc.h | 13 +-- hash.c | 102 ++++++++++++++++---- rpc_client.c | 12 +-- rpc_hash.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rpc_internal.h | 8 +- 8 files changed, 430 insertions(+), 46 deletions(-) create mode 100644 rpc_hash.c diff --git a/GNUmakefile b/GNUmakefile index 810d997..1f6b711 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -25,28 +25,37 @@ # 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 + +STATIC_HASH_STATE_BLOCKS = 10 +STATIC_HMAC_STATE_BLOCKS = 4 + INC = hal.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} - 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_CLIENT = hal_rpc.o rpc_client.o -RPC_OBJ_SERVER = hal_rpc.o rpc_server.o +RPC_OBJ_COMMON = hal_rpc.o rpc_hash.o +RPC_OBJ_CLIENT = ${RPC_OBJ_COMMON} rpc_client.o +RPC_OBJ_SERVER = ${RPC_OBJ_COMMON} rpc_misc.o rpc_pkey.o -# Default should be to build the RPC server, but we haven't written even the skeleton of that yet. -# We'll probably end up needing a makefile conditional to handle all this properly +# Default should be to build the RPC server code, but we haven't +# written even the skeleton of that yet. We'll probably end up +# needing a makefile conditional to handle all this properly RPC_OBJ = ${RPC_OBJ_CLIENT} 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} + all: ${LIB} cd tests; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@ cd utils; ${MAKE} CFLAGS='${CFLAGS} -I..' LDFLAGS='${LDFLAGS}' $@ diff --git a/hal.h b/hal.h index eb1e253..1ccc491 100644 --- a/hal.h +++ b/hal.h @@ -221,7 +221,17 @@ typedef struct hal_hash_driver hal_hash_driver_t; * problem. */ +typedef enum { + hal_digest_algorithm_sha1, + hal_digest_algorithm_sha256, + hal_digest_algorithm_sha512_224, + hal_digest_algorithm_sha512_256, + hal_digest_algorithm_sha384, + hal_digest_algorithm_sha512 +} hal_digest_algorithm_t; + typedef struct { + hal_digest_algorithm_t digest_algorithm; size_t block_length; size_t digest_length; size_t hash_state_length; @@ -284,6 +294,10 @@ extern void hal_hash_cleanup(hal_hash_state_t **state); extern void hal_hmac_cleanup(hal_hmac_state_t **state); +extern const hal_hash_descriptor_t *hal_hash_get_descriptor(const hal_hash_state_t * const state); + +extern const hal_hash_descriptor_t *hal_hmac_get_descriptor(const hal_hmac_state_t * const state); + /* * AES key wrap functions. */ diff --git a/hal_rpc.c b/hal_rpc.c index 15f5f65..6ad198e 100644 --- a/hal_rpc.c +++ b/hal_rpc.c @@ -146,20 +146,20 @@ hal_error_t hal_rpc_logout(const hal_rpc_client_handle_t client) return misc_dispatch->logout(client); } -hal_error_t hal_rpc_hash_get_digest_length(const hal_rpc_hash_alg_t alg, size_t *length) +hal_error_t hal_rpc_hash_get_digest_length(const hal_digest_algorithm_t alg, size_t *length) { if (length == NULL) return HAL_ERROR_BAD_ARGUMENTS; return hash_dispatch->get_digest_length(alg, length); } -hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_rpc_hash_alg_t alg, +hal_error_t hal_rpc_hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg, uint8_t *id, size_t *len, const size_t len_max) { return hash_dispatch->get_digest_algorithm_id(alg, id, len, len_max); } -hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_rpc_hash_alg_t *alg) +hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg) { if (hash.handle == hal_rpc_hash_handle_none.handle || alg == NULL) return HAL_ERROR_BAD_ARGUMENTS; @@ -169,7 +169,7 @@ hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_rpc 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_rpc_hash_alg_t alg, + const hal_digest_algorithm_t alg, const uint8_t * const key, const size_t key_len) { if (hash == NULL) diff --git a/hal_rpc.h b/hal_rpc.h index db300e3..553fb6b 100644 --- a/hal_rpc.h +++ b/hal_rpc.h @@ -87,21 +87,16 @@ 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 enum { - hal_rpc_hash_alg__sha1, hal_rpc_hash_alg__sha256, hal_rpc_hash_alg__sha512_224, - hal_rpc_hash_alg__sha512_256, hal_rpc_hash_alg__sha384, hal_rpc_hash_alg__sha512 -} hal_rpc_hash_alg_t; - 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_rpc_hash_alg_t alg, size_t *length); +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_rpc_hash_alg_t alg, +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_rpc_hash_alg_t *alg); +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 @@ -111,7 +106,7 @@ extern hal_error_t hal_rpc_hash_get_algorithm(const hal_rpc_hash_handle_t hash, 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_rpc_hash_alg_t alg, + 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, diff --git a/hash.c b/hash.c index 0ba6b50..138740e 100644 --- a/hash.c +++ b/hash.c @@ -52,13 +52,6 @@ * Driver. This encapsulates whatever per-algorithm voodoo we need * this week. At the moment, this is mostly Cryptech core addresses, * but this is subject to change without notice. - * - * Most of the addresses in the current version could be calculated - * from a single address (the core base address), but this week's - * theory prefers the precomputed composite addresses, and doing it - * this way saves some microscopic bit of addition at runtime. - * Whatever. It'll probably all change again once we have a dynamic - * memory map, so it's not really worth overthinking at the moment. */ struct hal_hash_driver { @@ -103,10 +96,6 @@ struct hal_hmac_state { /* * Drivers for known digest algorithms. - * - * Initialization of the core_name field is not a typo, we're - * concatenating two string constants and trusting the compiler to - * whine if the resulting string doesn't fit into the field. */ static const hal_hash_driver_t sha1_driver = { @@ -163,6 +152,7 @@ static const uint8_t */ const hal_hash_descriptor_t hal_hash_sha1[1] = {{ + hal_digest_algorithm_sha1, SHA1_BLOCK_LEN, SHA1_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha1, sizeof(dalgid_sha1), @@ -170,6 +160,7 @@ const hal_hash_descriptor_t hal_hash_sha1[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha256[1] = {{ + hal_digest_algorithm_sha256, SHA256_BLOCK_LEN, SHA256_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha256, sizeof(dalgid_sha256), @@ -177,6 +168,7 @@ const hal_hash_descriptor_t hal_hash_sha256[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{ + hal_digest_algorithm_sha512_224, SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512_224, sizeof(dalgid_sha512_224), @@ -184,6 +176,7 @@ const hal_hash_descriptor_t hal_hash_sha512_224[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{ + hal_digest_algorithm_sha512_256, SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512_256, sizeof(dalgid_sha512_256), @@ -191,6 +184,7 @@ const hal_hash_descriptor_t hal_hash_sha512_256[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha384[1] = {{ + hal_digest_algorithm_sha384, SHA512_BLOCK_LEN, SHA384_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha384, sizeof(dalgid_sha384), @@ -198,12 +192,40 @@ const hal_hash_descriptor_t hal_hash_sha384[1] = {{ }}; const hal_hash_descriptor_t hal_hash_sha512[1] = {{ + hal_digest_algorithm_sha512, SHA512_BLOCK_LEN, SHA512_DIGEST_LEN, sizeof(hal_hash_state_t), sizeof(hal_hmac_state_t), dalgid_sha512, sizeof(dalgid_sha512), &sha512_driver, SHA512_NAME, 0 }}; +/* + * Static state blocks. This library is intended for a style of + * embedded programming in which one avoids heap-based allocation + * functions such as malloc() wherever possible and instead uses + * static variables when just allocating on the stack won't do. + * + * The number of each kind of state block to be allocated this way + * must be configured at compile-time. Sorry, that's life in the + * deeply embedded universe. + */ + +#ifndef HAL_STATIC_HASH_STATE_BLOCKS +#define HAL_STATIC_HASH_STATE_BLOCKS 0 +#endif + +#ifndef HAL_STATIC_HMAC_STATE_BLOCKS +#define HAL_STATIC_HMAC_STATE_BLOCKS 0 +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 +static hal_hash_state_t static_hash_state[HAL_STATIC_HASH_STATE_BLOCKS]; +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 +static hal_hmac_state_t static_hmac_state[HAL_STATIC_HMAC_STATE_BLOCKS]; +#endif + /* * Debugging control. */ @@ -215,6 +237,38 @@ void hal_hash_set_debug(int onoff) debug = onoff; } +/* + * Internal utilities to allocate static state blocks. + */ + +static inline hal_hash_state_t *alloc_static_hash_state(void) +{ + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + + for (int i = 0; i < sizeof(static_hash_state)/sizeof(*static_hash_state); i++) + if ((static_hash_state[i].flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return &static_hash_state[i]; + +#endif + + return NULL; +} + +static inline hal_hmac_state_t *alloc_static_hmac_state(void) +{ + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 + + for (int i = 0; i < sizeof(static_hmac_state)/sizeof(*static_hmac_state); i++) + if ((static_hmac_state[i].hash_state.flags & STATE_FLAG_STATE_ALLOCATED) == 0) + return &static_hmac_state[i]; + +#endif + + return NULL; +} + /* * Internal utility to do whatever checking we need of a descriptor, * then extract the driver pointer in a way that works nicely with @@ -223,7 +277,7 @@ void hal_hash_set_debug(int onoff) * Returns the driver pointer on success, NULL on failure. */ -static const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const descriptor) +static inline const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const descriptor) { return descriptor == NULL ? NULL : descriptor->driver; } @@ -233,8 +287,8 @@ static const hal_hash_driver_t *check_driver(const hal_hash_descriptor_t * const * attempting to locate an appropriate core if we weren't given one. */ -static hal_error_t check_core(const hal_core_t **core, - const hal_hash_descriptor_t * const descriptor) +static inline hal_error_t check_core(const hal_core_t **core, + const hal_hash_descriptor_t * const descriptor) { assert(descriptor != NULL && descriptor->driver != NULL); return hal_core_check_name(core, descriptor->core_name); @@ -262,7 +316,7 @@ hal_error_t hal_hash_initialize(const hal_core_t *core, if ((err = check_core(&core, descriptor)) != HAL_OK) return err; - if (state_buffer == NULL && (state = malloc(descriptor->hash_state_length)) == NULL) + if (state_buffer == NULL && (state = alloc_static_hash_state()) == NULL) return HAL_ERROR_ALLOCATION_FAILURE; memset(state, 0, sizeof(*state)); @@ -293,7 +347,6 @@ void hal_hash_cleanup(hal_hash_state_t **state_) return; memset(state, 0, state->descriptor->hash_state_length); - free(state); *state_ = NULL; } @@ -540,7 +593,7 @@ hal_error_t hal_hmac_initialize(const hal_core_t *core, if ((err = check_core(&core, descriptor)) != HAL_OK) return err; - if (state_buffer == NULL && (state = malloc(descriptor->hmac_state_length)) == NULL) + if (state_buffer == NULL && (state = alloc_static_hmac_state()) == NULL) return HAL_ERROR_ALLOCATION_FAILURE; hal_hash_state_t *h = &state->hash_state; @@ -637,7 +690,6 @@ void hal_hmac_cleanup(hal_hmac_state_t **state_) return; memset(state, 0, h->descriptor->hmac_state_length); - free(state); *state_ = NULL; } @@ -687,6 +739,20 @@ hal_error_t hal_hmac_finalize(hal_hmac_state_t *state, return HAL_OK; } +/* + * Pull descriptor pointer from state block. + */ + +const hal_hash_descriptor_t *hal_hash_get_descriptor(const hal_hash_state_t * const state) +{ + return state == NULL ? NULL : state->descriptor; +} + +const hal_hash_descriptor_t *hal_hmac_get_descriptor(const hal_hmac_state_t * const state) +{ + return state == NULL ? NULL : state->hash_state.descriptor; +} + /* * "Any programmer who fails to comply with the standard naming, formatting, * or commenting conventions should be shot. If it so happens that it is diff --git a/rpc_client.c b/rpc_client.c index 4a755af..20cc26f 100644 --- a/rpc_client.c +++ b/rpc_client.c @@ -64,18 +64,18 @@ static hal_error_t logout(const hal_rpc_client_handle_t client) return HAL_ERROR_IMPOSSIBLE; } -static hal_error_t hash_get_digest_len(const hal_rpc_hash_alg_t alg, size_t *length) +static hal_error_t hash_get_digest_len(const hal_digest_algorithm_t alg, size_t *length) { return HAL_ERROR_IMPOSSIBLE; } -static hal_error_t hash_get_digest_algorithm_id(const hal_rpc_hash_alg_t alg, +static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg, uint8_t *id, size_t *len, const size_t len_max) { return HAL_ERROR_IMPOSSIBLE; } -static hal_error_t hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_rpc_hash_alg_t *alg) +static hal_error_t hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg) { return HAL_ERROR_IMPOSSIBLE; } @@ -83,7 +83,7 @@ static hal_error_t hash_get_algorithm(const hal_rpc_hash_handle_t hash, hal_rpc_ static hal_error_t hash_initialize(const hal_rpc_client_handle_t client, const hal_rpc_session_handle_t session, hal_rpc_hash_handle_t *hash, - const hal_rpc_hash_alg_t alg, + const hal_digest_algorithm_t alg, const uint8_t * const key, const size_t key_len) { return HAL_ERROR_IMPOSSIBLE; @@ -213,7 +213,7 @@ static hal_error_t pkey_mixed_sign(const hal_rpc_session_handle_t session, if (input != NULL) return pkey_remote_sign(session, pkey, hash, input, input_len, output, output_len); - hal_rpc_hash_alg_t alg; + hal_digest_algorithm_t alg; size_t digest_len; hal_error_t err; @@ -238,7 +238,7 @@ static hal_error_t pkey_mixed_verify(const hal_rpc_session_handle_t session, if (input != NULL) return pkey_remote_verify(session, pkey, hash, input, input_len, output, output_len); - hal_rpc_hash_alg_t alg; + hal_digest_algorithm_t alg; size_t digest_len; hal_error_t err; diff --git a/rpc_hash.c b/rpc_hash.c new file mode 100644 index 0000000..4ceadb6 --- /dev/null +++ b/rpc_hash.c @@ -0,0 +1,300 @@ +/* + * rpc_hash.c + * ---------- + * Remote procedure call server-side hash implementation. + * + * Authors: Rob Austein + * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "hal.h" +#include "rpc_internal.h" + +/* + * Need table and handle allocation, including some kind of in_use + * flag (perhaps just handle == none). + * + * Hash and HMAC aren't really things for which we need permission + * bits, so not sure we even care about login stuff here. + */ + +typedef struct { + hal_rpc_client_handle_t client_handle; + hal_rpc_session_handle_t session_handle; + hal_rpc_hash_handle_t hash_handle; + union { + hal_hash_state_t *hash; + hal_hmac_state_t *hmac; + } state; +} handle_slot_t; + +#ifndef HAL_STATIC_HASH_STATE_BLOCKS +#define HAL_STATIC_HASH_STATE_BLOCKS 0 +#endif + +#ifndef HAL_STATIC_HMAC_STATE_BLOCKS +#define HAL_STATIC_HMAC_STATE_BLOCKS 0 +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 +static handle_slot_t hash_handle[HAL_STATIC_HASH_STATE_BLOCKS]; +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 +static handle_slot_t hmac_handle[HAL_STATIC_HMAC_STATE_BLOCKS]; +#endif + +/* + * Handle allocation is simple: we look for an unused (state == NULL) + * slot in the appropriate table, and, assuming we find one, construct + * a composite handle consisting of a flag telling us which table this + * is, the index into the table, and a counter whose sole purpose is + * to keep the same handle from reoccurring anytime soon, to help + * identify use-after-free bugs in calling code. + */ + +#define HANDLE_FLAG_HMAC 0x80000000 + +static inline handle_slot_t *alloc_handle(const int is_hmac) +{ +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 || HAL_STATIC_HMAC_STATE_BLOCKS > 0 + static uint16_t next_glop = 0; + uint32_t glop = ++next_glop << 16; + next_glop %= 0x7FFF; +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + if (!is_hmac) { + for (int i = 0; i < sizeof(hash_handle)/sizeof(*hash_handle); i++) { + if (hash_handle[i].state.hash == NULL) { + hash_handle[i].hash_handle.handle = i | glop; + return &hash_handle[i]; + } + } + } +#endif + +#if HAL_STATIC_HMAC_STATE_BLOCKS > 0 + if (is_hmac) { + for (int i = 0; i < sizeof(hmac_handle)/sizeof(*hmac_handle); i++) { + if (hmac_handle[i].state.hmac == NULL) { + hmac_handle[i].hash_handle.handle = i | glop | HANDLE_FLAG_HMAC; + return &hmac_handle[i]; + } + } + } +#endif + + return NULL; +} + +/* + * Check a caller-supplied handle. Must be in range, in use, and have + * the right glop. Returns slot pointer on success, NULL otherwise. + */ + +static inline handle_slot_t *find_handle(const hal_rpc_hash_handle_t handle) +{ +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 || HAL_STATIC_HMAC_STATE_BLOCKS > 0 + const int i = (int) (handle.handle & 0xFFFF); + const int is_hmac = (handle.handle & HANDLE_FLAG_HMAC) != 0; +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + if (!is_hmac && i < sizeof(hash_handle)/sizeof(*hash_handle) && + hash_handle[i].hash_handle.handle == handle.handle && hash_handle[i].state.hash != NULL) + return &hash_handle[i]; +#endif + +#if HAL_STATIC_HASH_STATE_BLOCKS > 0 + if (is_hmac && i < sizeof(hmac_handle)/sizeof(*hmac_handle) && + hmac_handle[i].hash_handle.handle == handle.handle && hmac_handle[i].state.hmac != NULL) + return &hmac_handle[i]; +#endif + + return NULL; +} + +/* + * Translate an algorithm number to a descriptor. + */ + +static inline const hal_hash_descriptor_t *alg_to_descriptor(const hal_digest_algorithm_t alg) +{ + switch (alg) { + case hal_digest_algorithm_sha1: return hal_hash_sha1; + case hal_digest_algorithm_sha256: return hal_hash_sha256; + case hal_digest_algorithm_sha512_224: return hal_hash_sha512_224; + case hal_digest_algorithm_sha512_256: return hal_hash_sha512_256; + case hal_digest_algorithm_sha384: return hal_hash_sha384; + case hal_digest_algorithm_sha512: return hal_hash_sha512; + default: return NULL; + } +} + +/* + * Given a slot pointer, fetch the descriptor. + */ + +static inline const hal_hash_descriptor_t *slot_to_descriptor(const handle_slot_t * const slot) +{ + if (slot == NULL) + return NULL; + + if ((slot->hash_handle.handle & HANDLE_FLAG_HMAC) == 0) + return hal_hash_get_descriptor(slot->state.hash); + else + return hal_hmac_get_descriptor(slot->state.hmac); +} + +/* + * Public API + */ + +static hal_error_t get_digest_length(const hal_digest_algorithm_t alg, size_t *length) +{ + const hal_hash_descriptor_t * const d = alg_to_descriptor(alg); + + if (d == NULL || length == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + *length = d->digest_length; + return HAL_OK; +} + +static hal_error_t get_digest_algorithm_id(const hal_digest_algorithm_t alg, + uint8_t *id, size_t *len, const size_t len_max) +{ + const hal_hash_descriptor_t * const d = alg_to_descriptor(alg); + + if (d == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (len != NULL) + *len = d->digest_algorithm_id_length; + + if (id == NULL) + return HAL_OK; + + if (len_max < d->digest_algorithm_id_length) + return HAL_ERROR_RESULT_TOO_LONG; + + memcpy(id, d->digest_algorithm_id, d->digest_algorithm_id_length); + return HAL_OK; +} + +static hal_error_t get_algorithm(const hal_rpc_hash_handle_t handle, hal_digest_algorithm_t *alg) +{ + handle_slot_t *slot = find_handle(handle); + const hal_hash_descriptor_t *descriptor = slot_to_descriptor(slot); + + if (slot == NULL || alg == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if (descriptor == NULL) + return HAL_ERROR_IMPOSSIBLE; + + *alg = descriptor->digest_algorithm; + return HAL_OK; +} + +static hal_error_t initialize(const hal_rpc_client_handle_t client, + const hal_rpc_session_handle_t session, + hal_rpc_hash_handle_t *hash, + const hal_digest_algorithm_t alg, + const uint8_t * const key, const size_t key_len) +{ + const hal_hash_descriptor_t *descriptor; + handle_slot_t *slot; + + if (hash == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((descriptor = alg_to_descriptor(alg)) == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((slot = alloc_handle(key != NULL)) == NULL) + return HAL_ERROR_ALLOCATION_FAILURE; + + slot->client_handle = client; + slot->session_handle = session; + + if (key == NULL) + return hal_hash_initialize(NULL, descriptor, &slot->state.hash, NULL, 0); + else + return hal_hmac_initialize(NULL, descriptor, &slot->state.hmac, NULL, 0, key, key_len); +} + +static hal_error_t update(const hal_rpc_hash_handle_t handle, + const uint8_t * data, const size_t length) +{ + handle_slot_t *slot = find_handle(handle); + + if (slot == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((handle.handle & HANDLE_FLAG_HMAC) == 0) + return hal_hash_update(slot->state.hash, data, length); + else + return hal_hmac_update(slot->state.hmac, data, length); +} + +static hal_error_t finalize(const hal_rpc_hash_handle_t handle, + uint8_t *digest, const size_t length) +{ + handle_slot_t *slot = find_handle(handle); + hal_error_t err; + + if (slot == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + if ((handle.handle & HANDLE_FLAG_HMAC) == 0) { + err = hal_hash_finalize(slot->state.hash, digest, length); + hal_hash_cleanup(&slot->state.hash); + } + + else { + err = hal_hmac_finalize(slot->state.hmac, digest, length); + hal_hmac_cleanup(&slot->state.hmac); + } + + return err; +} + +const hal_rpc_hash_dispatch_t hal_rpc_remote_hash_dispatch = { + get_digest_length, get_digest_algorithm_id, get_algorithm, initialize, update, finalize +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * End: + */ diff --git a/rpc_internal.h b/rpc_internal.h index 73e79f7..b861ec7 100644 --- a/rpc_internal.h +++ b/rpc_internal.h @@ -93,17 +93,17 @@ typedef struct { typedef struct { - hal_error_t (*get_digest_length)(const hal_rpc_hash_alg_t alg, size_t *length); + hal_error_t (*get_digest_length)(const hal_digest_algorithm_t alg, size_t *length); - hal_error_t (*get_digest_algorithm_id)(const hal_rpc_hash_alg_t alg, + hal_error_t (*get_digest_algorithm_id)(const hal_digest_algorithm_t alg, uint8_t *id, size_t *len, const size_t len_max); - hal_error_t (*get_algorithm)(const hal_rpc_hash_handle_t hash, hal_rpc_hash_alg_t *alg); + hal_error_t (*get_algorithm)(const hal_rpc_hash_handle_t hash, hal_digest_algorithm_t *alg); hal_error_t (*initialize)(const hal_rpc_client_handle_t client, const hal_rpc_session_handle_t session, hal_rpc_hash_handle_t *hash, - const hal_rpc_hash_alg_t alg, + const hal_digest_algorithm_t alg, const uint8_t * const key, const size_t key_length); hal_error_t (*update)(const hal_rpc_hash_handle_t hash, -- cgit v1.2.3