summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto
diff options
context:
space:
mode:
authorVadim Sukhomlinov <sukhomlinov@google.com>2021-08-19 09:04:45 -0700
committerCommit Bot <commit-bot@chromium.org>2021-08-23 22:36:40 +0000
commit93017e6d8a63ce28a71f59d9f1ea7a733be6926a (patch)
tree57c6cdf793a7e9f72a61c64d4d350e00784c47b6 /board/cr50/dcrypto
parent8ee57eba1e47bee8f46d85f5ad4232208acb552a (diff)
downloadchrome-ec-93017e6d8a63ce28a71f59d9f1ea7a733be6926a.tar.gz
cr50: replace direct calls to EC OS from FIPS module with callbacks
In order to implement self-integrity test for FIPS module we need to make sure binary code of module in image doesn't change from build to build. To do that we already place FIPS module as constant address. However, any call to functions outside the module creates a relocation which is changing depending on location of that external function in the image. To prevent that we either need to bring these functions in the module like it was done with memcpy() and some others or replace their invocations with callbacks. Task & Memory management functions are hard to bring in the module, so replace few invocations with indirect calls using vtable. This way invocation code will remain the same. 1. Identify and minimize dependency on EC OS - remove few asserts and cprintfs. 2. Remove checking privilege level in TRNG init - we know that it is high by the order of initialization in board_init() and that our RO doesn't drop permissions. Correct initialization of TRNG is important for certification, so we can't just assume it may be initialized improperly. 3. Added vtable with EC OS functions, initialization of FIPS module vtable in board_init(). 4. Switched to using vtable instead of direct calls. Note, we continue to use EC OS with CRYPTO_TEST=1 to reduce vtable size and image size. BUG=b:138578318 TEST=make BOARD=cr50; tests Signed-off-by: Vadim Sukhomlinov <sukhomlinov@google.com> Change-Id: Ibd7bd2353fc4e7e5886f9bfef96b36dc64ff2359 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3107847 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Tested-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Auto-Submit: Vadim Sukhomlinov <sukhomlinov@chromium.org> Commit-Queue: Andrey Pronin <apronin@chromium.org>
Diffstat (limited to 'board/cr50/dcrypto')
-rw-r--r--board/cr50/dcrypto/bn.c39
-rw-r--r--board/cr50/dcrypto/dcrypto_runtime.c22
-rw-r--r--board/cr50/dcrypto/sha_hw.c9
-rw-r--r--board/cr50/dcrypto/trng.c13
4 files changed, 52 insertions, 31 deletions
diff --git a/board/cr50/dcrypto/bn.c b/board/cr50/dcrypto/bn.c
index 671ce6256e..4f0963d902 100644
--- a/board/cr50/dcrypto/bn.c
+++ b/board/cr50/dcrypto/bn.c
@@ -8,19 +8,11 @@
#endif
#include "dcrypto.h"
+#include "fips.h"
#include "internal.h"
#include "trng.h"
-
-#include <assert.h>
-
-#ifdef CONFIG_WATCHDOG
-extern void watchdog_reload(void);
-#else
-static inline void watchdog_reload(void) { }
-#endif
-
void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len)
{
DCRYPTO_bn_wrap(b, buf, len);
@@ -29,8 +21,12 @@ void bn_init(struct LITE_BIGNUM *b, void *buf, size_t len)
void DCRYPTO_bn_wrap(struct LITE_BIGNUM *b, void *buf, size_t len)
{
- /* Only word-multiple sized buffers accepted. */
- assert((len & 0x3) == 0);
+ /* Note: only word-multiple sized buffers accepted. */
+ if (len & 3) {
+ fips_throw_err(FIPS_FATAL_BN_MATH);
+ return;
+ }
+
b->dmax = len / LITE_BN_BYTES;
b->d = (struct access_helper *) buf;
}
@@ -309,8 +305,23 @@ static void bn_compute_RR(struct LITE_BIGNUM *RR, const struct LITE_BIGNUM *N)
/* Repeat 2 * R % N, log2(R) times. */
for (i = 0; i < N->dmax * LITE_BN_BITS2; i++) {
+ /**
+ * assume RR = N - x, where x is positive, less than N,
+ * let n = RR & N bit size (RR created same size as N).
+ *
+ * if RR * 2 overflows it means 2^n > RR >= 2^(n-1),
+ * 2^n > N - x >= 2^(n-1)
+ * ==> N >= 2^(n-1) + x
+ *
+ * 2*RR - 2^n < N because:
+ * ((2^(n-1) + x) - x)*2 - 2^n < 2^(n-1) + x
+ * 0 < 2^(n-1) + x
+ */
if (bn_lshift(RR))
- assert(bn_sub(RR, N) == -1);
+ if (bn_sub(RR, N) != -1)
+ fips_throw_err(FIPS_FATAL_BN_MATH);
+
+ /* RR < N is invariant of the loop */
if (bn_gte(RR, N))
bn_sub(RR, N);
}
@@ -370,7 +381,9 @@ static void bn_modexp_internal(struct LITE_BIGNUM *output,
* TODO(ngm): may be unnecessary with
* a faster implementation.
*/
- watchdog_reload();
+#ifdef CONFIG_WATCHDOG
+ fips_vtable->watchdog_reload();
+#endif
}
bn_mont_mul(output, NULL, &acc, nprime, N); /* Convert out. */
diff --git a/board/cr50/dcrypto/dcrypto_runtime.c b/board/cr50/dcrypto/dcrypto_runtime.c
index 7de990ea41..db0ab292d7 100644
--- a/board/cr50/dcrypto/dcrypto_runtime.c
+++ b/board/cr50/dcrypto/dcrypto_runtime.c
@@ -4,6 +4,7 @@
*/
#include "flash_log.h"
+#include "fips.h"
#include "internal.h"
#include "registers.h"
#include "task.h"
@@ -51,8 +52,8 @@ static void dcrypto_wipe_imem(void)
void dcrypto_init_and_lock(void)
{
- mutex_lock(&dcrypto_mutex);
- my_task_id = task_get_current();
+ fips_vtable->mutex_lock(&dcrypto_mutex);
+ my_task_id = fips_vtable->task_get_current();
if (dcrypto_is_initialized)
return;
@@ -74,14 +75,14 @@ void dcrypto_init_and_lock(void)
GREG32(CRYPTO, INT_STATE) = -1; /* Reset all the status bits. */
GREG32(CRYPTO, INT_ENABLE) = -1; /* Enable all status bits. */
- task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT);
+ fips_vtable->task_enable_irq(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT);
dcrypto_is_initialized = 1;
}
void dcrypto_unlock(void)
{
- mutex_unlock(&dcrypto_mutex);
+ fips_vtable->mutex_unlock(&dcrypto_mutex);
}
#ifndef DCRYPTO_CALL_TIMEOUT_US
@@ -105,7 +106,7 @@ uint32_t dcrypto_call(uint32_t adr)
GREG32(CRYPTO, HOST_CMD) = 0x08000000 + adr; /* Call imem:adr. */
- event = task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE,
+ event = fips_vtable->task_wait_event_mask(TASK_EVENT_DCRYPTO_DONE,
DCRYPTO_CALL_TIMEOUT_US);
/* TODO(ngm): switch return value to an enum. */
switch (event) {
@@ -126,19 +127,22 @@ uint32_t dcrypto_call(uint32_t adr)
dcrypto_reset_and_wipe();
#ifdef CONFIG_FLASH_LOG
/* State value of zero indicates event timeout. */
- flash_log_add_event(FE_LOG_DCRYPTO_FAILURE,
+ fips_vtable->flash_log_add_event(FE_LOG_DCRYPTO_FAILURE,
sizeof(state), &state);
#endif
return 1;
}
}
-
+/**
+ * DECLARE_IRQ() referencing this function moved outside FIPS module
+ * into fips_cmd.c to remove direct references to EC OS functions hard-
+ * coded into macro.
+ */
void __keep dcrypto_done_interrupt(void)
{
GREG32(CRYPTO, INT_STATE) = GC_CRYPTO_INT_STATE_HOST_CMD_DONE_MASK;
- task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0);
+ fips_vtable->task_set_event(my_task_id, TASK_EVENT_DCRYPTO_DONE, 0);
}
-DECLARE_IRQ(GC_IRQNUM_CRYPTO0_HOST_CMD_DONE_INT, dcrypto_done_interrupt, 1);
void dcrypto_imem_load(size_t offset, const uint32_t *opcodes,
size_t n_opcodes)
diff --git a/board/cr50/dcrypto/sha_hw.c b/board/cr50/dcrypto/sha_hw.c
index acad1ba29d..82f5c6dacf 100644
--- a/board/cr50/dcrypto/sha_hw.c
+++ b/board/cr50/dcrypto/sha_hw.c
@@ -3,6 +3,7 @@
* found in the LICENSE file.
*/
#include "dcrypto.h"
+#include "fips.h"
#include "internal.h"
#include "registers.h"
@@ -27,21 +28,21 @@ int dcrypto_grab_sha_hw(void)
{
int rv = 0;
- mutex_lock(&hw_busy_mutex);
+ fips_vtable->mutex_lock(&hw_busy_mutex);
if (!hw_busy) {
rv = 1;
hw_busy = true;
}
- mutex_unlock(&hw_busy_mutex);
+ fips_vtable->mutex_unlock(&hw_busy_mutex);
return rv;
}
void dcrypto_release_sha_hw(void)
{
- mutex_lock(&hw_busy_mutex);
+ fips_vtable->mutex_lock(&hw_busy_mutex);
hw_busy = false;
- mutex_unlock(&hw_busy_mutex);
+ fips_vtable->mutex_unlock(&hw_busy_mutex);
}
#endif /* ! SECTION_IS_RO */
diff --git a/board/cr50/dcrypto/trng.c b/board/cr50/dcrypto/trng.c
index 6045243615..03a9f756c2 100644
--- a/board/cr50/dcrypto/trng.c
+++ b/board/cr50/dcrypto/trng.c
@@ -47,16 +47,16 @@
void fips_init_trng(void)
{
-#if (!(defined(CONFIG_CUSTOMIZED_RO) && defined(SECTION_IS_RO)))
/*
* Most of the trng initialization requires high permissions. If RO has
* dropped the permission level, dont try to read or write these high
* permission registers because it will cause rolling reboots. RO
* should do the TRNG initialization before dropping the level.
+ *
+ * For Cr50 RO doesn't drop permission level and init_trng() is called
+ * by board_init() before dropping permissions.
*/
- if (!runlevel_is_high())
- return;
-#endif
+
/**
* According to NIST SP 800-90B only vetted conditioning mechanism
* should be used for post-processing raw entropy.
@@ -127,7 +127,10 @@ uint64_t read_rand(void)
empty_count > TRNG_EMPTY_COUNT) {
/* TRNG timed out, restart */
GWRITE(TRNG, STOP_WORK, 1);
- flash_log_add_event(FE_LOG_TRNG_STALL, 0, NULL);
+#ifdef CONFIG_FLASH_LOG
+ fips_vtable->flash_log_add_event(FE_LOG_TRNG_STALL, 0,
+ NULL);
+#endif
GWRITE(TRNG, GO_EVENT, 1);
empty_count = 0;
reset_count++;