aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2018-06-14 11:12:00 +0200
committerJérôme Forissier <jerome.forissier@linaro.org>2018-06-18 10:01:13 +0200
commit6e954a6e42bd37911605d3b4cd22e4d1d23c2372 (patch)
tree1c305f414f6c5eccc142cbf6d76bf8784836d569
parentb8d0b26e700584b85819b33306d93811deb48800 (diff)
core: add new RNG implementation
Adds a new cryptographically secure pseudo random number generator known as Fortuna. The implementation is based on the description in [0]. This implementation replaces the implementation in LTC which was used until now. Gathering of entropy has been refined with crypto_rng_add_event() to better match how entropy is added to Fortuna. A enum crypto_rng_src identifies the source of the event. The source also controls how the event is added. There are two options available, queue it in a circular buffer for later processing or adding it directly to a pool. The former option is suitable when being called from an interrupt handler or some other place where RPC to normal world is forbidden. plat_prng_add_jitter_entropy_norpc() is removed and plat_prng_add_jitter_entropy() is updated to use this new entropy source scheme. The configuration of LTC is simplified by this, now PRNG is always drawn via prng_mpa_desc. plat_rng_init() takes care of initializing the PRNG in order to allow platforms to override or enhance the Fortuna integration. [0] Link:https://www.schneier.com/academic/paperfiles/fortuna.pdf Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r--core/arch/arm/kernel/tee_time_arm_cntpct.c17
-rw-r--r--core/arch/arm/kernel/thread.c12
-rw-r--r--core/arch/arm/mm/tee_pager.c2
-rw-r--r--core/arch/arm/pta/system.c8
-rw-r--r--core/arch/arm/tee/entry_std.c8
-rw-r--r--core/crypto.mk3
-rw-r--r--core/crypto/rng_fortuna.c531
-rw-r--r--core/crypto/rng_hw.c26
-rw-r--r--core/crypto/sub.mk8
-rw-r--r--core/drivers/imx_snvs.c4
-rw-r--r--core/include/crypto/crypto.h51
-rw-r--r--core/include/tee/tee_cryp_utl.h16
-rw-r--r--core/lib/libtomcrypt/src/sub.mk1
-rw-r--r--core/lib/libtomcrypt/src/tee_ltc_provider.c204
-rw-r--r--core/tee/tee_cryp_utl.c55
15 files changed, 708 insertions, 238 deletions
diff --git a/core/arch/arm/kernel/tee_time_arm_cntpct.c b/core/arch/arm/kernel/tee_time_arm_cntpct.c
index ea36b65d..bf738e8a 100644
--- a/core/arch/arm/kernel/tee_time_arm_cntpct.c
+++ b/core/arch/arm/kernel/tee_time_arm_cntpct.c
@@ -3,18 +3,17 @@
* Copyright (c) 2014, 2015 Linaro Limited
*/
+#include <arm.h>
+#include <crypto/crypto.h>
#include <kernel/misc.h>
#include <kernel/tee_time.h>
-#include <trace.h>
#include <kernel/time_source.h>
#include <mm/core_mmu.h>
-#include <utee_defines.h>
-
-#include <tee/tee_cryp_utl.h>
-
-#include <stdint.h>
#include <mpa.h>
-#include <arm.h>
+#include <stdint.h>
+#include <tee/tee_cryp_utl.h>
+#include <trace.h>
+#include <utee_defines.h>
static TEE_Result arm_cntpct_get_sys_time(TEE_Time *time)
{
@@ -49,7 +48,7 @@ REGISTER_TIME_SOURCE(arm_cntpct_time_source)
* and adding one byte of entropy when we reach 8 rotated bits.
*/
-void plat_prng_add_jitter_entropy(void)
+void plat_prng_add_jitter_entropy(enum crypto_rng_src sid, unsigned int *pnum)
{
uint64_t tsc = read_cntpct();
int bytes = 0, n;
@@ -73,6 +72,6 @@ void plat_prng_add_jitter_entropy(void)
if (bytes) {
FMSG("%s: 0x%02X\n", __func__,
(int)acc & ((1 << (bytes * 8)) - 1));
- tee_prng_add_entropy((uint8_t *)&acc, bytes);
+ crypto_rng_add_event(sid, pnum, (uint8_t *)&acc, bytes);
}
}
diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c
index 1e67e2c5..ed8cb13d 100644
--- a/core/arch/arm/kernel/thread.c
+++ b/core/arch/arm/kernel/thread.c
@@ -143,6 +143,8 @@ static uint8_t thread_user_kdata_page[
static unsigned int thread_global_lock = SPINLOCK_UNLOCK;
static bool thread_prealloc_rpc_cache;
+static unsigned int thread_rpc_pnum;
+
static void init_canaries(void)
{
#ifdef CFG_WITH_STACK_CANARIES
@@ -1442,13 +1444,9 @@ uint32_t thread_rpc_cmd(uint32_t cmd, size_t num_params,
uint64_t carg;
size_t n;
- /*
- * Break recursion in case plat_prng_add_jitter_entropy_norpc()
- * sleeps on a mutex or unlocks a mutex with a sleeper (contended
- * mutex).
- */
- if (cmd != OPTEE_MSG_RPC_CMD_WAIT_QUEUE)
- plat_prng_add_jitter_entropy_norpc();
+ /* The source CRYPTO_RNG_SRC_JITTER_RPC is safe to use here */
+ plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_RPC,
+ &thread_rpc_pnum);
if (!get_rpc_arg(cmd, num_params, &arg, &carg))
return TEE_ERROR_OUT_OF_MEMORY;
diff --git a/core/arch/arm/mm/tee_pager.c b/core/arch/arm/mm/tee_pager.c
index d1caa139..ed74156b 100644
--- a/core/arch/arm/mm/tee_pager.c
+++ b/core/arch/arm/mm/tee_pager.c
@@ -371,7 +371,7 @@ void tee_pager_generate_authenc_key(void)
{
uint8_t key[PAGER_AE_KEY_BITS / 8];
- if (rng_generate(key, sizeof(key)) != TEE_SUCCESS)
+ if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS)
panic("failed to generate random");
if (internal_aes_gcm_expand_enc_key(key, sizeof(key),
&pager_ae_key))
diff --git a/core/arch/arm/pta/system.c b/core/arch/arm/pta/system.c
index dbb019fc..1186407d 100644
--- a/core/arch/arm/pta/system.c
+++ b/core/arch/arm/pta/system.c
@@ -6,11 +6,13 @@
#include <kernel/pseudo_ta.h>
#include <kernel/user_ta.h>
#include <pta_system.h>
-#include <tee/tee_cryp_utl.h>
+#include <crypto/crypto.h>
#include <util.h>
#define MAX_ENTROPY_IN 32u
+static unsigned int system_pnum;
+
static TEE_Result system_rng_reseed(struct tee_ta_session *s __unused,
uint32_t param_types,
TEE_Param params[TEE_NUM_PARAMS])
@@ -33,7 +35,9 @@ static TEE_Result system_rng_reseed(struct tee_ta_session *s __unused,
entropy_sz = MIN(entropy_sz, MAX_ENTROPY_IN);
- return tee_prng_add_entropy(entropy_input, entropy_sz);
+ crypto_rng_add_event(CRYPTO_RNG_SRC_NONSECURE, &system_pnum,
+ entropy_input, entropy_sz);
+ return TEE_SUCCESS;
}
static TEE_Result open_session(uint32_t param_types __unused,
diff --git a/core/arch/arm/tee/entry_std.c b/core/arch/arm/tee/entry_std.c
index 5a7fef92..47c97406 100644
--- a/core/arch/arm/tee/entry_std.c
+++ b/core/arch/arm/tee/entry_std.c
@@ -35,6 +35,8 @@ static struct mobj *shm_mobj;
static struct mobj **sdp_mem_mobjs;
#endif
+static unsigned int session_pnum;
+
static bool param_mem_from_mobj(struct param_mem *mem, struct mobj *mobj,
const paddr_t pa, const size_t sz)
{
@@ -295,7 +297,8 @@ static void entry_open_session(struct thread_smc_args *smc_args,
* un-predictable, using this property to increase randomness
* of prng
*/
- plat_prng_add_jitter_entropy();
+ plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
+ &session_pnum);
cleanup_params:
cleanup_params(arg->params + num_meta, saved_attr,
@@ -322,7 +325,8 @@ static void entry_close_session(struct thread_smc_args *smc_args,
goto out;
}
- plat_prng_add_jitter_entropy();
+ plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
+ &session_pnum);
s = (struct tee_ta_session *)(vaddr_t)arg->session;
res = tee_ta_close_session(s, &tee_open_sessions, NSAPP_IDENTITY);
diff --git a/core/crypto.mk b/core/crypto.mk
index 74536139..b0a50d54 100644
--- a/core/crypto.mk
+++ b/core/crypto.mk
@@ -48,6 +48,8 @@ CFG_CRYPTO_SHA256:=y
endif
endif
+$(eval $(call cryp-enable-all-depends,CFG_WITH_SOFTWARE_PRNG, AES ECB SHA256))
+
ifeq ($(CFG_CRYPTO_WITH_CE),y)
$(call force,CFG_AES_GCM_TABLE_BASED,n,conflicts with CFG_CRYPTO_WITH_CE)
@@ -135,4 +137,3 @@ _CFG_CRYPTO_WITH_HASH := $(call cryp-one-enabled, MD5 SHA1 SHA224 SHA256 SHA384
_CFG_CRYPTO_WITH_MAC := $(call cryp-one-enabled, HMAC CMAC CBC_MAC)
_CFG_CRYPTO_WITH_CBC := $(call cryp-one-enabled, CBC CBC_MAC)
_CFG_CRYPTO_WITH_ASN1 := $(call cryp-one-enabled, RSA DSA ECC)
-_CFG_CRYPTO_WITH_FORTUNA_PRNG := $(call cryp-all-enabled, AES SHA256)
diff --git a/core/crypto/rng_fortuna.c b/core/crypto/rng_fortuna.c
new file mode 100644
index 00000000..b9ce2d22
--- /dev/null
+++ b/core/crypto/rng_fortuna.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright (c) 2018, Linaro Limited */
+
+/*
+ * This is an implementation of the Fortuna cryptographic PRNG as defined in
+ * https://www.schneier.com/academic/paperfiles/fortuna.pdf
+ * There's one small exception, see comment in restart_pool() below.
+ */
+
+#include <assert.h>
+#include <crypto/crypto.h>
+#include <kernel/mutex.h>
+#include <kernel/refcount.h>
+#include <kernel/spinlock.h>
+#include <kernel/tee_time.h>
+#include <string.h>
+#include <types_ext.h>
+#include <utee_defines.h>
+#include <util.h>
+
+#define NUM_POOLS 32
+#define BLOCK_SIZE 16
+#define KEY_SIZE 32
+#define CIPHER_ALGO TEE_ALG_AES_ECB_NOPAD
+#define HASH_ALGO TEE_ALG_SHA256
+#define MIN_POOL_SIZE 64
+#define MAX_EVENT_DATA_LEN 32U
+#define RING_BUF_DATA_SIZE 4U
+
+/*
+ * struct fortuna_state - state of the Fortuna PRNG
+ * @ctx: Cipher context used to produce the random numbers
+ * @counter: Counter which is encrypted to produce the random numbers
+ * @pool0_length: Amount of data added to pool0
+ * @pool_ctx: One hash context for each pool
+ * @reseed_ctx: Hash context used while reseeding
+ * @reseed_count: Number of time we've reseeded the PRNG, used to tell
+ * which pools should be used in the reseed process
+ * @next_reseed_time: If we have a secure time, the earliest next time we
+ * may reseed
+ *
+ * To minimize the delay in crypto_rng_add_event() there's @pool_spin_lock
+ * which protects everything needed by this function.
+ *
+ * @next_reseed_time is used as a rate limiter for reseeding.
+ */
+static struct fortuna_state {
+ void *ctx;
+ uint64_t counter[2];
+ unsigned int pool0_length;
+ void *pool_ctx[NUM_POOLS];
+ void *reseed_ctx;
+ uint32_t reseed_count;
+#ifndef CFG_SECURE_TIME_SOURCE_REE
+ TEE_Time next_reseed_time;
+#endif
+} state;
+
+static struct mutex state_mu = MUTEX_INITIALIZER;
+
+static struct {
+ struct {
+ uint8_t snum;
+ uint8_t pnum;
+ uint8_t dlen;
+ uint8_t data[RING_BUF_DATA_SIZE];
+ } elem[8];
+ unsigned int begin;
+ unsigned int end;
+} ring_buffer;
+
+unsigned int ring_buffer_spin_lock;
+
+static void inc_counter(uint64_t counter[2])
+{
+ counter[0]++;
+ if (!counter[0])
+ counter[1]++;
+}
+
+static TEE_Result hash_init(void *ctx)
+{
+ return crypto_hash_init(ctx, HASH_ALGO);
+}
+
+static TEE_Result hash_update(void *ctx, const void *data, size_t dlen)
+{
+ return crypto_hash_update(ctx, HASH_ALGO, data, dlen);
+}
+
+static TEE_Result hash_final(void *ctx, uint8_t digest[KEY_SIZE])
+{
+ return crypto_hash_final(ctx, HASH_ALGO, digest, KEY_SIZE);
+}
+
+static TEE_Result key_from_data(void *ctx, const void *data, size_t dlen,
+ uint8_t key[KEY_SIZE])
+{
+ TEE_Result res;
+
+ res = hash_init(ctx);
+ if (res)
+ return res;
+ res = hash_update(ctx, data, dlen);
+ if (res)
+ return res;
+ return hash_final(ctx, key);
+}
+
+static TEE_Result cipher_init(void *ctx, uint8_t key[KEY_SIZE])
+{
+ return crypto_cipher_init(ctx, CIPHER_ALGO, TEE_MODE_ENCRYPT,
+ key, KEY_SIZE, NULL, 0, NULL, 0);
+}
+
+static void fortuna_done(void)
+{
+ size_t n;
+
+ for (n = 0; n < NUM_POOLS; n++) {
+ crypto_hash_free_ctx(state.pool_ctx[n], HASH_ALGO);
+ state.pool_ctx[n] = NULL;
+ }
+ crypto_hash_free_ctx(state.reseed_ctx, HASH_ALGO);
+ state.reseed_ctx = NULL;
+ crypto_cipher_free_ctx(state.ctx, CIPHER_ALGO);
+ state.ctx = NULL;
+}
+
+TEE_Result crypto_rng_init(const void *data, size_t dlen)
+{
+ TEE_Result res;
+ uint8_t key[KEY_SIZE];
+ void *ctx;
+ size_t n;
+
+ COMPILE_TIME_ASSERT(sizeof(state.counter) == BLOCK_SIZE);
+
+ if (state.ctx)
+ return TEE_ERROR_BAD_STATE;
+
+ memset(&state, 0, sizeof(state));
+
+ for (n = 0; n < NUM_POOLS; n++) {
+ res = crypto_hash_alloc_ctx(&state.pool_ctx[n], HASH_ALGO);
+ if (res)
+ goto err;
+ res = crypto_hash_init(state.pool_ctx[n], HASH_ALGO);
+ if (res)
+ goto err;
+ }
+
+ res = crypto_hash_alloc_ctx(&state.reseed_ctx, HASH_ALGO);
+ if (res)
+ goto err;
+
+ res = key_from_data(state.reseed_ctx, data, dlen, key);
+ if (res)
+ return res;
+
+ res = crypto_cipher_alloc_ctx(&ctx, CIPHER_ALGO);
+ if (res)
+ return res;
+ res = cipher_init(ctx, key);
+ if (res)
+ return res;
+ inc_counter(state.counter);
+ state.ctx = ctx;
+ return TEE_SUCCESS;
+err:
+ fortuna_done();
+ return res;
+}
+
+static void push_ring_buffer(uint8_t snum, uint8_t pnum, const void *data,
+ size_t dlen)
+{
+ uint8_t dl = MIN(RING_BUF_DATA_SIZE, dlen);
+ unsigned int next_begin;
+ uint32_t old_itr_status;
+
+ /* Spinlock to serialize writers */
+ old_itr_status = cpu_spin_lock_xsave(&ring_buffer_spin_lock);
+
+ next_begin = (ring_buffer.begin + 1) % ARRAY_SIZE(ring_buffer.elem);
+ if (next_begin == atomic_load_uint(&ring_buffer.end))
+ goto out; /* buffer is full */
+
+ ring_buffer.elem[next_begin].snum = snum;
+ ring_buffer.elem[next_begin].pnum = pnum;
+ ring_buffer.elem[next_begin].dlen = dl;
+ memcpy(ring_buffer.elem[next_begin].data, data, dl);
+
+ atomic_store_uint(&ring_buffer.begin, next_begin);
+
+out:
+ cpu_spin_unlock_xrestore(&ring_buffer_spin_lock, old_itr_status);
+}
+
+static size_t pop_ring_buffer(uint8_t *snum, uint8_t *pnum,
+ uint8_t data[RING_BUF_DATA_SIZE])
+{
+ unsigned int next_end;
+ size_t dlen;
+
+ if (atomic_load_uint(&ring_buffer.begin) == ring_buffer.end)
+ return 0;
+
+ next_end = (ring_buffer.end + 1) % ARRAY_SIZE(ring_buffer.elem);
+
+ *snum = ring_buffer.elem[ring_buffer.end].snum;
+ *pnum = ring_buffer.elem[ring_buffer.end].pnum;
+ dlen = MIN(ring_buffer.elem[ring_buffer.end].dlen, RING_BUF_DATA_SIZE);
+ assert(ring_buffer.elem[ring_buffer.end].dlen == dlen);
+ memcpy(data, ring_buffer.elem[ring_buffer.end].data, dlen);
+
+ atomic_store_uint(&ring_buffer.end, next_end);
+
+ return dlen;
+}
+
+static TEE_Result add_event(uint8_t snum, uint8_t pnum,
+ const void *data, size_t dlen)
+{
+ TEE_Result res;
+ size_t dl = MIN(MAX_EVENT_DATA_LEN, dlen);
+ uint8_t v[] = { snum, dl };
+
+ if (pnum >= NUM_POOLS)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ res = hash_update(state.pool_ctx[pnum], v, sizeof(v));
+ if (res)
+ return res;
+ res = hash_update(state.pool_ctx[pnum], data, dl);
+ if (res)
+ return res;
+ if (!pnum) {
+ unsigned int l;
+
+ if (!ADD_OVERFLOW(state.pool0_length, dl, &l))
+ state.pool0_length = l;
+ }
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result drain_ring_buffer(void)
+{
+ while (true) {
+ TEE_Result res;
+ uint8_t snum;
+ uint8_t pnum;
+ uint8_t data[RING_BUF_DATA_SIZE];
+ size_t dlen;
+
+ dlen = pop_ring_buffer(&snum, &pnum, data);
+ if (!dlen)
+ return TEE_SUCCESS;
+
+ res = add_event(snum, pnum, data, dlen);
+ if (res)
+ return res;
+ }
+}
+
+static unsigned int get_next_pnum(unsigned int *pnum)
+{
+ unsigned int nval;
+ unsigned int oval = atomic_load_uint(pnum);
+
+ while (true) {
+ nval = (oval + 1) % NUM_POOLS;
+
+ if (atomic_cas_uint(pnum, &oval, nval)) {
+ /*
+ * *pnum is normally initialized to 0 and we'd like
+ * to start feeding pool number 0 as that's the
+ * most important one.
+ *
+ * If we where to take just *pnum and increase it
+ * later multiple updaters could end up with the
+ * same number.
+ *
+ * By increasing first we get the number unique for
+ * next update and by subtracting one (using
+ * modulus) we get the number for this update.
+ */
+ return (nval + NUM_POOLS - 1) % NUM_POOLS;
+ }
+ /*
+ * At this point atomic_cas_uint() has updated oval to the
+ * current *pnum.
+ */
+ }
+}
+
+void crypto_rng_add_event(enum crypto_rng_src sid, unsigned int *pnum,
+ const void *data, size_t dlen)
+{
+ unsigned int pn = get_next_pnum(pnum);
+ uint8_t snum = sid >> 1;
+
+ if (CRYPTO_RNG_SRC_IS_QUICK(sid)) {
+ push_ring_buffer(snum, pn, data, dlen);
+ } else {
+ mutex_lock(&state_mu);
+ add_event(snum, pn, data, dlen);
+ drain_ring_buffer();
+ mutex_unlock(&state_mu);
+ }
+}
+
+/* GenerateBlocks */
+static TEE_Result generate_blocks(void *block, size_t nblocks)
+{
+ uint8_t *b = block;
+ size_t n;
+
+ for (n = 0; n < nblocks; n++) {
+ TEE_Result res = crypto_cipher_update(state.ctx, CIPHER_ALGO,
+ TEE_MODE_ENCRYPT, false,
+ (void *)state.counter,
+ BLOCK_SIZE,
+ b + n * BLOCK_SIZE);
+
+ /*
+ * Make sure to increase the counter before returning an
+ * eventual errors, we must never re-use the counter with
+ * the same key.
+ */
+ inc_counter(state.counter);
+ if (res)
+ return res;
+ }
+
+ return TEE_SUCCESS;
+}
+
+/* GenerateRandomData */
+static TEE_Result generate_random_data(void *buf, size_t blen)
+{
+ TEE_Result res;
+
+ res = generate_blocks(buf, blen / BLOCK_SIZE);
+ if (res)
+ return res;
+ if (blen % BLOCK_SIZE) {
+ uint8_t block[BLOCK_SIZE];
+ uint8_t *b = (uint8_t *)buf + ROUNDDOWN(blen, BLOCK_SIZE);
+
+ res = generate_blocks(block, 1);
+ if (res)
+ return res;
+ memcpy(b, block, blen % BLOCK_SIZE);
+ }
+
+ return TEE_SUCCESS;
+}
+
+#ifdef CFG_SECURE_TIME_SOURCE_REE
+static bool reseed_rate_limiting(void)
+{
+ /*
+ * There's no point in checking REE time for reseed rate limiting,
+ * and also it makes it less complicated if we can avoid doing RPC
+ * here.
+ */
+ return false;
+}
+#else
+static bool reseed_rate_limiting(void)
+{
+ TEE_Result res;
+ TEE_Time time;
+ const TEE_Time time_100ms = { 0, 100 };
+
+ res = tee_time_get_sys_time(&time);
+ /*
+ * Failure to read time must result in allowing reseed or we could
+ * block reseeding forever.
+ */
+ if (res)
+ return false;
+
+ if (TEE_TIME_LT(time, state.next_reseed_time))
+ return true;
+
+ /* Time to reseed, calculate next time reseed is OK */
+ TEE_TIME_ADD(time, time_100ms, state.next_reseed_time);
+ return false;
+}
+#endif
+
+static TEE_Result restart_pool(void *pool_ctx, uint8_t pool_digest[KEY_SIZE])
+{
+ TEE_Result res = hash_final(pool_ctx, pool_digest);
+
+ if (res)
+ return res;
+
+ res = hash_init(pool_ctx);
+ if (res)
+ return res;
+
+ /*
+ * Restart the pool with the digest of the old pool. This is an
+ * extension to Fortuna. In the original Fortuna all pools was
+ * restarted from scratch. This extension is one more defense
+ * against spamming of the pools with known data which could lead
+ * to the spammer knowing the state of the pools.
+ *
+ * This extra precaution could be useful since OP-TEE sometimes
+ * have very few sources of good entropy and at the same time has
+ * sources that could quite easily be predicted by an attacker.
+ */
+ return hash_update(pool_ctx, pool_digest, KEY_SIZE);
+}
+
+static bool reseed_from_pool(uint32_t reseed_count, size_t pool_num)
+{
+ /*
+ * Specification says: use pool if
+ * 2^pool_num is a divisor of reseed_count
+ *
+ * in order to avoid an expensive modulus operation we're
+ * optimizing this below.
+ */
+ return !pool_num || !((reseed_count >> (pool_num - 1)) & 1);
+}
+
+static TEE_Result maybe_reseed(void)
+{
+ TEE_Result res;
+ size_t n;
+ uint8_t pool_digest[KEY_SIZE];
+
+ if (state.pool0_length < MIN_POOL_SIZE)
+ return TEE_SUCCESS;
+
+ if (reseed_rate_limiting())
+ return TEE_SUCCESS;
+
+ state.reseed_count++;
+
+ res = hash_init(state.reseed_ctx);
+ if (res)
+ return res;
+
+ for (n = 0;
+ n < NUM_POOLS && reseed_from_pool(state.reseed_count, n); n++) {
+ res = restart_pool(state.pool_ctx[n], pool_digest);
+ if (res)
+ return res;
+ if (!n)
+ state.pool0_length = 0;
+
+ res = hash_update(state.reseed_ctx, pool_digest, KEY_SIZE);
+ if (res)
+ return res;
+ }
+ res = hash_final(state.reseed_ctx, pool_digest);
+ if (res)
+ return res;
+
+ crypto_cipher_final(state.ctx, CIPHER_ALGO);
+ res = crypto_cipher_init(state.ctx, CIPHER_ALGO, TEE_MODE_ENCRYPT,
+ pool_digest, KEY_SIZE, NULL, 0, NULL, 0);
+ if (res)
+ return res;
+ inc_counter(state.counter);
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result fortuna_read(void *buf, size_t blen)
+{
+ TEE_Result res;
+
+ if (!state.ctx)
+ return TEE_ERROR_BAD_STATE;
+
+ mutex_lock(&state_mu);
+
+ res = maybe_reseed();
+ if (res)
+ goto out;
+
+ if (blen) {
+ uint8_t new_key[KEY_SIZE];
+
+ res = generate_random_data(buf, blen);
+ if (res)
+ goto out;
+
+ res = generate_blocks(new_key, KEY_SIZE / BLOCK_SIZE);
+ if (res)
+ goto out;
+ crypto_cipher_final(state.ctx, CIPHER_ALGO);
+ res = cipher_init(state.ctx, new_key);
+ if (res)
+ goto out;
+ }
+
+ res = drain_ring_buffer();
+out:
+ if (res)
+ fortuna_done();
+ mutex_unlock(&state_mu);
+
+ return res;
+}
+
+TEE_Result crypto_rng_read(void *buf, size_t blen)
+{
+ size_t offs = 0;
+
+ while (true) {
+ TEE_Result res;
+ size_t n;
+
+ /* Draw at most 1 MiB of random on a single key */
+ n = MIN(blen - offs, SIZE_1M);
+ if (!n)
+ return TEE_SUCCESS;
+ res = fortuna_read((uint8_t *)buf + offs, n);
+ if (res)
+ return res;
+ offs += n;
+ }
+}
diff --git a/core/crypto/rng_hw.c b/core/crypto/rng_hw.c
new file mode 100644
index 00000000..577eacaa
--- /dev/null
+++ b/core/crypto/rng_hw.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright (c) 2018, Linaro Limited */
+
+#include <compiler.h>
+#include <crypto/crypto.h>
+#include <tee/tee_cryp_utl.h>
+#include <types_ext.h>
+
+TEE_Result __weak crypto_rng_init(const void *data __unused,
+ size_t dlen __unused)
+{
+ return TEE_SUCCESS;
+}
+
+void __weak crypto_rng_add_event(enum crypto_rng_src sid __unused,
+ unsigned int *pnum __unused,
+ const void *data __unused,
+ size_t dlen __unused)
+{
+}
+
+TEE_Result __weak crypto_rng_read(void *buf, size_t blen)
+{
+ return get_rng_array(buf, blen);
+}
+
diff --git a/core/crypto/sub.mk b/core/crypto/sub.mk
index f21eface..bb16a3eb 100644
--- a/core/crypto/sub.mk
+++ b/core/crypto/sub.mk
@@ -6,4 +6,10 @@ srcs-y += aes-gcm-ghash-tbl.c
else
srcs-y += aes-gcm-ghash.c
endif
-srcs-$(CFG_WITH_USER_TA) += signed_hdr.c \ No newline at end of file
+srcs-$(CFG_WITH_USER_TA) += signed_hdr.c
+
+ifeq ($(CFG_WITH_SOFTWARE_PRNG),y)
+srcs-y += rng_fortuna.c
+else
+srcs-y += rng_hw.c
+endif
diff --git a/core/drivers/imx_snvs.c b/core/drivers/imx_snvs.c
index bf5a7df6..278d42f9 100644
--- a/core/drivers/imx_snvs.c
+++ b/core/drivers/imx_snvs.c
@@ -157,7 +157,7 @@ TEE_Result snvs_srtc_enable(void)
}
/* Reused from tee_time_arm_cntpct.c */
-void plat_prng_add_jitter_entropy(void)
+void plat_prng_add_jitter_entropy(enum crypto_rng_src sid, unsigned int *pnum)
{
uint64_t tsc = snvs_srtc_read_lp_counter();
int bytes = 0, n;
@@ -181,6 +181,6 @@ void plat_prng_add_jitter_entropy(void)
if (bytes) {
FMSG("%s: 0x%02" PRIX16, __func__,
acc & GENMASK_32(bytes * 8, 0));
- tee_prng_add_entropy((uint8_t *)&acc, bytes);
+ crypto_rng_add_event(sid, pnum, (uint8_t *)&acc, bytes);
}
}
diff --git a/core/include/crypto/crypto.h b/core/include/crypto/crypto.h
index 38cf752d..2018d3cf 100644
--- a/core/include/crypto/crypto.h
+++ b/core/include/crypto/crypto.h
@@ -256,13 +256,54 @@ TEE_Result crypto_acipher_ecc_shared_secret(struct ecc_keypair *private_key,
TEE_Result hash_sha256_check(const uint8_t *hash, const uint8_t *data,
size_t data_size);
-/* Add entropy to PRNG entropy pool. */
-TEE_Result crypto_rng_add_entropy(const uint8_t *inbuf, size_t len);
+#define CRYPTO_RNG_SRC_IS_QUICK(sid) (!!((sid) & 1))
-/* To read random data from PRNG implementation. */
-TEE_Result crypto_rng_read(void *buf, size_t blen);
+/*
+ * enum crypto_rng_src - RNG entropy source
+ *
+ * Identifiers for different RNG entropy sources. The lowest bit indicates
+ * if the source is to be merely queued (bit is 1) or if it's delivered
+ * directly to the pool. The difference is that in the latter case RPC to
+ * normal world can be performed and in the former it must not.
+ */
+enum crypto_rng_src {
+ CRYPTO_RNG_SRC_JITTER_SESSION = (0 << 1 | 0),
+ CRYPTO_RNG_SRC_JITTER_RPC = (1 << 1 | 1),
+ CRYPTO_RNG_SRC_NONSECURE = (1 << 1 | 0),
+};
+
+/*
+ * crypto_rng_init() - initialize the RNG
+ * @data: buffer with initial seed
+ * @dlen: length of @data
+ */
+TEE_Result crypto_rng_init(const void *data, size_t dlen);
-TEE_Result rng_generate(void *buffer, size_t len);
+/*
+ * crypto_rng_add_event() - supply entropy to RNG from a source
+ * @sid: Source identifier, should be unique for a specific source
+ * @pnum: Pool number, acquired using crypto_rng_get_next_pool_num()
+ * @data: Data associated with the event
+ * @dlen: Length of @data
+ *
+ * @sid controls whether the event is merly queued in a ring buffer or if
+ * it's added to one of the pools directly. If CRYPTO_RNG_SRC_IS_QUICK() is
+ * true (lowest bit set) events are queue otherwise added to corresponding
+ * pool. If CRYPTO_RNG_SRC_IS_QUICK() is false, eventual queued events are
+ * added to their queues too.
+ */
+void crypto_rng_add_event(enum crypto_rng_src sid, unsigned int *pnum,
+ const void *data, size_t dlen);
+
+/*
+ * crypto_rng_read() - read cryptograhically secure RNG
+ * @buf: Buffer to hold the data
+ * @len: Length of buffer.
+ *
+ * Eventual queued events are also added to their pools during this
+ * function call.
+ */
+TEE_Result crypto_rng_read(void *buf, size_t len);
TEE_Result crypto_aes_expand_enc_key(const void *key, size_t key_len,
void *enc_key, unsigned int *rounds);
diff --git a/core/include/tee/tee_cryp_utl.h b/core/include/tee/tee_cryp_utl.h
index 92534b3c..5ad15e6f 100644
--- a/core/include/tee/tee_cryp_utl.h
+++ b/core/include/tee/tee_cryp_utl.h
@@ -7,6 +7,7 @@
#define TEE_CRYP_UTL_H
#include <tee_api_types.h>
+#include <crypto/crypto.h>
#if !defined(CFG_WITH_SOFTWARE_PRNG)
TEE_Result get_rng_array(void *buffer, int len);
@@ -26,12 +27,17 @@ TEE_Result tee_aes_cbc_cts_update(void *cbc_ctx, void *ecb_ctx,
const uint8_t *data, size_t len,
uint8_t *dst);
-TEE_Result tee_prng_add_entropy(const uint8_t *in, size_t len);
-void plat_prng_add_jitter_entropy(void);
/*
- * The _norpc version must not invoke Normal World, or infinite recursion
- * may occur. As an exception however, using mutexes is allowed.
+ * plat_prng_add_jitter_entropy() - Adds jitter to RNG entropy pool
+ * @sid: source ID, normally unique per location of the call
+ * @pnum: pointer where the pool number for this @sid is stored
+ *
+ * Note that the supplied @sid controls (CRYPTO_RNG_SRC_IS_QUICK()) whether
+ * RPC is allowed to be performed or the event just will be queued for later
+ * consumption.
*/
-void plat_prng_add_jitter_entropy_norpc(void);
+void plat_prng_add_jitter_entropy(enum crypto_rng_src sid, unsigned int *pnum);
+
+void plat_rng_init(void);
#endif
diff --git a/core/lib/libtomcrypt/src/sub.mk b/core/lib/libtomcrypt/src/sub.mk
index 89e74bd9..ca88fb1f 100644
--- a/core/lib/libtomcrypt/src/sub.mk
+++ b/core/lib/libtomcrypt/src/sub.mk
@@ -16,4 +16,3 @@ subdirs-$(_CFG_CRYPTO_WITH_ACIPHER) += math
subdirs-y += misc
subdirs-y += modes
subdirs-$(_CFG_CRYPTO_WITH_ACIPHER) += pk
-subdirs-$(CFG_WITH_SOFTWARE_PRNG) += prngs
diff --git a/core/lib/libtomcrypt/src/tee_ltc_provider.c b/core/lib/libtomcrypt/src/tee_ltc_provider.c
index 4cec762a..86000421 100644
--- a/core/lib/libtomcrypt/src/tee_ltc_provider.c
+++ b/core/lib/libtomcrypt/src/tee_ltc_provider.c
@@ -25,8 +25,6 @@
#include <kernel/thread.h>
#endif
-#if !defined(CFG_WITH_SOFTWARE_PRNG)
-
/* Random generator */
static int prng_mpa_start(union Prng_state *prng __unused)
{
@@ -49,10 +47,10 @@ static int prng_mpa_ready(union Prng_state *prng __unused)
static unsigned long prng_mpa_read(unsigned char *out, unsigned long outlen,
union Prng_state *prng __unused)
{
- if (TEE_SUCCESS == get_rng_array(out, outlen))
- return outlen;
- else
+ if (crypto_rng_read(out, outlen))
return 0;
+
+ return outlen;
}
static int prng_mpa_done(union Prng_state *prng __unused)
@@ -92,69 +90,6 @@ static const struct ltc_prng_descriptor prng_mpa_desc = {
.test = &prng_mpa_test,
};
-#endif /* !CFG_WITH_SOFTWARE_PRNG */
-
-struct tee_ltc_prng {
- int index;
- const char *name;
- prng_state state;
- bool inited;
-};
-
-static struct tee_ltc_prng _tee_ltc_prng =
-#if defined(CFG_WITH_SOFTWARE_PRNG)
- {
-#if defined(_CFG_CRYPTO_WITH_FORTUNA_PRNG)
- .name = "fortuna",
-#else
- /*
- * we need AES and SHA256 for fortuna PRNG,
- * if the system configuration can't provide those,
- * fallback to RC4
- */
- .name = "rc4",
-#endif
- };
-#else
- {
- .name = "prng_mpa",
- };
-#endif
-
-static struct tee_ltc_prng *tee_ltc_get_prng(void)
-{
- return &_tee_ltc_prng;
-}
-
-static TEE_Result tee_ltc_prng_init(struct tee_ltc_prng *prng)
-{
- int res;
- int prng_index;
-
- assert(prng);
-
- prng_index = find_prng(prng->name);
- if (prng_index == -1)
- return TEE_ERROR_BAD_PARAMETERS;
-
- if (!prng->inited) {
- res = prng_descriptor[prng_index]->start(&prng->state);
- if (res != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
-
- plat_prng_add_jitter_entropy_norpc();
-
- res = prng_descriptor[prng_index]->ready(&prng->state);
- if (res != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
-
- prng->index = prng_index;
- prng->inited = true;
- }
-
- return TEE_SUCCESS;
-}
-
/*
* tee_ltc_reg_algs(): Registers
* - algorithms
@@ -189,16 +124,7 @@ static void tee_ltc_reg_algs(void)
#if defined(CFG_CRYPTO_SHA512)
register_hash(&sha512_desc);
#endif
-
-#if defined(CFG_WITH_SOFTWARE_PRNG)
-#if defined(_CFG_CRYPTO_WITH_FORTUNA_PRNG)
- register_prng(&fortuna_desc);
-#else
- register_prng(&rc4_desc);
-#endif
-#else
register_prng(&prng_mpa_desc);
-#endif
}
@@ -692,13 +618,12 @@ TEE_Result crypto_acipher_gen_rsa_key(struct rsa_keypair *key, size_t key_size)
rsa_key ltc_tmp_key;
int ltc_res;
long e;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
/* get the public exponent */
e = mp_get_int(key->e);
/* Generate a temporary RSA key */
- ltc_res = rsa_make_key(&prng->state, prng->index, key_size/8, e,
+ ltc_res = rsa_make_key(NULL, find_prng("prng_mpa"), key_size / 8, e,
&ltc_tmp_key);
if (ltc_res != CRYPT_OK) {
res = TEE_ERROR_BAD_PARAMETERS;
@@ -934,7 +859,6 @@ TEE_Result crypto_acipher_rsaes_encrypt(uint32_t algo,
.e = key->e,
.N = key->n
};
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
mod_size = ltc_mp.unsigned_size((void *)(ltc_key.N));
if (*dst_len < mod_size) {
@@ -956,7 +880,7 @@ TEE_Result crypto_acipher_rsaes_encrypt(uint32_t algo,
ltc_res = rsa_encrypt_key_ex(src, src_len, dst,
(unsigned long *)(dst_len), label,
- label_len, &prng->state, prng->index,
+ label_len, NULL, find_prng("prng_mpa"),
ltc_hashindex, ltc_rsa_algo, &ltc_key);
switch (ltc_res) {
case CRYPT_PK_INVALID_PADDING:
@@ -988,7 +912,6 @@ TEE_Result crypto_acipher_rsassa_sign(uint32_t algo, struct rsa_keypair *key,
int ltc_res, ltc_rsa_algo, ltc_hashindex;
unsigned long ltc_sig_len;
rsa_key ltc_key = { 0, };
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
ltc_key.type = PK_PRIVATE;
ltc_key.e = key->e;
@@ -1050,7 +973,7 @@ TEE_Result crypto_acipher_rsassa_sign(uint32_t algo, struct rsa_keypair *key,
ltc_sig_len = mod_size;
ltc_res = rsa_sign_hash_ex(msg, msg_len, sig, &ltc_sig_len,
- ltc_rsa_algo, &prng->state, prng->index,
+ ltc_rsa_algo, NULL, find_prng("prng_mpa"),
ltc_hashindex, salt_len, &ltc_key);
*sig_len = ltc_sig_len;
@@ -1187,7 +1110,6 @@ TEE_Result crypto_acipher_gen_dsa_key(struct dsa_keypair *key, size_t key_size)
dsa_key ltc_tmp_key;
size_t group_size, modulus_size = key_size/8;
int ltc_res;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
if (modulus_size <= 128)
group_size = 20;
@@ -1199,7 +1121,7 @@ TEE_Result crypto_acipher_gen_dsa_key(struct dsa_keypair *key, size_t key_size)
group_size = 40;
/* Generate the DSA key */
- ltc_res = dsa_make_key(&prng->state, prng->index, group_size,
+ ltc_res = dsa_make_key(NULL, find_prng("prng_mpa"), group_size,
modulus_size, &ltc_tmp_key);
if (ltc_res != CRYPT_OK) {
res = TEE_ERROR_BAD_PARAMETERS;
@@ -1238,7 +1160,6 @@ TEE_Result crypto_acipher_dsa_sign(uint32_t algo, struct dsa_keypair *key,
.y = key->y,
.x = key->x,
};
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
if (algo != TEE_ALG_DSA_SHA1 &&
algo != TEE_ALG_DSA_SHA224 &&
@@ -1270,8 +1191,8 @@ TEE_Result crypto_acipher_dsa_sign(uint32_t algo, struct dsa_keypair *key,
goto err;
}
- ltc_res = dsa_sign_hash_raw(msg, msg_len, r, s, &prng->state,
- prng->index, &ltc_key);
+ ltc_res = dsa_sign_hash_raw(msg, msg_len, r, s, NULL,
+ find_prng("prng_mpa"), &ltc_key);
if (ltc_res == CRYPT_OK) {
*sig_len = 2 * mp_unsigned_bin_size(ltc_key.q);
@@ -1363,12 +1284,11 @@ TEE_Result crypto_acipher_gen_dh_key(struct dh_keypair *key, struct bignum *q,
TEE_Result res;
dh_key ltc_tmp_key;
int ltc_res;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
/* Generate the DH key */
ltc_tmp_key.g = key->g;
ltc_tmp_key.p = key->p;
- ltc_res = dh_make_key(&prng->state, prng->index, q, xbits,
+ ltc_res = dh_make_key(NULL, find_prng("prng_mpa"), q, xbits,
&ltc_tmp_key);
if (ltc_res != CRYPT_OK) {
res = TEE_ERROR_BAD_PARAMETERS;
@@ -1521,7 +1441,6 @@ TEE_Result crypto_acipher_gen_ecc_key(struct ecc_keypair *key)
TEE_Result res;
ecc_key ltc_tmp_key;
int ltc_res;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
size_t key_size_bytes = 0;
size_t key_size_bits = 0;
@@ -1531,7 +1450,7 @@ TEE_Result crypto_acipher_gen_ecc_key(struct ecc_keypair *key)
}
/* Generate the ECC key */
- ltc_res = ecc_make_key(&prng->state, prng->index,
+ ltc_res = ecc_make_key(NULL, find_prng("prng_mpa"),
key_size_bytes, &ltc_tmp_key);
if (ltc_res != CRYPT_OK) {
return TEE_ERROR_BAD_PARAMETERS;
@@ -1647,7 +1566,6 @@ TEE_Result crypto_acipher_ecc_sign(uint32_t algo, struct ecc_keypair *key,
void *r, *s;
size_t key_size_bytes;
ecc_key ltc_key;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
if (algo == 0) {
res = TEE_ERROR_BAD_PARAMETERS;
@@ -1672,7 +1590,7 @@ TEE_Result crypto_acipher_ecc_sign(uint32_t algo, struct ecc_keypair *key,
}
ltc_res = ecc_sign_hash_raw(msg, msg_len, r, s,
- &prng->state, prng->index, &ltc_key);
+ NULL, find_prng("prng_mpa"), &ltc_key);
if (ltc_res == CRYPT_OK) {
*sig_len = 2 * key_size_bytes;
@@ -2867,69 +2785,6 @@ void crypto_aes_gcm_final(void *ctx)
}
#endif /*CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB*/
-/******************************************************************************
- * Pseudo Random Number Generator
- ******************************************************************************/
-TEE_Result crypto_rng_read(void *buf, size_t blen)
-{
- int err;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
-
- err = prng_is_valid(prng->index);
-
- if (err != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
-
- if (prng_descriptor[prng->index]->read(buf, blen, &prng->state) !=
- (unsigned long)blen)
- return TEE_ERROR_BAD_STATE;
-
- return TEE_SUCCESS;
-}
-
-/* Called as a result of rng_generate() below */
-static TEE_Result _tee_ltc_prng_add_entropy(
- const uint8_t *inbuf __maybe_unused, size_t len __maybe_unused)
-{
-#if defined(CFG_WITH_SOFTWARE_PRNG)
- int err;
-#ifdef _CFG_CRYPTO_WITH_FORTUNA_PRNG
- int (*add_entropy)(const unsigned char *, unsigned long,
- prng_state *) = fortuna_add_entropy;
-#else
- int (*add_entropy)(const unsigned char *, unsigned long,
- prng_state *) = rc4_add_entropy;
-#endif
-
- err = add_entropy(inbuf, len, &_tee_ltc_prng.state);
- if (err != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
-
- return TEE_SUCCESS;
-#else
- return TEE_ERROR_BAD_STATE;
-#endif
-}
-
-TEE_Result crypto_rng_add_entropy(const uint8_t *inbuf, size_t len)
-{
- int err;
- struct tee_ltc_prng *prng = tee_ltc_get_prng();
-
- err = prng_is_valid(prng->index);
-
- if (err != CRYPT_OK)
- return _tee_ltc_prng_add_entropy(inbuf, len);
-
- err = prng_descriptor[prng->index]->add_entropy(
- inbuf, len, &prng->state);
-
- if (err != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
-
- return TEE_SUCCESS;
-}
-
TEE_Result crypto_init(void)
{
#if defined(_CFG_CRYPTO_WITH_ACIPHER)
@@ -2937,7 +2792,7 @@ TEE_Result crypto_init(void)
#endif
tee_ltc_reg_algs();
- return tee_ltc_prng_init(tee_ltc_get_prng());
+ return TEE_SUCCESS;
}
#if defined(CFG_WITH_VFP)
@@ -2971,39 +2826,6 @@ TEE_Result hash_sha256_check(const uint8_t *hash, const uint8_t *data,
}
#endif
-TEE_Result rng_generate(void *buffer, size_t len)
-{
-#if defined(CFG_WITH_SOFTWARE_PRNG)
-#ifdef _CFG_CRYPTO_WITH_FORTUNA_PRNG
- int (*start)(prng_state *) = fortuna_start;
- int (*ready)(prng_state *) = fortuna_ready;
- unsigned long (*read)(unsigned char *, unsigned long, prng_state *) =
- fortuna_read;
-#else
- int (*start)(prng_state *) = rc4_start;
- int (*ready)(prng_state *) = rc4_ready;
- unsigned long (*read)(unsigned char *, unsigned long, prng_state *) =
- rc4_read;
-#endif
-
- if (!_tee_ltc_prng.inited) {
- if (start(&_tee_ltc_prng.state) != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
- plat_prng_add_jitter_entropy_norpc();
- if (ready(&_tee_ltc_prng.state) != CRYPT_OK)
- return TEE_ERROR_BAD_STATE;
- _tee_ltc_prng.inited = true;
- }
- if (read(buffer, len, &_tee_ltc_prng.state) != len)
- return TEE_ERROR_BAD_STATE;
- return TEE_SUCCESS;
-
-
-#else
- return get_rng_array(buffer, len);
-#endif
-}
-
TEE_Result crypto_aes_expand_enc_key(const void *key, size_t key_len,
void *enc_key, unsigned int *rounds)
{
diff --git a/core/tee/tee_cryp_utl.c b/core/tee/tee_cryp_utl.c
index 78277f35..a7dfe342 100644
--- a/core/tee/tee_cryp_utl.c
+++ b/core/tee/tee_cryp_utl.c
@@ -5,12 +5,14 @@
#include <crypto/crypto.h>
#include <initcall.h>
+#include <kernel/panic.h>
#include <kernel/tee_time.h>
#include <rng_support.h>
#include <stdlib.h>
#include <string_ext.h>
#include <string.h>
#include <tee/tee_cryp_utl.h>
+#include <trace.h>
#include <utee_defines.h>
#if !defined(CFG_WITH_SOFTWARE_PRNG)
@@ -329,34 +331,65 @@ TEE_Result tee_aes_cbc_cts_update(void *cbc_ctx, void *ecb_ctx,
return TEE_SUCCESS;
}
-TEE_Result tee_prng_add_entropy(const uint8_t *in, size_t len)
-{
- return crypto_rng_add_entropy(in, len);
-}
-
/*
* Override this in your platform code to feed the PRNG platform-specific
* jitter entropy. This implementation does not efficiently deliver entropy
* and is here for backwards-compatibility.
*/
-__weak void plat_prng_add_jitter_entropy(void)
+__weak void plat_prng_add_jitter_entropy(enum crypto_rng_src sid,
+ unsigned int *pnum)
{
TEE_Time current;
+#ifdef CFG_SECURE_TIME_SOURCE_REE
+ if (CRYPTO_RNG_SRC_IS_QUICK(sid))
+ return; /* Can't read REE time here */
+#endif
+
if (tee_time_get_sys_time(&current) == TEE_SUCCESS)
- tee_prng_add_entropy((uint8_t *)&current, sizeof(current));
+ crypto_rng_add_event(sid, pnum, &current, sizeof(current));
}
-__weak void plat_prng_add_jitter_entropy_norpc(void)
+__weak void plat_rng_init(void)
{
+ TEE_Result res = TEE_SUCCESS;
+ TEE_Time t;
+
#ifndef CFG_SECURE_TIME_SOURCE_REE
- plat_prng_add_jitter_entropy();
+ /*
+ * This isn't much of a seed. Ideally we should either get a seed from
+ * a hardware RNG or from a previously saved seed.
+ *
+ * Seeding with hardware RNG is currently up to the platform to
+ * override this function.
+ *
+ * Seeding with a saved seed will require cooperation from normal
+ * world, this is still TODO.
+ */
+ res = tee_time_get_sys_time(&t);
+#else
+ EMSG("Warning: seeding RNG with zeroes");
+ memset(&t, 0, sizeof(t));
#endif
+ if (!res)
+ res = crypto_rng_init(&t, sizeof(t));
+ if (res) {
+ EMSG("Failed to initialize RNG: %#" PRIx32, res);
+ panic();
+ }
}
static TEE_Result tee_cryp_init(void)
{
- return crypto_init();
-}
+ TEE_Result res = crypto_init();
+ res = crypto_init();
+ if (res) {
+ EMSG("Failed to initialize crypto API: %#" PRIx32, res);
+ panic();
+ }
+ plat_rng_init();
+
+ return TEE_SUCCESS;
+}
service_init(tee_cryp_init);