]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: migrate ECDSA verification to OpenSSL 3 EVP API
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 30 Jun 2026 12:05:50 +0000 (21:05 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 2 Jul 2026 18:02:56 +0000 (03:02 +0900)
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
src/resolve/test-dnssec-crypto.c

index b2e04b3928b0b3cb1a6de0aa253760baa214a7ca..67cf991e70596d7df14906c8465d64ff34eca3fb 100644 (file)
@@ -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)
-                return -ENOMEM;
-
-        _cleanup_(EC_POINT_freep) EC_POINT *p = sym_EC_POINT_new(ec_group);
-        if (!p)
-                return -ENOMEM;
+        const char *curve_name = sym_OBJ_nid2sn(curve);
+        if (!curve_name)
+                return log_openssl_errors(LOG_DEBUG, "Unknown curve NID");
 
-        _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");
+        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_(EC_KEY_freep) EC_KEY *eckey = sym_EC_KEY_new();
-        if (!eckey)
+        _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *kctx = sym_EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+        if (!kctx)
                 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_EVP_PKEY_fromdata_init(kctx) <= 0)
+                return log_openssl_errors(LOG_DEBUG, "Failed to initialize EC key creation");
 
-        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(
index 47dff4af699fb69b4975a3a85eb0b4e1d50815bb..82a91a6386c269b822e1e2259a08a4e6afebe73c 100644 (file)
@@ -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) {