]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor the OpenSSL ECDSA usage to use newer APIs
authorAram Sargsyan <aram@isc.org>
Mon, 20 Sep 2021 15:15:14 +0000 (15:15 +0000)
committerAram Sargsyan <aram@isc.org>
Thu, 28 Oct 2021 07:38:56 +0000 (07:38 +0000)
OpenSSL 3 deprecates most of the EC* family and associated APIs.

Reimplement the existing functionality using a newer set of APIs
which will be used when compiling/linking with OpenSSL 3.0.0 or newer
versions.

lib/dns/opensslecdsa_link.c

index 29f17c1d74c1a067d7f7b73c50480a0319a98b4d..bb47db5ab5227057a545326863f60b22966a672a 100644 (file)
 #include <stdbool.h>
 
 #include <openssl/bn.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#endif
 #include <openssl/ecdsa.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
 #include <openssl/objects.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/param_build.h>
+#endif
 #if !defined(OPENSSL_NO_ENGINE)
 #include <openssl/engine.h>
 #endif
                goto err; \
        }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static isc_result_t
+raw_key_to_ossl(unsigned int key_alg, int private, const unsigned char *key,
+               size_t *key_len, EVP_PKEY **pkey) {
+       isc_result_t ret;
+       int status;
+       const char *groupname;
+       OSSL_PARAM_BLD *bld = NULL;
+       OSSL_PARAM *params = NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       BIGNUM *priv = NULL;
+       size_t len = 0;
+       unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
+
+       if (key_alg == DST_ALG_ECDSA256) {
+               groupname = "P-256";
+               len = private ? DNS_KEY_ECDSA256SIZE / 2 : DNS_KEY_ECDSA256SIZE;
+       } else if (key_alg == DST_ALG_ECDSA384) {
+               groupname = "P-384";
+               len = private ? DNS_KEY_ECDSA384SIZE / 2 : DNS_KEY_ECDSA384SIZE;
+       } else {
+               DST_RET(ISC_R_NOTIMPLEMENTED);
+       }
+
+       ret = (private ? DST_R_INVALIDPRIVATEKEY : DST_R_INVALIDPUBLICKEY);
+       if (*key_len < len) {
+               DST_RET(ret);
+       }
+
+       bld = OSSL_PARAM_BLD_new();
+       if (bld == NULL) {
+               DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_new",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = OSSL_PARAM_BLD_push_utf8_string(
+               bld, OSSL_PKEY_PARAM_GROUP_NAME, groupname, 0);
+       if (status != 1) {
+               DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_"
+                                              "utf8_string",
+                                              DST_R_OPENSSLFAILURE));
+       }
+
+       if (private) {
+               priv = BN_bin2bn(key, len, NULL);
+               if (priv == NULL) {
+                       DST_RET(dst__openssl_toresult2("BN_bin2bn",
+                                                      DST_R_OPENSSLFAILURE));
+               }
+
+               status = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+                                               priv);
+               if (status != 1) {
+                       DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN",
+                                                      DST_R_OPENSSLFAILURE));
+               }
+       } else {
+               buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+               memmove(buf + 1, key, len);
+
+               status = OSSL_PARAM_BLD_push_octet_string(
+                       bld, OSSL_PKEY_PARAM_PUB_KEY, buf, 1 + len);
+               if (status != 1) {
+                       DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_"
+                                                      "octet_string",
+                                                      DST_R_OPENSSLFAILURE));
+               }
+       }
+
+       params = OSSL_PARAM_BLD_to_param(bld);
+       if (params == NULL) {
+               DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+       if (ctx == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_fromdata_init(ctx);
+       if (status != 1) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata_init",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_fromdata(
+               ctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY,
+               params);
+       if (status != 1 || *pkey == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata",
+                                              DST_R_OPENSSLFAILURE));
+       }
+
+       *key_len = len;
+       ret = ISC_R_SUCCESS;
+
+err:
+       if (params != NULL) {
+               OSSL_PARAM_free(params);
+       }
+       if (bld != NULL) {
+               OSSL_PARAM_BLD_free(bld);
+       }
+       if (ctx != NULL) {
+               EVP_PKEY_CTX_free(ctx);
+       }
+       if (priv != NULL) {
+               BN_clear_free(priv);
+       }
+
+       return (ret);
+}
+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
+
 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;
        const EVP_MD *type = NULL;
 
        UNUSED(key);
        REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
                dctx->key->key_alg == DST_ALG_ECDSA384);
+       REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
 
        evp_md_ctx = EVP_MD_CTX_create();
        if (evp_md_ctx == NULL) {
-               return (ISC_R_NOMEMORY);
+               DST_RET(ISC_R_NOMEMORY);
        }
        if (dctx->key->key_alg == DST_ALG_ECDSA256) {
                type = EVP_sha256();
@@ -66,15 +188,30 @@ opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
                type = EVP_sha384();
        }
 
-       if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
-               EVP_MD_CTX_destroy(evp_md_ctx);
-               return (dst__openssl_toresult3(
-                       dctx->category, "EVP_DigestInit_ex", ISC_R_FAILURE));
+       if (dctx->use == DO_SIGN) {
+               if (EVP_DigestSignInit(evp_md_ctx, NULL, type, NULL,
+                                      dctx->key->keydata.pkey) != 1)
+               {
+                       EVP_MD_CTX_destroy(evp_md_ctx);
+                       DST_RET(dst__openssl_toresult3(dctx->category,
+                                                      "EVP_DigestSignInit",
+                                                      ISC_R_FAILURE));
+               }
+       } else {
+               if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL,
+                                        dctx->key->keydata.pkey) != 1)
+               {
+                       EVP_MD_CTX_destroy(evp_md_ctx);
+                       DST_RET(dst__openssl_toresult3(dctx->category,
+                                                      "EVP_DigestVerifyInit",
+                                                      ISC_R_FAILURE));
+               }
        }
 
        dctx->ctxdata.evp_md_ctx = evp_md_ctx;
 
