summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.
*