diff options
-rw-r--r-- | chip/g/dcrypto/dcrypto_p256.c | 49 | ||||
-rw-r--r-- | chip/g/dcrypto/dcrypto_runtime.c | 165 | ||||
-rw-r--r-- | chip/g/dcrypto/internal.h | 8 |
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. * |