-       return (ISC_R_SUCCESS);
+err:
+       return (ret);
 }
 
 static void
@@ -83,6 +220,7 @@ opensslecdsa_destroyctx(dst_context_t *dctx) {
 
        REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
                dctx->key->key_alg == DST_ALG_ECDSA384);
+       REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
 
        if (evp_md_ctx != NULL) {
                EVP_MD_CTX_destroy(evp_md_ctx);
@@ -92,17 +230,31 @@ opensslecdsa_destroyctx(dst_context_t *dctx) {
 
 static isc_result_t
 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
+       isc_result_t ret = ISC_R_SUCCESS;
        EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
 
        REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
                dctx->key->key_alg == DST_ALG_ECDSA384);
-
-       if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) {
-               return (dst__openssl_toresult3(
-                       dctx->category, "EVP_DigestUpdate", ISC_R_FAILURE));
+       REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY);
+
+       if (dctx->use == DO_SIGN) {
+               if (EVP_DigestSignUpdate(evp_md_ctx, data->base,
+                                        data->length) != 1) {
+                       DST_RET(dst__openssl_toresult3(dctx->category,
+                                                      "EVP_DigestSignUpdate",
+                                                      ISC_R_FAILURE));
+               }
+       } else {
+               if (EVP_DigestVerifyUpdate(evp_md_ctx, data->base,
+                                          data->length) != 1) {
+                       DST_RET(dst__openssl_toresult3(dctx->category,
+                                                      "EVP_DigestVerifyUpdate",
+                                                      ISC_R_FAILURE));
+               }
        }
 
-       return (ISC_R_SUCCESS);
+err:
+       return (ret);
 }
 
 static int
@@ -121,20 +273,16 @@ opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
        isc_result_t ret;
        dst_key_t *key = dctx->key;
        isc_region_t region;
-       ECDSA_SIG *ecdsasig;
        EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
-       EVP_PKEY *pkey = key->keydata.pkey;
-       EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
-       unsigned int dgstlen, siglen;
-       unsigned char digest[EVP_MAX_MD_SIZE];
+       ECDSA_SIG *ecdsasig = NULL;
+       size_t siglen, sigder_len = 0, sigder_alloced = 0;
+       unsigned char *sigder = NULL;
+       const unsigned char *sigder_copy;
        const BIGNUM *r, *s;
 
        REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
                key->key_alg == DST_ALG_ECDSA384);
-
-       if (eckey == NULL) {
-               return (ISC_R_FAILURE);
-       }
+       REQUIRE(dctx->use == DO_SIGN);
 
        if (key->key_alg == DST_ALG_ECDSA256) {
                siglen = DNS_SIG_ECDSA256SIZE;
@@ -147,16 +295,25 @@ opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
                DST_RET(ISC_R_NOSPACE);
        }
 
-       if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen)) {
+       if (EVP_DigestSignFinal(evp_md_ctx, NULL, &sigder_len) != 1) {
                DST_RET(dst__openssl_toresult3(
-                       dctx->category, "EVP_DigestFinal_ex", ISC_R_FAILURE));
+                       dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
        }
-
-       ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
-       if (ecdsasig == NULL) {
-               DST_RET(dst__openssl_toresult3(dctx->category, "ECDSA_do_sign",
-                                              DST_R_SIGNFAILURE));
+       if (sigder_len == 0) {
+               DST_RET(ISC_R_FAILURE);
+       }
+       sigder = isc_mem_get(dctx->mctx, sigder_len);
+       sigder_alloced = sigder_len;
+       if (EVP_DigestSignFinal(evp_md_ctx, sigder, &sigder_len) != 1) {
+               DST_RET(dst__openssl_toresult3(
+                       dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE));
+       }
+       sigder_copy = sigder;
+       if (d2i_ECDSA_SIG(&ecdsasig, &sigder_copy, sigder_len) == NULL) {
+               DST_RET(dst__openssl_toresult3(dctx->category, "d2i_ECDSA_SIG",
+                                              ISC_R_FAILURE));
        }
+
        ECDSA_SIG_get0(ecdsasig, &r, &s);
        BN_bn2bin_fixed(r, region.base, siglen / 2);
        isc_region_consume(&region, siglen / 2);
@@ -167,7 +324,10 @@ opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
        ret = ISC_R_SUCCESS;
 
 err:
-       EC_KEY_free(eckey);
+       if (sigder != NULL && sigder_alloced != 0) {
+               isc_mem_put(dctx->mctx, sigder, sigder_alloced);
+       }
+
        return (ret);
 }
 
@@ -179,18 +339,14 @@ opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
        unsigned char *cp = sig->base;
        ECDSA_SIG *ecdsasig = NULL;
        EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
-       EVP_PKEY *pkey = key->keydata.pkey;
-       EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
-       unsigned int dgstlen, siglen;
-       unsigned char digest[EVP_MAX_MD_SIZE];
+       size_t siglen, sigder_len = 0, sigder_alloced = 0;
+       unsigned char *sigder = NULL;
+       unsigned char *sigder_copy;
        BIGNUM *r = NULL, *s = NULL;
 
        REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
                key->key_alg == DST_ALG_ECDSA384);
