From c18ee628a502b5694caade7482be85d0e7cc0284 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 30 Jun 2026 21:05:50 +0900 Subject: [PATCH] resolved: migrate ECDSA verification to OpenSSL 3 EVP API OpenSSL 3.0 deprecated low-level Elliptic Curve (EC) key manipulation functions (EC_KEY, EC_POINT, EC_GROUP) and direct signature verification functions like ECDSA_do_verify(). This commit modernizes dnssec_ecdsa_verify_raw() by transitioning to the provider-aware EVP API: * Uses OSSL_PARAM arrays and EVP_PKEY_fromdata() to construct the EC public key directly from the raw octet string and curve name, avoiding deprecated EC_POINT parsing. * Converts the raw R and S signature components into a DER-encoded ASN.1 signature using i2d_ECDSA_SIG(), as required by the modern EVP API. * Uses EVP_PKEY_verify() for the actual signature validation. Additionally, this drops an outdated TODO comment waiting for raw ECDSA support in the EVP API, as well as the deprecated warning suppression macros and fallback code blocks. Unit tests for ECDSA are now run unconditionally. --- src/resolve/resolved-dns-dnssec.c | 70 ++++++++++++++++--------------- src/resolve/test-dnssec-crypto.c | 4 -- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index b2e04b3928..67cf991e70 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -212,8 +212,6 @@ int dnssec_ecdsa_verify_raw( const struct iovec *hash, const struct iovec *key) { -#if !defined(OPENSSL_NO_DEPRECATED_3_0) - DISABLE_WARNING_DEPRECATED_DECLARATIONS; int r; assert(hash_algorithm); @@ -222,33 +220,26 @@ int dnssec_ecdsa_verify_raw( assert(iovec_is_set(hash)); assert(iovec_is_set(key)); - _cleanup_(EC_GROUP_freep) EC_GROUP *ec_group = sym_EC_GROUP_new_by_curve_name(curve); - if (!ec_group) + const char *curve_name = sym_OBJ_nid2sn(curve); + if (!curve_name) + return log_openssl_errors(LOG_DEBUG, "Unknown curve NID"); + + OSSL_PARAM params[] = { + sym_OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, (char*) curve_name, 0), + sym_OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, key->iov_base, key->iov_len), + sym_OSSL_PARAM_construct_end(), + }; + + _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *kctx = sym_EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (!kctx) return -ENOMEM; - _cleanup_(EC_POINT_freep) EC_POINT *p = sym_EC_POINT_new(ec_group); - if (!p) - return -ENOMEM; + if (sym_EVP_PKEY_fromdata_init(kctx) <= 0) + return log_openssl_errors(LOG_DEBUG, "Failed to initialize EC key creation"); - _cleanup_(BN_CTX_freep) BN_CTX *bctx = sym_BN_CTX_new(); - if (!bctx) - return -ENOMEM; - - if (sym_EC_POINT_oct2point(ec_group, p, key->iov_base, key->iov_len, bctx) <= 0) - return log_openssl_errors(LOG_DEBUG, "Failed to parse EC public key point"); - - _cleanup_(EC_KEY_freep) EC_KEY *eckey = sym_EC_KEY_new(); - if (!eckey) - return -ENOMEM; - - if (sym_EC_KEY_set_group(eckey, ec_group) <= 0) - return log_openssl_errors(LOG_DEBUG, "Failed to set EC group"); - - if (sym_EC_KEY_set_public_key(eckey, p) <= 0) - return log_openssl_errors(LOG_DEBUG, "EC_KEY_set_public_key failed"); - - if (sym_EC_KEY_check_key(eckey) <= 0) - return log_openssl_errors(LOG_DEBUG, "EC_KEY_check_key failed"); + _cleanup_(EVP_PKEY_freep) EVP_PKEY *epubkey = NULL; + if (sym_EVP_PKEY_fromdata(kctx, &epubkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) + return log_openssl_errors(LOG_DEBUG, "Failed to load EC public key from raw data"); _cleanup_(BN_freep) BIGNUM *bn_r = sym_BN_bin2bn(signature_r->iov_base, signature_r->iov_len, NULL); if (!bn_r) @@ -258,8 +249,6 @@ int dnssec_ecdsa_verify_raw( if (!bn_s) return log_openssl_errors(LOG_DEBUG, "Failed to convert ECDSA signature s to BIGNUM"); - /* TODO: We should eventually use the EVP API once it supports ECDSA signature verification */ - _cleanup_(ECDSA_SIG_freep) ECDSA_SIG *sig = sym_ECDSA_SIG_new(); if (!sig) return -ENOMEM; @@ -269,15 +258,30 @@ int dnssec_ecdsa_verify_raw( TAKE_PTR(bn_r); TAKE_PTR(bn_s); - r = sym_ECDSA_do_verify(hash->iov_base, hash->iov_len, sig, eckey); + _cleanup_(OPENSSL_freep) void *buf = NULL; + r = sym_i2d_ECDSA_SIG(sig, (unsigned char**) &buf); + if (r <= 0) + return log_openssl_errors(LOG_DEBUG, "Failed to DER encode ECDSA signature"); + struct iovec der_sig = IOVEC_MAKE(buf, r); + + _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *vctx = sym_EVP_PKEY_CTX_new(epubkey, NULL); + if (!vctx) + return -ENOMEM; + + if (sym_EVP_PKEY_public_check(vctx) <= 0) + return log_openssl_errors(LOG_DEBUG, "EC public key validation failed"); + + if (sym_EVP_PKEY_verify_init(vctx) <= 0) + return log_openssl_errors(LOG_DEBUG, "Failed to initialize ECDSA signature verification"); + + if (sym_EVP_PKEY_CTX_set_signature_md(vctx, hash_algorithm) <= 0) + return log_openssl_errors(LOG_DEBUG, "Failed to set ECDSA signature digest"); + + r = sym_EVP_PKEY_verify(vctx, der_sig.iov_base, der_sig.iov_len, hash->iov_base, hash->iov_len); if (r < 0) return log_openssl_errors(LOG_DEBUG, "Signature verification failed"); - REENABLE_WARNING; return r; -#else - return -EOPNOTSUPP; -#endif } static int dnssec_ecdsa_verify( diff --git a/src/resolve/test-dnssec-crypto.c b/src/resolve/test-dnssec-crypto.c index 47dff4af69..82a91a6386 100644 --- a/src/resolve/test-dnssec-crypto.c +++ b/src/resolve/test-dnssec-crypto.c @@ -342,7 +342,6 @@ TEST(generate_ecdsa_test_vectors) { -expected); TEST(dnssec_ecdsa_verify_raw) { -#if !defined(OPENSSL_NO_DEPRECATED_3_0) uint8_t *p; /* Normal verification */ @@ -391,9 +390,6 @@ TEST(dnssec_ecdsa_verify_raw) { p[bad_key.iov_len - 1] ^= 0x01; bad_key.iov_len -= 1; TEST_ECDSA_VERIFY(test_ecdsa_r, test_ecdsa_s, test_digest, bad_key, -ENOTRECOVERABLE); -#else - TEST_ECDSA_VERIFY(test_ecdsa_r, test_ecdsa_s, test_digest, test_ecdsa_key, -EOPNOTSUPP); -#endif } static int intro(void) {