summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaur Krykpayev <bkrykpayev@google.com>2019-07-04 23:40:19 -0700
committerCommit Bot <commit-bot@chromium.org>2020-07-11 05:33:57 +0000
commitb11f71e7fff01d1edd2492a616a0b391c08e5688 (patch)
treeefc14a8d1aa5b20819053ada8b5980d6b0f4f3cc
parent6863b3943c7eb72199374a2e0eb9fe5721ac2bd0 (diff)
downloadchrome-ec-b11f71e7fff01d1edd2492a616a0b391c08e5688.tar.gz
[DCRYPTO Hardening] Adding the ecdsa test that can be invoked through console.
This test's main goal is to be used against future changes in the dcrypto engine. All it does is comparing signature received from the ecdsa sign function to the golden results. Signed-off-by: mschilder@google.com BUG=b:137659935 TEST=something of a test itself and is run by calling the command through the console connection via host. The test sequence is following: - call the dcrypto_ecdsa_sign function on the known input. - call the dcrypto_ecdsa_verisign on the same input (this function is added in the following CLs in the chain). - compare both results to the golden value. Test passes if both results match to the golden value. To run the test compile the CR50: make -j BOARD=cr50 CRYPTO_TEST=1 in the console run: dcrypto_ecdsa Change-Id: I07437f6a69ba79bdcce8c92976a374733b17d339 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2269337 Reviewed-by: Vadim Sukhomlinov <sukhomlinov@chromium.org> Reviewed-by: Marius Schilder <mschilder@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>
-rw-r--r--chip/g/dcrypto/dcrypto_p256.c49
-rw-r--r--chip/g/dcrypto/dcrypto_runtime.c165
-rw-r--r--chip/g/dcrypto/internal.h8
3 files changed, 212 insertions, 10 deletions
diff --git a/chip/g/dcrypto/dcrypto_p256.c b/chip/g/dcrypto/dcrypto_p256.c
index 64b06dab40..4de8d22f9a 100644
--- a/chip/g/dcrypto/dcrypto_p256.c
+++ b/chip/g/dcrypto/dcrypto_p256.c
@@ -752,6 +752,20 @@ struct DMEM_ecc {
#define DMEM_OFFSET(p) (offsetof(struct DMEM_ecc, p))
#define DMEM_INDEX(p) (DMEM_OFFSET(p) / DMEM_CELL_SIZE)
+/* p256 elliptic curve characteristics */
+static const p256_int SECP256r1_nMin1 = {
+ {
+ 0xfc632551 - 1,
+ 0xf3b9cac2,
+ 0xa7179e84,
+ 0xbce6faad,
+ -1,
+ -1,
+ 0,
+ -1,
+ },
+};
+
/*
* Read-only pointer to read-only DMEM_ecc struct, use cp*w()
* functions for writes.
@@ -825,6 +839,22 @@ static void dcrypto_ecc_init(void)
CP1W(d, 0, 8);
}
+/* Return -1 if a < b */
+static int p256_lt(const p256_int *a, const p256_int *b)
+{
+ p256_sddigit borrow = 0;
+
+ for (int i = 0; i < P256_NDIGITS; ++i) {
+ volatile uint32_t blinder = rand();
+
+ borrow += ((p256_sddigit)P256_DIGIT(a, i) - blinder);
+ borrow -= P256_DIGIT(b, i);
+ borrow += blinder;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int)borrow;
+}
+
int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
const p256_int *message, p256_int *r, p256_int *s)
{
@@ -967,3 +997,22 @@ int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y)
dcrypto_unlock();
return result == 0;
}
+
+int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output)
+{
+ int result = 0;
+
+ /* make sure to return stirred output even if drbg fails */
+ dcrypto_p256_rnd(output);
+
+ do {
+ result = hmac_drbg_generate_p256(drbg, output);
+ } while ((result == 0) && (p256_lt(output, &SECP256r1_nMin1) >= 0));
+ return result;
+}
+
+void dcrypto_p256_rnd(p256_int *output)
+{
+ for (int i = 0; i < 8; ++i)
+ output->a[i] = rand();
+}
diff --git a/chip/g/dcrypto/dcrypto_runtime.c b/chip/g/dcrypto/dcrypto_runtime.c
index b20f561393..394293ab83 100644
--- a/chip/g/dcrypto/dcrypto_runtime.c
+++ b/chip/g/dcrypto/dcrypto_runtime.c
@@ -177,15 +177,14 @@ uint32_t dcrypto_dmem_load(size_t offset, const void *words, size_t n_words)
return diff;
}
-#ifdef DCRYPTO_RUNTIME_TEST
-/*
- * Add console command "dcrypto_test" that runs a couple of engine failure
- * scenarios and checks for adequate handling thereof:
- * - error return code
- * - dmem erasure on error
- * - dmem preservation on success
- */
+#ifdef CRYPTO_TEST_SETUP
+
#include "console.h"
+#include "dcrypto.h"
+#include "trng.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "watchdog.h"
/* AUTO-GENERATED. DO NOT MODIFY. */
/* clang-format off */
@@ -294,6 +293,13 @@ static const uint32_t IMEM_test_hang[] = {
};
/* clang-format on */
+/*
+ * Add console command "dcrypto_test" that runs a couple of engine failure
+ * scenarios and checks for adequate handling thereof:
+ * - error return code
+ * - dmem erasure on error
+ * - dmem preservation on success
+ */
static int command_dcrypto_test(int argc, char *argv[])
{
volatile uint32_t *ptr = GREG32_ADDR(CRYPTO, DMEM_DUMMY);
@@ -330,4 +336,145 @@ static int command_dcrypto_test(int argc, char *argv[])
DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_test, command_dcrypto_test, "",
"dcrypto test");
-#endif /* DCRYPTO_RUNTIME_TEST */
+#define ECDSA_TEST_ITERATIONS 1000
+
+#define ECDSA_TEST_SLEEP_DELAY_IN_US 1000000
+
+static const p256_int r_golden = {
+ .a = { 0xebc04580, 0x996c8634, 0xeaff3cd6, 0x4af33b39, 0xa17da3fb,
+ 0x2c9054f4, 0x3b4dfb95, 0xb3bf339c },
+};
+static const p256_int s_golden = {
+ .a = { 0xac457a6d, 0x8ca854ea, 0xa5877cc1, 0x17bd44f2, 0x77c4c11a,
+ 0xd55d07a0, 0x1efb1274, 0x94afb5c9 },
+};
+
+static int call_on_bigger_stack(uint32_t stack,
+ int (*func)(p256_int *, p256_int *),
+ p256_int *r, p256_int *s)
+{
+ int result = 0;
+
+ /* Move to new stack and call the function */
+ __asm__ volatile("mov r4, sp\n"
+ "mov sp, %[new_stack]\n"
+ "mov r0, %[r]\n"
+ "mov r1, %[s]\n"
+ "blx %[func]\n"
+ "mov sp, r4\n"
+ "mov %[result], r0\n"
+ : [result] "=r"(result) /* output */
+ : [new_stack] "r"(stack), [r] "r"(r), [s] "r"(s),
+ [func] "r"(func) /* input */
+ : "r0", "r1", "r2", "r3", "r4",
+ "lr" /* clobbered registers */
+ );
+
+ return result;
+}
+
+/* Sets up the ecdsa_sign function with proper input conditions to mimic the
+ * ecdsa_verisign execution flow.
+ * in: r - ptr to entropy, s - ptr to message.
+ * out: r,s - generated signature.
+ */
+static int ecdsa_sign_go(p256_int *r, p256_int *s)
+{
+ struct drbg_ctx drbg;
+ p256_int d, tmp;
+ int ret = 0;
+ p256_int message = *s;
+
+ /* drbg init with same entropy */
+ hmac_drbg_init(&drbg, r->a, sizeof(r->a), NULL, 0, NULL, 0);
+
+ /* pick a key */
+ ret = dcrypto_p256_pick(&drbg, &tmp);
+ if (ret) {
+ /* to be consistent with ecdsa_sign error return */
+ ret = 0;
+ goto exit;
+ }
+
+ /* add 1 */
+ p256_add_d(&tmp, 1, &d);
+
+ /* drbg_reseed with entropy and message */
+ hmac_drbg_reseed(&drbg, r->a, sizeof(r->a), s->a, sizeof(s->a), NULL,
+ 0);
+
+ ret = dcrypto_p256_ecdsa_sign(&drbg, &d, &message, r, s);
+
+exit:
+ drbg_exit(&drbg);
+ return ret;
+}
+
+static int command_dcrypto_ecdsa_test(int argc, char *argv[])
+{
+ p256_int entropy, message, r, s;
+ LITE_SHA256_CTX hsh;
+ int result = 0;
+ char *new_stack;
+ const uint32_t new_stack_size = 2 * 1024;
+
+ /* start with some known value for a message */
+ const uint8_t ten = 0x0A;
+
+ for (uint8_t i = 0; i < 8; i++)
+ entropy.a[i] = i;
+
+ DCRYPTO_SHA256_init(&hsh, 0);
+ HASH_update(&hsh, &ten, sizeof(ten));
+ p256_from_bin(HASH_final(&hsh), &message);
+
+ r = entropy;
+ s = message;
+
+ result = shared_mem_acquire(new_stack_size, &new_stack);
+
+ if (result != EC_SUCCESS) {
+ ccprintf("Failed to acquire stack memory: %d\n", result);
+ return result;
+ }
+
+ for (uint32_t i = 0; i < ECDSA_TEST_ITERATIONS; i++) {
+ result = call_on_bigger_stack((uint32_t)new_stack +
+ new_stack_size,
+ ecdsa_sign_go, &r, &s);
+
+ if (!result) {
+ ccprintf("ECDSA TEST fail: %d\n", result);
+ return EC_ERROR_INVAL;
+ }
+
+ watchdog_reload();
+ delay_sleep_by(ECDSA_TEST_SLEEP_DELAY_IN_US);
+ }
+
+ shared_mem_release(new_stack);
+
+ /* compare to the golden r and s values */
+ for (uint8_t i = 0; i < 8; i++) {
+ if (r.a[i] != r_golden.a[i]) {
+ ccprintf("ECDSA TEST r does not match with golden at "
+ "%d: %08x != %08x\n",
+ i, r.a[i], r_golden.a[i]);
+ return EC_ERROR_INVAL;
+ }
+ if (s.a[i] != s_golden.a[i]) {
+ ccprintf("ECDSA TEST s does not match with golden at "
+ "%d: %08x != %08x\n",
+ i, s.a[i], s_golden.a[i]);
+ return EC_ERROR_INVAL;
+ }
+ }
+
+ ccprintf("ECDSA TEST success!!!\n");
+
+ return EC_SUCCESS;
+}
+DECLARE_SAFE_CONSOLE_COMMAND(dcrypto_ecdsa, command_dcrypto_ecdsa_test, "",
+ "dcrypto ecdsa test");
+
+#endif
diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h
index 26bac1c73f..1811426f2a 100644
--- a/chip/g/dcrypto/internal.h
+++ b/chip/g/dcrypto/internal.h
@@ -165,7 +165,7 @@ int dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg, const p256_int *key,
const p256_int *message, p256_int *r, p256_int *s)
__attribute__((warn_unused_result));
int dcrypto_p256_base_point_mul(const p256_int *k, p256_int *x, p256_int *y)
- __attribute__((warn_unused_result));
+ __attribute__((warn_unused_result));
int dcrypto_p256_point_mul(const p256_int *k,
const p256_int *in_x, const p256_int *in_y,
p256_int *x, p256_int *y)
@@ -177,6 +177,12 @@ int dcrypto_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
int dcrypto_p256_is_valid_point(const p256_int *x, const p256_int *y)
__attribute__((warn_unused_result));
+/* Pick a p256 number between 1 < k < |p256| */
+int dcrypto_p256_pick(struct drbg_ctx *drbg, p256_int *output);
+
+/* Overwrite with random p256 value */
+void dcrypto_p256_rnd(p256_int *output);
+
/*
* Accelerator runtime.
*