-
-       if (eckey == NULL) {
-               return (ISC_R_FAILURE);
-       }
+       REQUIRE(dctx->use == DO_VERIFY);
 
        if (key->key_alg == DST_ALG_ECDSA256) {
                siglen = DNS_SIG_ECDSA256SIZE;
@@ -199,12 +355,7 @@ opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
        }
 
        if (sig->length != siglen) {
-               return (DST_R_VERIFYFAILURE);
-       }
-
-       if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen)) {
-               DST_RET(dst__openssl_toresult3(
-                       dctx->category, "EVP_DigestFinal_ex", ISC_R_FAILURE));
+               DST_RET(DST_R_VERIFYFAILURE);
        }
 
        ecdsasig = ECDSA_SIG_new();
@@ -214,10 +365,28 @@ opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
        r = BN_bin2bn(cp, siglen / 2, NULL);
        cp += siglen / 2;
        s = BN_bin2bn(cp, siglen / 2, NULL);
-       ECDSA_SIG_set0(ecdsasig, r, s);
        /* cp += siglen / 2; */
+       ECDSA_SIG_set0(ecdsasig, r, s);
+
+       status = i2d_ECDSA_SIG(ecdsasig, NULL);
+       if (status < 0) {
+               DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
+                                              DST_R_VERIFYFAILURE));
+       }
+
+       sigder_len = (size_t)status;
+       sigder = isc_mem_get(dctx->mctx, sigder_len);
+       sigder_alloced = sigder_len;
+
+       sigder_copy = sigder;
+       status = i2d_ECDSA_SIG(ecdsasig, &sigder_copy);
+       if (status < 0) {
+               DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG",
+                                              DST_R_VERIFYFAILURE));
+       }
+
+       status = EVP_DigestVerifyFinal(evp_md_ctx, sigder, sigder_len);
 
-       status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
        switch (status) {
        case 1:
                ret = ISC_R_SUCCESS;
@@ -226,7 +395,8 @@ opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
                ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
                break;
        default:
-               ret = dst__openssl_toresult3(dctx->category, "ECDSA_do_verify",
+               ret = dst__openssl_toresult3(dctx->category,
+                                            "EVP_DigestVerifyFinal",
                                             DST_R_VERIFYFAILURE);
                break;
        }
@@ -235,19 +405,27 @@ err:
        if (ecdsasig != NULL) {
                ECDSA_SIG_free(ecdsasig);
        }
-       EC_KEY_free(eckey);
+       if (sigder != NULL && sigder_alloced != 0) {
+               isc_mem_put(dctx->mctx, sigder, sigder_alloced);
+       }
+
        return (ret);
 }
 
 static bool
 opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
        bool ret;
-       int status;
        EVP_PKEY *pkey1 = key1->keydata.pkey;
        EVP_PKEY *pkey2 = key2->keydata.pkey;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey1 = NULL;
        EC_KEY *eckey2 = NULL;
-       const BIGNUM *priv1, *priv2;
+       const BIGNUM *priv1;
+       const BIGNUM *priv2;
+#else
+       BIGNUM *priv1 = NULL;
+       BIGNUM *priv2 = NULL;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        if (pkey1 == NULL && pkey2 == NULL) {
                return (true);
@@ -255,6 +433,12 @@ opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
                return (false);
        }
 
+       /* `EVP_PKEY_eq` checks only the public key components and paramters. */
+       if (EVP_PKEY_eq(pkey1, pkey2) != 1) {
+               DST_RET(false);
+       }
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
        eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
        if (eckey1 == NULL && eckey2 == NULL) {
@@ -262,39 +446,53 @@ opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
        } else if (eckey1 == NULL || eckey2 == NULL) {
                DST_RET(false);
        }
-
-       status = EVP_PKEY_eq(pkey1, pkey2);
-       if (status != 1) {
-               DST_RET(false);
-       }
-
        priv1 = EC_KEY_get0_private_key(eckey1);
        priv2 = EC_KEY_get0_private_key(eckey2);
+#else
+       EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_PRIV_KEY, &priv1);
+       EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_PRIV_KEY, &priv2);
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        if (priv1 != NULL || priv2 != NULL) {
-               if (priv1 == NULL || priv2 == NULL) {
-                       DST_RET(false);
-               }
-               if (BN_cmp(priv1, priv2) != 0) {
+               if (priv1 == NULL || priv2 == NULL || BN_cmp(priv1, priv2) != 0)
+               {
                        DST_RET(false);
                }
        }
+
        ret = true;
 
 err:
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (eckey1 != NULL) {
                EC_KEY_free(eckey1);
        }
        if (eckey2 != NULL) {
                EC_KEY_free(eckey2);
        }
+#else
+       if (priv1 != NULL) {
+               BN_clear_free(priv1);
+       }
+       if (priv2 != NULL) {
+               BN_clear_free(priv2);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        return (ret);
 }
 
 static isc_result_t
 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
        isc_result_t ret;
-       EVP_PKEY *pkey;
+       int status;
+       EVP_PKEY *pkey = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey = NULL;
+#else
+       EVP_PKEY_CTX *ctx = NULL;
+       EVP_PKEY *params_pkey = NULL;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        int group_nid;
 
        REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
@@ -310,13 +508,15 @@ opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
                key->key_size = DNS_KEY_ECDSA384SIZE * 4;
        }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        eckey = EC_KEY_new_by_curve_name(group_nid);
        if (eckey == NULL) {
-               return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
+               DST_RET(dst__openssl_toresult2("EC_KEY_new_by_curve_name",
                                               DST_R_OPENSSLFAILURE));
        }
 
