diff --git a/components/mbedtls/Kconfig b/components/mbedtls/Kconfig index b28b25d1e16..90d67502ea8 100644 --- a/components/mbedtls/Kconfig +++ b/components/mbedtls/Kconfig @@ -1347,8 +1347,10 @@ menu "mbedTLS" Note that deterministic signatures generated by the peripheral use its own deterministic K derivation, which is a variant of RFC 6979. On SECP384R1 they do not match the RFC 6979 signatures of a software implementation, - although both are valid. Disable this option if strict RFC 6979 - deterministic signatures are required on SECP384R1. + although both are valid. For a plaintext key pair, deterministic signing + on SECP384R1 therefore uses the software implementation, which follows + RFC 6979. A key in an eFuse key block or in the Key Manager is always + signed by the peripheral. On a chip without a software key source the private key has to be burnt in an efuse key block with key purpose set to ECDSA_KEY. diff --git a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c index 5fe506ad941..ed4578bac6b 100644 --- a/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c +++ b/components/mbedtls/port/psa_driver/esp_ecdsa/psa_crypto_driver_esp_ecdsa_transparent.c @@ -44,6 +44,21 @@ static const char *TAG = "psa_crypto_driver_esp_ecdsa"; * failing for a given input */ #define ESP_ECDSA_SIGN_MAX_ATTEMPTS 16 +/* The peripheral derives the deterministic nonce with its own variant of + * RFC 6979. The signatures match RFC 6979 on SECP256R1 (checked against the + * RFC 6979 test vectors), but not on SECP384R1. Only SECP256R1 is accepted, so + * that deterministic requests on any other curve fall back to the builtin + * RFC 6979 implementation. */ +static bool esp_ecdsa_transparent_det_sign_supported(esp_ecdsa_curve_t curve) +{ +#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP + return ecdsa_ll_is_deterministic_mode_supported() && curve == ESP_ECDSA_CURVE_SECP256R1; +#else + (void) curve; + return false; +#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */ +} + psa_status_t esp_ecdsa_transparent_sign_hash_start( esp_ecdsa_transparent_sign_hash_operation_t *operation, const psa_key_attributes_t *attributes, @@ -81,22 +96,16 @@ psa_status_t esp_ecdsa_transparent_sign_hash_start( return PSA_ERROR_NOT_SUPPORTED; } - if (PSA_ALG_ECDSA_IS_DETERMINISTIC(alg)) { -#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP - if (!ecdsa_ll_is_deterministic_mode_supported()) { - return PSA_ERROR_NOT_SUPPORTED; - } -#else - return PSA_ERROR_NOT_SUPPORTED; -#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE && SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP */ - } - size_t key_len = PSA_BITS_TO_BYTES(psa_get_key_bits(attributes)); esp_ecdsa_curve_t curve = esp_ecdsa_bits_to_curve(key_len); if (curve == ESP_ECDSA_CURVE_MAX) { return PSA_ERROR_NOT_SUPPORTED; } + if (PSA_ALG_ECDSA_IS_DETERMINISTIC(alg) && !esp_ecdsa_transparent_det_sign_supported(curve)) { + return PSA_ERROR_NOT_SUPPORTED; + } + /* Hash algorithm, eFuse curve and digest length checks shared with the opaque * driver. Every failure falls back to the builtin implementation. */ if (esp_ecdsa_check_sign_request(alg, curve, hash_length) != PSA_SUCCESS) { diff --git a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c index 905d3d9d4a4..2dacf005ac9 100644 --- a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c +++ b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa.c @@ -1134,6 +1134,135 @@ TEST_CASE("mbedtls ECDSA signature generation with software key on SECP384R1", " } #endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ +#if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE +/* RFC 6979 Appendix A.2.5: P-256, SHA-256, message "sample" (big endian) */ +static const uint8_t rfc6979_p256_priv[32] = { + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, + 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, + 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, +}; +static const uint8_t rfc6979_p256_hash[32] = { + 0xaf, 0x2b, 0xdb, 0xe1, 0xaa, 0x9b, 0x6e, 0xc1, + 0xe2, 0xad, 0xe1, 0xd6, 0x94, 0xf4, 0x1f, 0xc7, + 0x1a, 0x83, 0x1d, 0x02, 0x68, 0xe9, 0x89, 0x15, + 0x62, 0x11, 0x3d, 0x8a, 0x62, 0xad, 0xd1, 0xbf, +}; +static const uint8_t rfc6979_p256_r[32] = { + 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, +}; +static const uint8_t rfc6979_p256_s[32] = { + 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, +}; + +/* RFC 6979 Appendix A.2.5: P-256, SHA-256, message "test" (big endian, same key) */ +static const uint8_t rfc6979_p256_test_hash[32] = { + 0x9f, 0x86, 0xd0, 0x81, 0x88, 0x4c, 0x7d, 0x65, + 0x9a, 0x2f, 0xea, 0xa0, 0xc5, 0x5a, 0xd0, 0x15, + 0xa3, 0xbf, 0x4f, 0x1b, 0x2b, 0x0b, 0x82, 0x2c, + 0xd1, 0x5d, 0x6c, 0x15, 0xb0, 0xf0, 0x0a, 0x08, +}; +static const uint8_t rfc6979_p256_test_r[32] = { + 0xf1, 0xab, 0xb0, 0x23, 0x51, 0x83, 0x51, 0xcd, + 0x71, 0xd8, 0x81, 0x56, 0x7b, 0x1e, 0xa6, 0x63, + 0xed, 0x3e, 0xfc, 0xf6, 0xc5, 0x13, 0x2b, 0x35, + 0x4f, 0x28, 0xd3, 0xb0, 0xb7, 0xd3, 0x83, 0x67, +}; +static const uint8_t rfc6979_p256_test_s[32] = { + 0x01, 0x9f, 0x41, 0x13, 0x74, 0x2a, 0x2b, 0x14, + 0xbd, 0x25, 0x92, 0x6b, 0x49, 0xc6, 0x49, 0x15, + 0x5f, 0x26, 0x7e, 0x60, 0xd3, 0x81, 0x4b, 0x4c, + 0x0c, 0xc8, 0x42, 0x50, 0xe4, 0x6f, 0x00, 0x83, +}; + +#if SOC_ECDSA_SUPPORT_CURVE_P384 +/* RFC 6979 Appendix A.2.6: P-384, SHA-384, message "sample" (big endian) */ +static const uint8_t rfc6979_p384_priv[48] = { + 0x6b, 0x9d, 0x3d, 0xad, 0x2e, 0x1b, 0x8c, 0x1c, + 0x05, 0xb1, 0x98, 0x75, 0xb6, 0x65, 0x9f, 0x4d, + 0xe2, 0x3c, 0x3b, 0x66, 0x7b, 0xf2, 0x97, 0xba, + 0x9a, 0xa4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xd8, + 0x96, 0xd5, 0x72, 0x4e, 0x4c, 0x70, 0xa8, 0x25, + 0xf8, 0x72, 0xc9, 0xea, 0x60, 0xd2, 0xed, 0xf5, +}; +static const uint8_t rfc6979_p384_hash[48] = { + 0x9a, 0x90, 0x83, 0x50, 0x5b, 0xc9, 0x22, 0x76, + 0xae, 0xc4, 0xbe, 0x31, 0x26, 0x96, 0xef, 0x7b, + 0xf3, 0xbf, 0x60, 0x3f, 0x4b, 0xbd, 0x38, 0x11, + 0x96, 0xa0, 0x29, 0xf3, 0x40, 0x58, 0x53, 0x12, + 0x31, 0x3b, 0xca, 0x4a, 0x9b, 0x5b, 0x89, 0x0e, + 0xfe, 0xe4, 0x2c, 0x77, 0xb1, 0xee, 0x25, 0xfe, +}; +static const uint8_t rfc6979_p384_r[48] = { + 0x94, 0xed, 0xbb, 0x92, 0xa5, 0xec, 0xb8, 0xaa, + 0xd4, 0x73, 0x6e, 0x56, 0xc6, 0x91, 0x91, 0x6b, + 0x3f, 0x88, 0x14, 0x06, 0x66, 0xce, 0x9f, 0xa7, + 0x3d, 0x64, 0xc4, 0xea, 0x95, 0xad, 0x13, 0x3c, + 0x81, 0xa6, 0x48, 0x15, 0x2e, 0x44, 0xac, 0xf9, + 0x6e, 0x36, 0xdd, 0x1e, 0x80, 0xfa, 0xbe, 0x46, +}; +static const uint8_t rfc6979_p384_s[48] = { + 0x99, 0xef, 0x4a, 0xeb, 0x15, 0xf1, 0x78, 0xce, + 0xa1, 0xfe, 0x40, 0xdb, 0x26, 0x03, 0x13, 0x8f, + 0x13, 0x0e, 0x74, 0x0a, 0x19, 0x62, 0x45, 0x26, + 0x20, 0x3b, 0x63, 0x51, 0xd0, 0xa3, 0xa9, 0x4f, + 0xa3, 0x29, 0xc1, 0x45, 0x78, 0x6e, 0x67, 0x9e, + 0x7b, 0x82, 0xc7, 0x1a, 0x38, 0x62, 0x8a, 0xc8, +}; +#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ + +/* Sign with a deterministic ECDSA software key and compare the signature byte + * for byte with the RFC 6979 value. A valid signature is not enough here: the + * test must fail if any path uses a nonce that is not the RFC 6979 one. */ +static void test_ecdsa_sign_rfc6979_kat(size_t bits, psa_algorithm_t hash_alg, const uint8_t *priv, + const uint8_t *hash, const uint8_t *r, const uint8_t *s) +{ + size_t len = PSA_BITS_TO_BYTES(bits); + uint8_t signature[2 * MAX_ECDSA_COMPONENT_LEN] = {0}; + size_t signature_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t alg = PSA_ALG_DETERMINISTIC_ECDSA(hash_alg); + + psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attr, bits); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); + psa_set_key_algorithm(&attr, alg); + TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, psa_import_key(&attr, priv, len, &key_id)); + psa_reset_key_attributes(&attr); + + psa_status_t status = psa_sign_hash(key_id, alg, hash, PSA_HASH_LENGTH(hash_alg), + signature, sizeof(signature), &signature_len); + psa_destroy_key(key_id); + TEST_ASSERT_EQUAL_HEX32(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(2 * len, signature_len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(r, signature, len); + TEST_ASSERT_EQUAL_HEX8_ARRAY(s, signature + len, len); +} + +TEST_CASE("mbedtls ECDSA deterministic signature with software key matches RFC 6979 on SECP256R1", "[mbedtls][ecdsa_sw_key]") +{ + test_ecdsa_sign_rfc6979_kat(256, PSA_ALG_SHA_256, rfc6979_p256_priv, rfc6979_p256_hash, + rfc6979_p256_r, rfc6979_p256_s); + test_ecdsa_sign_rfc6979_kat(256, PSA_ALG_SHA_256, rfc6979_p256_priv, rfc6979_p256_test_hash, + rfc6979_p256_test_r, rfc6979_p256_test_s); +} + +#if SOC_ECDSA_SUPPORT_CURVE_P384 +TEST_CASE("mbedtls ECDSA deterministic signature with software key matches RFC 6979 on SECP384R1", "[mbedtls][ecdsa_sw_key]") +{ + test_ecdsa_sign_rfc6979_kat(384, PSA_ALG_SHA_384, rfc6979_p384_priv, rfc6979_p384_hash, + rfc6979_p384_r, rfc6979_p384_s); +} +#endif /* SOC_ECDSA_SUPPORT_CURVE_P384 */ +#endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */ + TEST_CASE("mbedtls ECDSA software fallback for combinations unsupported by the peripheral", "[mbedtls][ecdsa_sw_key]") { /* P-256 key with a SHA-384 sized hash is not supported by the transparent diff --git a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa_perf.c b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa_perf.c index 89b6eab3551..787d0012126 100644 --- a/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa_perf.c +++ b/components/mbedtls/test_apps/mbedtls_ut/main/test_psa_ecdsa_perf.c @@ -136,9 +136,8 @@ static void run_ecdsa_perf(size_t bits, bool deterministic) int64_t sw_us = time_sign(&ctx, mbedtls_psa_ecdsa_sign_hash, sw_sig); log_result(deterministic ? "deterministic sign" : "sign", bits, hw_us, sw_us); - /* Deterministic signatures are not compared byte for byte: on P-384 the - * peripheral derives the nonce with a variant of RFC 6979. - * Each implementation must accept the signature of the other one. */ + /* Each implementation must accept the signature of the other one. The + * RFC 6979 known-answer tests check deterministic signatures byte for byte. */ TEST_ASSERT_EQUAL(PSA_SUCCESS, mbedtls_psa_ecdsa_verify_hash(&ctx.pub_attr, ctx.pub, 2 * ctx.len + 1, ctx.alg, ctx.hash, ctx.len, hw_sig, 2 * ctx.len)); @@ -164,7 +163,11 @@ static void run_ecdsa_perf_on_curve(size_t bits) run_ecdsa_perf(bits, false); #if SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE - run_ecdsa_perf(bits, true); + /* The driver signs deterministic requests on P-256 only. On P-384 they + * fall back to the software implementation, so there is nothing to compare. */ + if (bits == 256) { + run_ecdsa_perf(bits, true); + } #endif /* SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE */ }