From 596903a6b7a76277b7166e2f15c67b2778a38ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ayd=C4=B1n=20Mercan?= Date: Mon, 8 Jul 2024 14:53:26 +0300 Subject: [PATCH] use deterministic ecdsa for openssl >= 3.2 OpenSSL has added support for deterministic ECDSA (RFC 6979) with version 3.2. Use it by default as derandomization doesn't pose a risk for DNS usecases and is allowed by FIPS 186-5. --- lib/dns/opensslecdsa_link.c | 44 ++++++++++++++++++++++++++-- tests/dns/dst_test.c | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c index 683b96cab4..9baabf6a99 100644 --- a/lib/dns/opensslecdsa_link.c +++ b/lib/dns/opensslecdsa_link.c @@ -56,6 +56,37 @@ goto err; \ } +#if OPENSSL_VERSION_NUMBER >= 0x30200000L +static isc_result_t +opensslecdsa_set_deterministic(EVP_PKEY_CTX *pctx, unsigned int key_alg) { + unsigned int rfc6979 = 1; + const char *md = NULL; + OSSL_PARAM params[3]; + + switch (key_alg) { + case DST_ALG_ECDSA256: + md = "SHA256"; + break; + case DST_ALG_ECDSA384: + md = "SHA384"; + break; + default: + UNREACHABLE(); + } + + params[0] = OSSL_PARAM_construct_utf8_string("digest", UNCONST(md), 0); + params[1] = OSSL_PARAM_construct_uint("nonce-type", &rfc6979); + params[2] = OSSL_PARAM_construct_end(); + + if (EVP_PKEY_CTX_set_params(pctx, params) != 1) { + return dst__openssl_toresult2("EVP_PKEY_CTX_set_params", + DST_R_OPENSSLFAILURE); + } + + return ISC_R_SUCCESS; +} +#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ + static bool opensslecdsa_valid_key_alg(unsigned int key_alg) { switch (key_alg) { @@ -510,12 +541,12 @@ opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new", DST_R_OPENSSLFAILURE)); } + status = EVP_PKEY_keygen_init(ctx); if (status != 1) { DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", DST_R_OPENSSLFAILURE)); } - status = EVP_PKEY_keygen(ctx, retkey); if (status != 1) { DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen", @@ -647,6 +678,7 @@ static isc_result_t opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { isc_result_t ret = ISC_R_SUCCESS; EVP_MD_CTX *evp_md_ctx; + EVP_PKEY_CTX *pctx = NULL; const EVP_MD *type = NULL; UNUSED(key); @@ -664,7 +696,7 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { } if (dctx->use == DO_SIGN) { - if (EVP_DigestSignInit(evp_md_ctx, NULL, type, NULL, + if (EVP_DigestSignInit(evp_md_ctx, &pctx, type, NULL, dctx->key->keydata.pkeypair.priv) != 1) { EVP_MD_CTX_destroy(evp_md_ctx); @@ -672,6 +704,14 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { "EVP_DigestSignInit", ISC_R_FAILURE)); } + +#if OPENSSL_VERSION_NUMBER >= 0x30200000L + ret = opensslecdsa_set_deterministic(pctx, dctx->key->key_alg); + if (ret != ISC_R_SUCCESS) { + goto err; + } +#endif /* OPENSSL_VERSION_NUMBER >= 0x30200000L */ + } else { if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL, dctx->key->keydata.pkeypair.pub) != 1) diff --git a/tests/dns/dst_test.c b/tests/dns/dst_test.c index 7713195660..3c3f72ec35 100644 --- a/tests/dns/dst_test.c +++ b/tests/dns/dst_test.c @@ -421,9 +421,67 @@ ISC_RUN_TEST_IMPL(cmp_test) { } } +ISC_RUN_TEST_IMPL(ecdsa_determinism_test) { + isc_result_t result; + isc_buffer_t *sigbuf1 = NULL, *sigbuf2 = NULL; + isc_buffer_t databuf, keybuf; + isc_region_t datareg; + dns_fixedname_t fname; + dns_name_t *name = NULL; + dst_key_t *key = NULL; + dst_context_t *ctx = NULL; + unsigned int siglen; + + const char *data = "these are some bytes to sign"; + + isc_buffer_constinit(&databuf, data, strlen(data)); + isc_buffer_add(&databuf, strlen(data)); + isc_buffer_region(&databuf, &datareg); + + name = dns_fixedname_initname(&fname); + isc_buffer_constinit(&keybuf, "example.", strlen("example.")); + isc_buffer_add(&keybuf, strlen("example.")); + result = dns_name_fromtext(name, &keybuf, dns_rootname, 0, NULL); + assert_int_equal(result, ISC_R_SUCCESS); + result = dst_key_fromfile(name, 19786, DST_ALG_ECDSA256, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + TESTS_DIR "/comparekeys", mctx, &key); + assert_int_equal(result, ISC_R_SUCCESS); + result = dst_key_sigsize(key, &siglen); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_buffer_allocate(mctx, &sigbuf1, siglen); + result = dst_context_create(key, mctx, DNS_LOGCATEGORY_GENERAL, true, 0, + &ctx); + assert_int_equal(result, ISC_R_SUCCESS); + result = dst_context_sign(ctx, sigbuf1); + assert_int_equal(result, ISC_R_SUCCESS); + dst_context_destroy(&ctx); + + isc_buffer_allocate(mctx, &sigbuf2, siglen); + result = dst_context_create(key, mctx, DNS_LOGCATEGORY_GENERAL, true, 0, + &ctx); + assert_int_equal(result, ISC_R_SUCCESS); + result = dst_context_sign(ctx, sigbuf2); + assert_int_equal(result, ISC_R_SUCCESS); + dst_context_destroy(&ctx); + +#if OPENSSL_VERSION_NUMBER >= 0x30200000L + assert_memory_equal(sigbuf1->base, sigbuf2->base, siglen); +#else + assert_memory_not_equal(sigbuf1->base, sigbuf2->base, siglen); +#endif + + isc_buffer_free(&sigbuf1); + isc_buffer_free(&sigbuf2); + + dst_key_free(&key); +} + ISC_TEST_LIST_START ISC_TEST_ENTRY(sig_test) ISC_TEST_ENTRY(cmp_test) +ISC_TEST_ENTRY(ecdsa_determinism_test) ISC_TEST_LIST_END ISC_TEST_MAIN