-       if (EC_KEY_generate_key(eckey) != 1) {
+       status = EC_KEY_generate_key(eckey);
+       if (status != 1) {
                DST_RET(dst__openssl_toresult2("EC_KEY_generate_key",
                                               DST_R_OPENSSLFAILURE));
        }
@@ -326,27 +526,109 @@ opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
                DST_RET(ISC_R_NOMEMORY);
        }
        if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
-               EVP_PKEY_free(pkey);
                DST_RET(ISC_R_FAILURE);
        }
+#else
+       /* Generate the key's parameters. */
+       ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+       if (ctx == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_paramgen_init(ctx);
+       if (status != 1) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen_init",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid);
+       if (status != 1) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_"
+                                              "curve_nid",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_paramgen(ctx, &params_pkey);
+       if (status != 1 || params_pkey == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       EVP_PKEY_CTX_free(ctx);
+
+       /* Generate the key. */
+       ctx = EVP_PKEY_CTX_new(params_pkey, NULL);
+       if (ctx == NULL) {
+               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, &pkey);
+       if (status != 1 || pkey == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen",
+                                              DST_R_OPENSSLFAILURE));
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        key->keydata.pkey = pkey;
+       pkey = NULL;
        ret = ISC_R_SUCCESS;
 
 err:
-       EC_KEY_free(eckey);
+       if (pkey != NULL) {
+               EVP_PKEY_free(pkey);
+       }
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       if (eckey != NULL) {
+               EC_KEY_free(eckey);
+       }
+#else
+       if (params_pkey != NULL) {
+               EVP_PKEY_free(params_pkey);
+       }
+       if (ctx != NULL) {
+               EVP_PKEY_CTX_free(ctx);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        return (ret);
 }
 
 static bool
 opensslecdsa_isprivate(const dst_key_t *key) {
        bool ret;
-       EVP_PKEY *pkey = key->keydata.pkey;
-       EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
+       EVP_PKEY *pkey;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       EC_KEY *eckey;
+#else
+       BIGNUM *priv = NULL;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+       REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
+               key->key_alg == DST_ALG_ECDSA384);
+
+       pkey = key->keydata.pkey;
+       if (pkey == NULL) {
+               return (false);
+       }
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       eckey = EVP_PKEY_get1_EC_KEY(pkey);
 
        ret = (eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
        if (eckey != NULL) {
                EC_KEY_free(eckey);
        }
+#else
+       ret = (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) ==
+                      1 &&
+              priv != NULL);
+       if (priv != NULL) {
+               BN_clear_free(priv);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        return (ret);
 }
 
@@ -354,81 +636,144 @@ static void
 opensslecdsa_destroy(dst_key_t *key) {
        EVP_PKEY *pkey = key->keydata.pkey;
 
-       EVP_PKEY_free(pkey);
-       key->keydata.pkey = NULL;
+       if (pkey != NULL) {
+               EVP_PKEY_free(pkey);
+               key->keydata.pkey = NULL;
+       }
 }
 
 static isc_result_t
 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
        isc_result_t ret;
        EVP_PKEY *pkey;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey = NULL;
-       isc_region_t r;
        int len;
        unsigned char *cp;
+#else
+       int status;
+       BIGNUM *x = NULL;
+       BIGNUM *y = NULL;
+       size_t keysize = 0;
+       size_t len = 0;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+       isc_region_t r;
        unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
 
        REQUIRE(key->keydata.pkey != NULL);
 
        pkey = key->keydata.pkey;
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        eckey = EVP_PKEY_get1_EC_KEY(pkey);
        if (eckey == NULL) {
-               return (dst__openssl_toresult(ISC_R_FAILURE));
+               DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
        }
        len = i2o_ECPublicKey(eckey, NULL);
+
        /* skip form */
        len--;
+#else
+       if (key->key_alg == DST_ALG_ECDSA256) {
+               keysize = DNS_KEY_ECDSA256SIZE;
+       } else if (key->key_alg == DST_ALG_ECDSA384) {
+               keysize = DNS_KEY_ECDSA384SIZE;
+       } else {
+               DST_RET(ISC_R_NOTIMPLEMENTED);
+       }
+
+       len = keysize;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        isc_buffer_availableregion(data, &r);
        if (r.length < (unsigned int)len) {
                DST_RET(ISC_R_NOSPACE);
        }
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        cp = buf;
        if (!i2o_ECPublicKey(eckey, &cp)) {
                DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
        }
        memmove(r.base, buf + 1, len);
+#else
+       status = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x);
+       if (status != 1 || x == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_get_bn_param",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       status = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y);
+       if (status != 1 || y == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_get_bn_param",
+                                              DST_R_OPENSSLFAILURE));
+       }
+       BN_bn2bin_fixed(x, &buf[0], keysize / 2);
+       BN_bn2bin_fixed(y, &buf[keysize / 2], keysize / 2);
+       memmove(r.base, buf, len);
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        isc_buffer_add(data, len);
        ret = ISC_R_SUCCESS;
 
 err:
