From 0b41ae0a302f8305241a64cb04f88a4553ea112f Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Mon, 8 Aug 2022 19:27:12 +0200 Subject: [PATCH] [crypto] allow selecting randomized ECDSA instead of deterministic (#7894) There is no hard dependency in the Thread specification which requires the use of deterministic signatures. On the contrary, looking at the tinycrypt implementation, that one issues randomized ECDSA signatures and seems to be quite happy with that. This change does not change the default behaviour, which is to use deterministic ECDSA when using the default MbedTLS backend. It does however make it possible for platforms which have qualified hardware entropy to select 'plain' ECDSA instead, which gives both a performance and code size improvement on those platforms. --- .../openthread-core-simulation-config.h | 11 +++++++++++ src/core/config/misc.h | 11 +++++++++++ src/core/crypto/ecdsa.cpp | 16 ++++++++++++++++ src/core/crypto/ecdsa_tinycrypt.cpp | 4 ++++ tests/unit/test_ecdsa.cpp | 8 ++++++-- third_party/mbedtls/mbedtls-config.h | 2 ++ 6 files changed, 50 insertions(+), 2 deletions(-) diff --git a/examples/platforms/simulation/openthread-core-simulation-config.h b/examples/platforms/simulation/openthread-core-simulation-config.h index 879f069bf..f17af97a9 100644 --- a/examples/platforms/simulation/openthread-core-simulation-config.h +++ b/examples/platforms/simulation/openthread-core-simulation-config.h @@ -254,4 +254,15 @@ #define OPENTHREAD_CONFIG_SRP_CLIENT_BUFFERS_MAX_SERVICES 20 #endif +/** + * @def OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE + * + * Define to 1 to generate ECDSA signatures determinsitically + * according to RFC 6979 instead of randomly. + * + */ +#ifndef OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE +#define OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE 1 +#endif + #endif // OPENTHREAD_CORE_SIMULATION_CONFIG_H_ diff --git a/src/core/config/misc.h b/src/core/config/misc.h index 3070bb07c..e29bcb50d 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -87,6 +87,17 @@ #define OPENTHREAD_CONFIG_ECDSA_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE + * + * Define to 1 to generate ECDSA signatures determinsitically + * according to RFC 6979 instead of randomly. + * + */ +#ifndef OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE +#define OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE 1 +#endif + /** * @def OPENTHREAD_CONFIG_UPTIME_ENABLE * diff --git a/src/core/crypto/ecdsa.cpp b/src/core/crypto/ecdsa.cpp index b91e4e189..4500d828f 100644 --- a/src/core/crypto/ecdsa.cpp +++ b/src/core/crypto/ecdsa.cpp @@ -142,12 +142,17 @@ Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) cons ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair); VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE #if (MBEDTLS_VERSION_NUMBER >= 0x02130000) ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), Sha256::Hash::kSize, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, nullptr); #else ret = mbedtls_ecdsa_sign_det(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), Sha256::Hash::kSize, MBEDTLS_MD_SHA256); +#endif +#else + ret = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), + Sha256::Hash::kSize, MbedTls::CryptoSecurePrng, nullptr); #endif VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); @@ -244,9 +249,20 @@ Error Sign(uint8_t * aOutput, VerifyOrExit(mbedtls_ecdsa_from_keypair(&ctx, keypair) == 0, error = kErrorFailed); // Sign using ECDSA. +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE +#if (MBEDTLS_VERSION_NUMBER >= 0x02130000) + VerifyOrExit(mbedtls_ecdsa_sign_det_ext(&ctx.MBEDTLS_PRIVATE(grp), &rMpi, &sMpi, &ctx.MBEDTLS_PRIVATE(d), + aInputHash, aInputHashLength, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, + nullptr)); +#else + VerifyOrExit(mbedtls_ecdsa_sign_det(&ctx.MBEDTLS_PRIVATE(grp), &rMpi, &sMpi, &ctx.MBEDTLS_PRIVATE(d), aInputHash, + aInputHashLength, MBEDTLS_MD_SHA256)); +#endif +#else VerifyOrExit(mbedtls_ecdsa_sign(&ctx.MBEDTLS_PRIVATE(grp), &rMpi, &sMpi, &ctx.MBEDTLS_PRIVATE(d), aInputHash, aInputHashLength, MbedTls::CryptoSecurePrng, nullptr) == 0, error = kErrorFailed); +#endif VerifyOrExit(mbedtls_mpi_size(&rMpi) + mbedtls_mpi_size(&sMpi) <= aOutputLength, error = kErrorNoBufs); // Concatenate the two octet sequences in the order R and then S. diff --git a/src/core/crypto/ecdsa_tinycrypt.cpp b/src/core/crypto/ecdsa_tinycrypt.cpp index ea75a2d81..852cb40e7 100644 --- a/src/core/crypto/ecdsa_tinycrypt.cpp +++ b/src/core/crypto/ecdsa_tinycrypt.cpp @@ -37,6 +37,10 @@ #ifdef MBEDTLS_USE_TINYCRYPT +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE +#warning "tinycrypt does not support generating deterministic ECDSA signatures" +#endif + #include #include diff --git a/tests/unit/test_ecdsa.cpp b/tests/unit/test_ecdsa.cpp index 533ebcce4..aad13a748 100644 --- a/tests/unit/test_ecdsa.cpp +++ b/tests/unit/test_ecdsa.cpp @@ -66,12 +66,14 @@ void TestEcdsaVector(void) const uint8_t kMessage[] = {'s', 'a', 'm', 'p', 'l', 'e'}; +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE const uint8_t kExpectedSignature[] = { 0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40, 0xDD, 0x9C, 0xD4, 0x5E, 0x81, 0xD6, 0x9D, 0x2C, 0x87, 0x7B, 0x56, 0xAA, 0xF9, 0x91, 0xC3, 0x4D, 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16, 0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41, 0xD4, 0x36, 0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65, 0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4, 0x06, 0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8, }; +#endif Instance *instance = testInitInstance(); @@ -110,6 +112,7 @@ void TestEcdsaVector(void) SuccessOrQuit(keyPair.Sign(hash, signature)); DumpBuffer("Signature", signature.GetBytes(), sizeof(signature)); +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE printf("\nCheck signature against expected sequence----------------------------------\n"); DumpBuffer("Expected signature", kExpectedSignature, sizeof(kExpectedSignature)); @@ -117,6 +120,7 @@ void TestEcdsaVector(void) VerifyOrQuit(memcmp(signature.GetBytes(), kExpectedSignature, sizeof(kExpectedSignature)) == 0); printf("Signature matches expected sequence.\n"); +#endif printf("\nVerify the signature ------------------------------------------------------\n"); SuccessOrQuit(publicKey.Verify(hash, signature)); @@ -125,7 +129,7 @@ void TestEcdsaVector(void) testFreeInstance(instance); } -void TestEdsaKeyGenerationSignAndVerify(void) +void TestEcdsaKeyGenerationSignAndVerify(void) { Instance *instance = testInitInstance(); @@ -183,7 +187,7 @@ int main(void) { #if OPENTHREAD_CONFIG_ECDSA_ENABLE ot::Crypto::TestEcdsaVector(); - ot::Crypto::TestEdsaKeyGenerationSignAndVerify(); + ot::Crypto::TestEcdsaKeyGenerationSignAndVerify(); printf("All tests passed\n"); #else printf("ECDSA feature is not enabled\n"); diff --git a/third_party/mbedtls/mbedtls-config.h b/third_party/mbedtls/mbedtls-config.h index 997870c21..131aaafea 100644 --- a/third_party/mbedtls/mbedtls-config.h +++ b/third_party/mbedtls/mbedtls-config.h @@ -103,7 +103,9 @@ #define MBEDTLS_BASE64_C #define MBEDTLS_ECDH_C #define MBEDTLS_ECDSA_C +#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE #define MBEDTLS_ECDSA_DETERMINISTIC +#endif #define MBEDTLS_OID_C #define MBEDTLS_PEM_PARSE_C #define MBEDTLS_PK_WRITE_C