-       EC_KEY_free(eckey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       if (eckey != NULL) {
+               EC_KEY_free(eckey);
+       }
+#else
+       if (x != NULL) {
+               BN_clear_free(x);
+       }
+       if (y != NULL) {
+               BN_clear_free(y);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        return (ret);
 }
 
 static isc_result_t
 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
        isc_result_t ret;
-       EVP_PKEY *pkey;
-       EC_KEY *eckey = NULL;
+       EVP_PKEY *pkey = NULL;
        isc_region_t r;
-       int group_nid;
-       unsigned int len;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       EC_KEY *eckey = NULL;
        const unsigned char *cp;
+       unsigned int len;
        unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
+       int group_nid;
+#else
+       size_t len;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
                key->key_alg == DST_ALG_ECDSA384);
 
        if (key->key_alg == DST_ALG_ECDSA256) {
                len = DNS_KEY_ECDSA256SIZE;
-               group_nid = NID_X9_62_prime256v1;
        } else {
                len = DNS_KEY_ECDSA384SIZE;
-               group_nid = NID_secp384r1;
        }
 
        isc_buffer_remainingregion(data, &r);
        if (r.length == 0) {
-               return (ISC_R_SUCCESS);
+               DST_RET(ISC_R_SUCCESS);
        }
        if (r.length < len) {
-               return (DST_R_INVALIDPUBLICKEY);
+               DST_RET(DST_R_INVALIDPUBLICKEY);
+       }
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       if (key->key_alg == DST_ALG_ECDSA256) {
+               group_nid = NID_X9_62_prime256v1;
+       } else {
+               group_nid = NID_secp384r1;
        }
 
        eckey = EC_KEY_new_by_curve_name(group_nid);
        if (eckey == NULL) {
-               return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+               DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
        }
 
        buf[0] = POINT_CONVERSION_UNCOMPRESSED;
@@ -450,6 +795,13 @@ opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
                EVP_PKEY_free(pkey);
                DST_RET(dst__openssl_toresult(ISC_R_FAILURE));
        }
+#else
+       len = r.length;
+       ret = raw_key_to_ossl(key->key_alg, 0, r.base, &len, &pkey);
+       if (ret != ISC_R_SUCCESS) {
+               DST_RET(ret);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        isc_buffer_forward(data, len);
        key->keydata.pkey = pkey;
@@ -457,9 +809,11 @@ opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
        ret = ISC_R_SUCCESS;
 
 err:
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (eckey != NULL) {
                EC_KEY_free(eckey);
        }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        return (ret);
 }
 
@@ -467,31 +821,46 @@ static isc_result_t
 opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
        isc_result_t ret;
        EVP_PKEY *pkey;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey = NULL;
-       const BIGNUM *privkey;
+       const BIGNUM *privkey = NULL;
+#else
+       int status;
+       BIGNUM *privkey = NULL;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        dst_private_t priv;
        unsigned char *buf = NULL;
        unsigned short i;
 
        if (key->keydata.pkey == NULL) {
-               return (DST_R_NULLKEY);
+               DST_RET(DST_R_NULLKEY);
        }
 
        if (key->external) {
                priv.nelements = 0;
-               return (dst__privstruct_writefile(key, &priv, directory));
+               DST_RET(dst__privstruct_writefile(key, &priv, directory));
        }
 
        pkey = key->keydata.pkey;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        eckey = EVP_PKEY_get1_EC_KEY(pkey);
        if (eckey == NULL) {
-               return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_get1_EC_KEY",
+                                              DST_R_OPENSSLFAILURE));
        }
        privkey = EC_KEY_get0_private_key(eckey);
        if (privkey == NULL) {
-               ret = dst__openssl_toresult(DST_R_OPENSSLFAILURE);
-               goto err;
+               DST_RET(dst__openssl_toresult2("EC_KEY_get0_private_key",
+                                              DST_R_OPENSSLFAILURE));
+       }
+#else
+       status = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+                                      &privkey);
+       if (status != 1 || privkey == NULL) {
+               DST_RET(dst__openssl_toresult2("EVP_PKEY_get_bn_param",
+                                              DST_R_OPENSSLFAILURE));
        }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
 
@@ -523,13 +892,23 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
        ret = dst__privstruct_writefile(key, &priv, directory);
 
 err:
-       EC_KEY_free(eckey);
-       if (buf != NULL) {
+       if (buf != NULL && privkey != NULL) {
                isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
        }
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       if (eckey != NULL) {
+               EC_KEY_free(eckey);
+       }
+#else
+       if (privkey != NULL) {
+               BN_clear_free(privkey);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
        return (ret);
 }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static isc_result_t
 ecdsa_check(EC_KEY *eckey, EC_KEY *pubeckey) {
        const EC_POINT *pubkey;
@@ -549,13 +928,158 @@ ecdsa_check(EC_KEY *eckey, EC_KEY *pubeckey) {
        if (EC_KEY_check_key(eckey) == 1) {
                return (ISC_R_SUCCESS);
        }
+
        return (ISC_R_FAILURE);
 }
+#else
+static isc_result_t
+ecdsa_check(EVP_PKEY **pkey, EVP_PKEY *pubpkey) {
+       isc_result_t ret = ISC_R_FAILURE;
+       int status;
+       size_t pkey_len = 0;
+       BIGNUM *x = NULL;
+       BIGNUM *y = NULL;
+       BIGNUM *priv = NULL;
+       char groupname[80];
+       unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
+       size_t keysize;
+       OSSL_PARAM_BLD *bld = NULL;
+       OSSL_PARAM *params = NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       EVP_PKEY *pkey_new = NULL;
+
+       /* Check if `pkey` has a public key. */
+       status = EVP_PKEY_get_octet_string_param(*pkey, OSSL_PKEY_PARAM_PUB_KEY,
+                                                NULL, 0, &pkey_len);
+
+       /* Check if `pubpkey` exists and that we can extract its public key. */
+       if (pubpkey == NULL ||
+           EVP_PKEY_get_bn_param(pubpkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) != 1 ||
+           x == NULL ||
+           EVP_PKEY_get_bn_param(pubpkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) != 1 ||
+           y == NULL)
+       {
+               if (status != 1 || pkey_len == 0) {
+                       /* No public key both in `pkey` and in `pubpkey` */
+                       DST_RET(DST_R_INVALIDPRIVATEKEY);
+               } else {
+                       /*
+                        * `pkey` has a public key, but there is no public key
+                        * in `pubpkey` to check against.
+                        */
+                       DST_RET(ISC_R_SUCCESS);
+               }
+       }
+
+       /*
+        * If `pkey` doesn't have a public key then we will copy it from
+        * `pubpkey`.
+        */
+       if (status != 1 || pkey_len == 0) {
+               /*
+                * We can't (?) add a public key to an existing PKEY, so we
+                * have to create a new PKEY.
+                */
+
+               keysize = (EVP_PKEY_bits(*pkey) + 7) / 8;
+               /*
+                * The "raw" public key is created by combining the "x" and "y"
+                * parts.
+                */
+               keysize *= 2;
+               buf[0] = POINT_CONVERSION_UNCOMPRESSED;
+               BN_bn2bin_fixed(x, &buf[1], keysize / 2);
+               BN_bn2bin_fixed(y, &buf[1 + keysize / 2], keysize / 2);
+
+               groupname[0] = '\0';
+               status = EVP_PKEY_get_utf8_string_param(
+                       *pkey, OSSL_PKEY_PARAM_GROUP_NAME, groupname,
+                       sizeof groupname, NULL);
+               if (status != 1 || strlen(groupname) == 0) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               status = EVP_PKEY_get_bn_param(*pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+                                              &priv);
+               if (status != 1) {
+                       DST_RET(ISC_R_FAILURE);
+               }
 
+               bld = OSSL_PARAM_BLD_new();
+               if (bld == NULL) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               if (OSSL_PARAM_BLD_push_utf8_string(
+                           bld, OSSL_PKEY_PARAM_GROUP_NAME, groupname, 0) != 1)
+               {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               if (OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+                                          priv) != 1) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               if (OSSL_PARAM_BLD_push_octet_string(bld,
+                                                    OSSL_PKEY_PARAM_PUB_KEY,
+                                                    buf, 1 + keysize) != 1)
+               {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               params = OSSL_PARAM_BLD_to_param(bld);
+               if (params == NULL) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+
+               ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+               if (ctx == NULL) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               if (EVP_PKEY_fromdata_init(ctx) != 1) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+               status = EVP_PKEY_fromdata(ctx, &pkey_new, EVP_PKEY_KEYPAIR,
+                                          params);
+               if (status != 1 || pkey_new == NULL) {
+                       DST_RET(ISC_R_FAILURE);
+               }
+
+               /* Replace the old key with the new one. */
+               EVP_PKEY_free(*pkey);
+               *pkey = pkey_new;
+       }
+
+       if (EVP_PKEY_eq(*pkey, pubpkey) == 1) {
+               DST_RET(ISC_R_SUCCESS);
+       }
+
+err:
+       if (ctx != NULL) {
+               EVP_PKEY_CTX_free(ctx);
+       }
+       if (params != NULL) {
+               OSSL_PARAM_free(params);
+       }
+       if (bld != NULL) {
+               OSSL_PARAM_BLD_free(bld);
+       }
+       if (priv != NULL) {
+               BN_clear_free(priv);
+       }
+       if (x != NULL) {
+               BN_clear_free(x);
+       }
+       if (y != NULL) {
+               BN_clear_free(y);
+       }
+
+       return (ret);
+}
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static isc_result_t
-load_privkey_from_privstruct(EC_KEY *eckey, dst_private_t *priv) {
-       BIGNUM *privkey = BN_bin2bn(priv->elements[0].data,
-                                   priv->elements[0].length, NULL);
+load_privkey_from_privstruct(EC_KEY *eckey, dst_private_t *priv,
+                            int privkey_index) {
+       BIGNUM *privkey = BN_bin2bn(priv->elements[privkey_index].data,
+                                   priv->elements[privkey_index].length, NULL);
        isc_result_t result = ISC_R_SUCCESS;
 
        if (privkey == NULL) {
@@ -585,19 +1109,27 @@ eckey_to_pkey(EC_KEY *eckey, EVP_PKEY **pkey) {
        }
        return (ISC_R_SUCCESS);
 }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
 static isc_result_t
-finalize_eckey(dst_key_t *key, EC_KEY *eckey, const char *engine,
-              const char *label) {
+finalize_eckey(dst_key_t *key,
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+              EC_KEY *eckey,
+#endif
+              const char *engine, const char *label) {
        isc_result_t result = ISC_R_SUCCESS;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EVP_PKEY *pkey = NULL;
 
+       REQUIRE(eckey != NULL);
+
        result = eckey_to_pkey(eckey, &pkey);
        if (result != ISC_R_SUCCESS) {
                return (result);
        }
 
        key->keydata.pkey = pkey;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        if (label != NULL) {
                key->label = isc_mem_strdup(key->mctx, label);
@@ -610,14 +1142,16 @@ finalize_eckey(dst_key_t *key, EC_KEY *eckey, const char *engine,
                key->key_size = DNS_KEY_ECDSA384SIZE * 4;
        }
 
-       return (ISC_R_SUCCESS);
+       return (result);
 }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 static isc_result_t
 dst__key_to_eckey(dst_key_t *key, EC_KEY **eckey) {
+       int group_nid;
+
        REQUIRE(eckey != NULL && *eckey == NULL);
 
-       int group_nid;
        switch (key->key_alg) {
        case DST_ALG_ECDSA256:
                group_nid = NID_X9_62_prime256v1;
@@ -629,12 +1163,15 @@ dst__key_to_eckey(dst_key_t *key, EC_KEY **eckey) {
                INSIST(0);
                ISC_UNREACHABLE();
        }
+
        *eckey = EC_KEY_new_by_curve_name(group_nid);
        if (*eckey == NULL) {
                return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
        }
+
        return (ISC_R_SUCCESS);
 }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
 static isc_result_t
 opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
@@ -643,29 +1180,35 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
 static isc_result_t
 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
        dst_private_t priv;
-       isc_result_t result = ISC_R_SUCCESS;
+       isc_result_t ret;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey = NULL;
        EC_KEY *pubeckey = NULL;
+#else
+       size_t len;
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        const char *engine = NULL;
        const char *label = NULL;
        int i, privkey_index = -1;
        bool finalize_key = false;
 
+       REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
+               key->key_alg == DST_ALG_ECDSA384);
+
        /* read private key file */
-       result = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, key->mctx,
-                                      &priv);
-       if (result != ISC_R_SUCCESS) {
-               goto end;
+       ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, key->mctx,
+                                   &priv);
+       if (ret != ISC_R_SUCCESS) {
+               goto err;
        }
 
        if (key->external) {
                if (priv.nelements != 0 || pub == NULL) {
-                       result = DST_R_INVALIDPRIVATEKEY;
-                       goto end;
+                       DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
                }
                key->keydata.pkey = pub->keydata.pkey;
                pub->keydata.pkey = NULL;
-               goto end;
+               DST_RET(ISC_R_SUCCESS);
        }
 
        for (i = 0; i < priv.nelements; i++) {
@@ -685,59 +1228,95 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
        }
 
        if (privkey_index < 0) {
-               result = DST_R_INVALIDPRIVATEKEY;
-               goto end;
+               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
        }
 
        if (label != NULL) {
-               result = opensslecdsa_fromlabel(key, engine, label, NULL);
-               if (result != ISC_R_SUCCESS) {
-                       goto end;
+               ret = opensslecdsa_fromlabel(key, engine, label, NULL);
+               if (ret != ISC_R_SUCCESS) {
+                       goto err;
                }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
                eckey = EVP_PKEY_get1_EC_KEY(key->keydata.pkey);
                if (eckey == NULL) {
-                       result = dst__openssl_toresult(DST_R_OPENSSLFAILURE);
-                       goto end;
+                       DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
                }
-
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        } else {
-               result = dst__key_to_eckey(key, &eckey);
-               if (result != ISC_R_SUCCESS) {
-                       goto end;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+               ret = dst__key_to_eckey(key, &eckey);
+               if (ret != ISC_R_SUCCESS) {
+                       goto err;
+               }
+
+               ret = load_privkey_from_privstruct(eckey, &priv, privkey_index);
+#else
+               if (key->keydata.pkey != NULL) {
+                       EVP_PKEY_free(key->keydata.pkey);
+                       key->keydata.pkey = NULL;
+               }
+
+               if (key->key_alg == DST_ALG_ECDSA256) {
+                       len = DNS_KEY_ECDSA256SIZE / 2;
+               } else {
+                       len = DNS_KEY_ECDSA384SIZE / 2;
                }
 
-               result = load_privkey_from_privstruct(eckey, &priv);
-               if (result != ISC_R_SUCCESS) {
-                       goto end;
+               ret = raw_key_to_ossl(key->key_alg, 1,
+                                     priv.elements[privkey_index].data, &len,
+                                     &key->keydata.pkey);
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+               if (ret != ISC_R_SUCCESS) {
+                       goto err;
                }
 
                finalize_key = true;
        }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (pub != NULL && pub->keydata.pkey != NULL) {
                pubeckey = EVP_PKEY_get1_EC_KEY(pub->keydata.pkey);
        }
 
        if (ecdsa_check(eckey, pubeckey) != ISC_R_SUCCESS) {
-               result = DST_R_INVALIDPRIVATEKEY;
-               goto end;
+               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
        }
 
        if (finalize_key) {
-               result = finalize_eckey(key, eckey, engine, label);
+               ret = finalize_eckey(key, eckey, engine, label);
+       }
+#else
+       if (ecdsa_check(&key->keydata.pkey,
+                       pub == NULL ? NULL : pub->keydata.pkey) !=
+           ISC_R_SUCCESS)
+       {
+               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
        }
 
-end:
+       if (finalize_key) {
+               ret = finalize_eckey(key, engine, label);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+
+err:
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (pubeckey != NULL) {
                EC_KEY_free(pubeckey);
        }
        if (eckey != NULL) {
                EC_KEY_free(eckey);
        }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+       if (ret != ISC_R_SUCCESS) {
+               key->keydata.generic = NULL;
+       }
+
        dst__privstruct_free(&priv, key->mctx);
        isc_safe_memwipe(&priv, sizeof(priv));
-       return (result);
+
+       return (ret);
 }
 
 static isc_result_t
@@ -746,11 +1325,20 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
 #if !defined(OPENSSL_NO_ENGINE)
        isc_result_t ret = ISC_R_SUCCESS;
        ENGINE *e;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        EC_KEY *eckey = NULL;
        EC_KEY *pubeckey = NULL;
+       int group_nid;
+#else
+       size_t len;
+       const char *curve_name, *nist_curve_name;
+       char buf[128]; /* Sufficient for all of the supported curves' names. */
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
        EVP_PKEY *pkey = NULL;
-       EVP_PKEY *pubkey = NULL;
-       int group_nid = 0;
+       EVP_PKEY *pubpkey = NULL;
+
+       REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
+               key->key_alg == DST_ALG_ECDSA384);
 
        UNUSED(pin);
 
@@ -759,25 +1347,37 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
        }
        e = dst__openssl_getengine(engine);
        if (e == NULL) {
-               return (DST_R_NOENGINE);
+               DST_RET(DST_R_NOENGINE);
        }
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (key->key_alg == DST_ALG_ECDSA256) {
                group_nid = NID_X9_62_prime256v1;
        } else {
                group_nid = NID_secp384r1;
        }
+#else
+       /* Get the expected curve names */
+       if (key->key_alg == DST_ALG_ECDSA256) {
+               curve_name = "prime256v1";
+               nist_curve_name = "P-256";
+       } else {
+               curve_name = "secp384r1";
+               nist_curve_name = "P-384";
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        /* Load private key. */
        pkey = ENGINE_load_private_key(e, label, NULL, NULL);
        if (pkey == NULL) {
-               return (dst__openssl_toresult2("ENGINE_load_private_key",
+               DST_RET(dst__openssl_toresult2("ENGINE_load_private_key",
                                               DST_R_OPENSSLFAILURE));
        }
        /* Check base id, group nid */
        if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
                DST_RET(DST_R_INVALIDPRIVATEKEY);
        }
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        eckey = EVP_PKEY_get1_EC_KEY(pkey);
        if (eckey == NULL) {
                DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
@@ -785,28 +1385,63 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
        if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) {
                DST_RET(DST_R_INVALIDPRIVATEKEY);
        }
+#else
+       len = 0;
+       if (EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME,
+                                          buf, sizeof buf, &len) != 1 ||
+           len == 0 || len >= sizeof buf)
+       {
+               DST_RET(DST_R_INVALIDPRIVATEKEY);
+       }
+       if (strncasecmp(buf, curve_name, strlen(curve_name)) != 0 &&
+           strncasecmp(buf, nist_curve_name, strlen(nist_curve_name)) != 0)
+       {
+               DST_RET(DST_R_INVALIDPRIVATEKEY);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        /* Load public key. */
-       pubkey = ENGINE_load_public_key(e, label, NULL, NULL);
-       if (pubkey == NULL) {
+       pubpkey = ENGINE_load_public_key(e, label, NULL, NULL);
+       if (pubpkey == NULL) {
                DST_RET(dst__openssl_toresult2("ENGINE_load_public_key",
                                               DST_R_OPENSSLFAILURE));
        }
        /* Check base id, group nid */
-       if (EVP_PKEY_base_id(pubkey) != EVP_PKEY_EC) {
+       if (EVP_PKEY_base_id(pubpkey) != EVP_PKEY_EC) {
                DST_RET(DST_R_INVALIDPUBLICKEY);
        }
-       pubeckey = EVP_PKEY_get1_EC_KEY(pubkey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+       pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
        if (pubeckey == NULL) {
                DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
        }
        if (EC_GROUP_get_curve_name(EC_KEY_get0_group(pubeckey)) != group_nid) {
                DST_RET(DST_R_INVALIDPUBLICKEY);
        }
+#else
+       len = 0;
+       if (EVP_PKEY_get_utf8_string_param(pubpkey, OSSL_PKEY_PARAM_GROUP_NAME,
+                                          buf, sizeof buf, &len) != 1 ||
+           len == 0 || len >= sizeof buf)
+       {
+               DST_RET(DST_R_INVALIDPUBLICKEY);
+       }
+       if (strncasecmp(buf, curve_name, strlen(curve_name)) != 0 &&
+           strncasecmp(buf, nist_curve_name, strlen(nist_curve_name)) != 0)
+       {
+               DST_RET(DST_R_INVALIDPUBLICKEY);
+       }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (ecdsa_check(eckey, pubeckey) != ISC_R_SUCCESS) {
-               DST_RET(DST_R_INVALIDPRIVATEKEY);
+               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
+       }
+#else
+       if (ecdsa_check(&pkey, pubpkey) != ISC_R_SUCCESS) {
+               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
        }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        key->label = isc_mem_strdup(key->mctx, label);
        key->engine = isc_mem_strdup(key->mctx, engine);
@@ -815,18 +1450,20 @@ opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
        pkey = NULL;
 
 err:
-       if (pubkey != NULL) {
-               EVP_PKEY_free(pubkey);
+       if (pubpkey != NULL) {
+               EVP_PKEY_free(pubpkey);
        }
        if (pkey != NULL) {
                EVP_PKEY_free(pkey);
        }
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
        if (pubeckey != NULL) {
                EC_KEY_free(pubeckey);
        }
        if (eckey != NULL) {
                EC_KEY_free(eckey);
        }
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
        return (ret);
 #else
@@ -835,7 +1472,7 @@ err:
        UNUSED(label);
        UNUSED(pin);
        return (DST_R_NOENGINE);
-#endif
+#endif /* !defined(OPENSSL_NO_ENGINE) */
 }
 
 static dst_func_t opensslecdsa_functions = {