]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor OpenSSL RSA private key handling
authorTimo Teräs <timo.teras@iki.fi>
Mon, 26 Dec 2022 14:29:56 +0000 (16:29 +0200)
committerOndřej Surý <ondrej@isc.org>
Mon, 9 Jan 2023 14:19:37 +0000 (15:19 +0100)
Instead of trying to enforce one pkey to contain both a private
and a public key pair, refactor the code to have separate public
and private pkeys.

This is a prerequisite for proper openssl 3.0 providers support
and greatly simplifies the code.

lib/dns/dst_internal.h
lib/dns/opensslrsa_link.c

index 9f5e8ee3b60d08e876c36d43664e687369a3d114..13dd6dc75aded154a1d8bbeeb93092989655ed4b 100644 (file)
@@ -98,8 +98,12 @@ struct dst_key {
                void *generic;
                dns_gss_ctx_id_t gssctx;
                DH *dh;
-               EVP_PKEY *pkey;
                dst_hmac_key_t *hmac_key;
+               EVP_PKEY *pkey;
+               struct {
+                       EVP_PKEY *pub;
+                       EVP_PKEY *priv;
+               } pkeypair;
        } keydata; /*%< pointer to key in crypto pkg fmt */
 
        isc_stdtime_t times[DST_MAX_TIMES + 1]; /*%< timing metadata */
index 94f4f4573186d4b107c0924d8d9a4f1816a8c692..619ce345f4a19d3b8ec2010983dd498750b2eb23 100644 (file)
@@ -155,7 +155,7 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
        isc_region_t r;
        unsigned int siglen = 0;
        EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
-       EVP_PKEY *pkey = key->keydata.pkey;
+       EVP_PKEY *pkey = key->keydata.pkeypair.priv;
 
        REQUIRE(opensslrsa_valid_key_alg(dctx->key->key_alg));
 
@@ -205,7 +205,7 @@ opensslrsa_verify2(dst_context_t *dctx, int maxbits, const isc_region_t *sig) {
        dst_key_t *key = dctx->key;
        int status = 0;
        EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
-       EVP_PKEY *pkey = key->keydata.pkey;
+       EVP_PKEY *pkey = key->keydata.pkeypair.pub;
 
        REQUIRE(opensslrsa_valid_key_alg(dctx->key->key_alg));
 
@@ -233,21 +233,8 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static bool
 opensslrsa_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 || OPENSSL_API_LEVEL < 30000
-       RSA *rsa1 = NULL;
-       RSA *rsa2 = NULL;
-       const BIGNUM *d1 = NULL, *d2 = NULL;
-       const BIGNUM *p1 = NULL, *p2 = NULL;
-       const BIGNUM *q1 = NULL, *q2 = NULL;
-#else
-       BIGNUM *d1 = NULL, *d2 = NULL;
-       BIGNUM *p1 = NULL, *p2 = NULL;
-       BIGNUM *q1 = NULL, *q2 = NULL;
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
+       EVP_PKEY *pkey1 = key1->keydata.pkeypair.pub;
+       EVP_PKEY *pkey2 = key2->keydata.pkeypair.pub;
 
        if (pkey1 == NULL && pkey2 == NULL) {
                return (true);
@@ -255,81 +242,17 @@ opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
                return (false);
        }
 
-       /* `EVP_PKEY_eq` checks only the public key components and paramters. */
-       status = EVP_PKEY_eq(pkey1, pkey2);
-       if (status != 1) {
-               DST_RET(false);
-       }
-
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       rsa1 = EVP_PKEY_get1_RSA(pkey1);
-       rsa2 = EVP_PKEY_get1_RSA(pkey2);
-       if (rsa1 == NULL && rsa2 == NULL) {
-               DST_RET(true);
-       } else if (rsa1 == NULL || rsa2 == NULL) {
-               DST_RET(false);
-       }
-       RSA_get0_key(rsa1, NULL, NULL, &d1);
-       RSA_get0_key(rsa2, NULL, NULL, &d2);
-#else
-       EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_RSA_D, &d1);
-       EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_RSA_D, &d2);
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
-       if (d1 != NULL || d2 != NULL) {
-               if (d1 == NULL || d2 == NULL) {
-                       DST_RET(false);
-               }
-
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-               RSA_get0_factors(rsa1, &p1, &q1);
-               RSA_get0_factors(rsa2, &p2, &q2);
-#else
-               EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_RSA_FACTOR1, &p1);
-               EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_RSA_FACTOR2, &q1);
-               EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_RSA_FACTOR1, &p2);
-               EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_RSA_FACTOR2, &q2);
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
-               if (BN_cmp(d1, d2) != 0 || BN_cmp(p1, p2) != 0 ||
-                   BN_cmp(q1, q2) != 0)
-               {
-                       DST_RET(false);
-               }
-       }
-
-       ret = true;
-
-err:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       if (rsa1 != NULL) {
-               RSA_free(rsa1);
-       }
-       if (rsa2 != NULL) {
-               RSA_free(rsa2);
-       }
-#else
-       if (d1 != NULL) {
-               BN_clear_free(d1);
-       }
-       if (d2 != NULL) {
-               BN_clear_free(d2);
-       }
-       if (p1 != NULL) {
-               BN_clear_free(p1);
-       }
-       if (p2 != NULL) {
-               BN_clear_free(p2);
-       }
-       if (q1 != NULL) {
-               BN_clear_free(q1);
+       /* `EVP_PKEY_eq` checks only the public components and parameters. */
+       if (EVP_PKEY_eq(pkey1, pkey2) != 1) {
+               return (false);
        }
-       if (q2 != NULL) {
-               BN_clear_free(q2);
+       /* The private key presence must be same for keys to match. */
+       if ((key1->keydata.pkeypair.priv != NULL) !=
+           (key2->keydata.pkeypair.priv != NULL))
+       {
+               return (false);
        }
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
-       return (ret);
+       return (true);
 }
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
@@ -478,7 +401,8 @@ opensslrsa_generate(dst_key_t *key, int exp, void (*callback)(int)) {
        }
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
 
-       key->keydata.pkey = pkey;
+       key->keydata.pkeypair.pub = pkey;
+       key->keydata.pkeypair.priv = pkey;
        pkey = NULL;
        ret = ISC_R_SUCCESS;
 
@@ -506,52 +430,19 @@ err:
 
 static bool
 opensslrsa_isprivate(const dst_key_t *key) {
-       bool ret;
-       EVP_PKEY *pkey;
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       RSA *rsa;
-       const BIGNUM *d = NULL;
-#else
-       BIGNUM *d = NULL;
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
        REQUIRE(opensslrsa_valid_key_alg(key->key_alg));
 
-       pkey = key->keydata.pkey;
-       if (pkey == NULL) {
-               return (false);
-       }
-
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       rsa = EVP_PKEY_get1_RSA(pkey);
-       INSIST(rsa != NULL);
-
-       if (RSA_test_flags(rsa, RSA_FLAG_EXT_PKEY) != 0) {
-               ret = true;
-       } else {
-               RSA_get0_key(rsa, NULL, NULL, &d);
-               ret = (d != NULL);
-       }
-       RSA_free(rsa);
-#else
-       ret = (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &d) == 1 &&
-              d != NULL);
-       if (d != NULL) {
-               BN_clear_free(d);
-       }
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
-       return (ret);
+       return (key->keydata.pkeypair.priv != NULL);
 }
 
 static void
 opensslrsa_destroy(dst_key_t *key) {
-       EVP_PKEY *pkey = key->keydata.pkey;
-
-       if (pkey != NULL) {
-               EVP_PKEY_free(pkey);
-               key->keydata.pkey = NULL;
+       if (key->keydata.pkeypair.pub != key->keydata.pkeypair.priv) {
+               EVP_PKEY_free(key->keydata.pkeypair.priv);
        }
+       EVP_PKEY_free(key->keydata.pkeypair.pub);
+       key->keydata.pkeypair.pub = NULL;
+       key->keydata.pkeypair.priv = NULL;
 }
 
 static isc_result_t
@@ -568,9 +459,9 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) {
        BIGNUM *e = NULL, *n = NULL;
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
 
-       REQUIRE(key->keydata.pkey != NULL);
+       REQUIRE(key->keydata.pkeypair.pub != NULL);
 
-       pkey = key->keydata.pkey;
+       pkey = key->keydata.pkeypair.pub;
        isc_buffer_availableregion(data, &r);
 
 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
@@ -748,7 +639,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
 
-       key->keydata.pkey = pkey;
+       key->keydata.pkeypair.pub = pkey;
        pkey = NULL;
        ret = ISC_R_SUCCESS;
 
@@ -800,7 +691,11 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) {
        BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
 
-       if (key->keydata.pkey == NULL) {
+       if (key->keydata.pkeypair.priv != NULL) {
+               pkey = key->keydata.pkeypair.priv;
+       } else if (key->keydata.pkeypair.pub != NULL) {
+               pkey = key->keydata.pkeypair.pub;
+       } else {
                DST_RET(DST_R_NULLKEY);
        }
 
@@ -808,7 +703,6 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) {
                return (dst__privstruct_writefile(key, &priv, directory));
        }
 
-       pkey = key->keydata.pkey;
 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
        rsa = EVP_PKEY_get1_RSA(pkey);
        if (rsa == NULL) {
@@ -964,131 +858,9 @@ err:
        return (ret);
 }
 
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
 static isc_result_t
-rsa_check(RSA *rsa, RSA *pub) {
-       const BIGNUM *n1 = NULL, *n2 = NULL;
-       const BIGNUM *e1 = NULL, *e2 = NULL;
-       BIGNUM *n = NULL, *e = NULL;
-
-       /*
-        * Public parameters should be the same but if they are not set
-        * copy them from the public key.
-        */
-       if (pub != NULL) {
-               RSA_get0_key(rsa, &n1, &e1, NULL);
-               RSA_get0_key(pub, &n2, &e2, NULL);
-               if (n1 != NULL) {
-                       if (BN_cmp(n1, n2) != 0) {
-                               return (DST_R_INVALIDPRIVATEKEY);
-                       }
-               } else {
-                       n = BN_dup(n2);
-                       if (n == NULL) {
-                               return (ISC_R_NOMEMORY);
-                       }
-               }
-               if (e1 != NULL) {
-                       if (BN_cmp(e1, e2) != 0) {
-                               if (n != NULL) {
-                                       BN_free(n);
-                               }
-                               return (DST_R_INVALIDPRIVATEKEY);
-                       }
-               } else {
-                       e = BN_dup(e2);
-                       if (e == NULL) {
-                               if (n != NULL) {
-                                       BN_free(n);
-                               }
-                               return (ISC_R_NOMEMORY);
-                       }
-               }
-               if (RSA_set0_key(rsa, n, e, NULL) == 0) {
-                       if (n != NULL) {
-                               BN_free(n);
-                       }
-                       if (e != NULL) {
-                               BN_free(e);
-                       }
-               }
-       }
-
-       RSA_get0_key(rsa, &n1, &e1, NULL);
-       if (n1 == NULL || e1 == NULL) {
-               return (DST_R_INVALIDPRIVATEKEY);
-       }
-
-       return (ISC_R_SUCCESS);
-}
-#else
-static isc_result_t
-rsa_check(EVP_PKEY *pkey, EVP_PKEY *pubpkey) {
-       isc_result_t ret = ISC_R_FAILURE;
-       int status;
-       BIGNUM *n1 = NULL, *n2 = NULL;
-       BIGNUM *e1 = NULL, *e2 = NULL;
-
-       /* Try to get the public key from pkey. */
-       EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n1);
-       EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e1);
-
-       /* Check if `pubpkey` exists and that we can extract its public key. */
-       if (pubpkey == NULL ||
-           EVP_PKEY_get_bn_param(pubpkey, OSSL_PKEY_PARAM_RSA_N, &n2) != 1 ||
-           n2 == NULL ||
-           EVP_PKEY_get_bn_param(pubpkey, OSSL_PKEY_PARAM_RSA_E, &e2) != 1 ||
-           e2 == NULL)
-       {
-               if (n1 == NULL || e1 == NULL) {
-                       /* 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 (n1 == NULL || e1 == NULL) {
-               status = EVP_PKEY_set_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, n2);
-               if (status != 1) {
-                       DST_RET(ISC_R_FAILURE);
-               }
-
-               status = EVP_PKEY_set_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, e2);
-               if (status != 1) {
-                       DST_RET(ISC_R_FAILURE);
-               }
-       }
-
-       if (EVP_PKEY_eq(pkey, pubpkey) == 1) {
-               DST_RET(ISC_R_SUCCESS);
-       }
-
-err:
-       if (n1 != NULL) {
-               BN_free(n1);
-       }
-       if (n2 != NULL) {
-               BN_free(n2);
-       }
-       if (e1 != NULL) {
-               BN_free(e1);
-       }
-       if (e2 != NULL) {
-               BN_free(e2);
-       }
-
-       return (ret);
-}
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
+opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
+                    const char *pin);
 
 static isc_result_t
 opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
@@ -1096,17 +868,13 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
        isc_result_t ret;
        int i;
 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       RSA *rsa = NULL, *pubrsa = NULL;
-       const BIGNUM *ex = NULL;
+       RSA *rsa = NULL;
 #else
        OSSL_PARAM_BLD *bld = NULL;
        OSSL_PARAM *params = NULL;
        EVP_PKEY_CTX *ctx = NULL;
        BIGNUM *ex = NULL;
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
-       ENGINE *ep = NULL;
-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
        isc_mem_t *mctx = key->mctx;
        const char *engine = NULL, *label = NULL;
        EVP_PKEY *pkey = NULL;
@@ -1126,18 +894,14 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
                if (priv.nelements != 0 || pub == NULL) {
                        DST_RET(DST_R_INVALIDPRIVATEKEY);
                }
-               key->keydata.pkey = pub->keydata.pkey;
-               pub->keydata.pkey = NULL;
+               key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub;
+               key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv;
+               pub->keydata.pkeypair.pub = NULL;
+               pub->keydata.pkeypair.priv = NULL;
                key->key_size = pub->key_size;
                DST_RET(ISC_R_SUCCESS);
        }
 
-#if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
-       if (pub != NULL && pub->keydata.pkey != NULL) {
-               pubrsa = EVP_PKEY_get1_RSA(pub->keydata.pkey);
-       }
-#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
-
        for (i = 0; i < priv.nelements; i++) {
                switch (priv.elements[i].tag) {
                case TAG_RSA_ENGINE:
@@ -1156,48 +920,17 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
         * See if we can fetch it.
         */
        if (label != NULL) {
-#if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
-               if (engine == NULL) {
-                       DST_RET(DST_R_NOENGINE);
-               }
-               ep = dst__openssl_getengine(engine);
-               if (ep == NULL) {
-                       DST_RET(dst__openssl_toresult(DST_R_NOENGINE));
+               ret = opensslrsa_fromlabel(key, engine, label, NULL);
+               if (ret != ISC_R_SUCCESS) {
+                       DST_RET(ret);
                }
-               pkey = ENGINE_load_private_key(ep, label, NULL, NULL);
-               if (pkey == NULL) {
-                       DST_RET(dst__openssl_toresult2("ENGINE_load_private_"
-                                                      "key",
-                                                      ISC_R_NOTFOUND));
-               }
-               key->engine = isc_mem_strdup(key->mctx, engine);
-               key->label = isc_mem_strdup(key->mctx, label);
-
-               rsa = EVP_PKEY_get1_RSA(pkey);
-               if (rsa == NULL) {
-                       DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
-               }
-               if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) {
-                       DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-               }
-               RSA_get0_key(rsa, NULL, &ex, NULL);
-
-               if (ex == NULL) {
-                       DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-               }
-               if (BN_num_bits(ex) > RSA_MAX_PUBEXP_BITS) {
-                       DST_RET(ISC_R_RANGE);
+               /* Check that the public component matches if given */
+               if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub,
+                                              pub->keydata.pkeypair.pub) != 1)
+               {
+                       DST_RET(DST_R_INVALIDPRIVATEKEY);
                }
-
-               key->key_size = EVP_PKEY_bits(pkey);
-               key->keydata.pkey = pkey;
-               pkey = NULL;
                DST_RET(ISC_R_SUCCESS);
-#else  /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
-               UNUSED(engine);
-               UNUSED(ex);
-               DST_RET(DST_R_NOENGINE);
-#endif /* if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000 */
        }
 
        for (i = 0; i < priv.nelements; i++) {
@@ -1244,6 +977,14 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
                }
        }
 
+       /* Basic sanity check for public key portion */
+       if (n == NULL || e == NULL) {
+               DST_RET(DST_R_INVALIDPRIVATEKEY);
+       }
+       if (BN_num_bits(e) > RSA_MAX_PUBEXP_BITS) {
+               DST_RET(ISC_R_RANGE);
+       }
+
 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000
        rsa = RSA_new();
        if (rsa == NULL) {
@@ -1266,6 +1007,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
                if (d != NULL) {
                        BN_clear_free(d);
                }
+               DST_RET(DST_R_INVALIDPRIVATEKEY);
        }
        if (RSA_set0_factors(rsa, p, q) == 0) {
                if (p != NULL) {
@@ -1286,9 +1028,6 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
                        BN_clear_free(iqmp);
                }
        }
-       if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) {
-               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-       }
 #else
        bld = OSSL_PARAM_BLD_new();
        if (bld == NULL) {
@@ -1354,20 +1093,16 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
        {
                DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
        }
-
-       if (rsa_check(pkey, pub != NULL ? pub->keydata.pkey : NULL) !=
-           ISC_R_SUCCESS)
-       {
-               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-       }
 #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 */
 
-       if (BN_num_bits(e) > RSA_MAX_PUBEXP_BITS) {
-               DST_RET(ISC_R_RANGE);
+       /* Check that the public component matches if given */
+       if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) {
+               DST_RET(DST_R_INVALIDPRIVATEKEY);
        }
 
        key->key_size = BN_num_bits(n);
-       key->keydata.pkey = pkey;
+       key->keydata.pkeypair.pub = pkey;
+       key->keydata.pkeypair.priv = pkey;
        pkey = NULL;
 
 err:
@@ -1378,9 +1113,6 @@ err:
        if (rsa != NULL) {
                RSA_free(rsa);
        }
-       if (pubrsa != NULL) {
-               RSA_free(pubrsa);
-       }
 #else
        if (ctx != NULL) {
                EVP_PKEY_CTX_free(ctx);
@@ -1435,9 +1167,7 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
 #if !defined(OPENSSL_NO_ENGINE) && OPENSSL_API_LEVEL < 30000
        ENGINE *e = NULL;
        isc_result_t ret = ISC_R_SUCCESS;
-       EVP_PKEY *pkey = NULL, *pubpkey = NULL;
-       RSA *rsa = NULL, *pubrsa = NULL;
-       const BIGNUM *ex = NULL;
+       EVP_PKEY *privpkey = NULL, *pubpkey = NULL;
 
        UNUSED(pin);
 
@@ -1454,49 +1184,27 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
                DST_RET(dst__openssl_toresult2("ENGINE_load_public_key",
                                               DST_R_OPENSSLFAILURE));
        }
-       pubrsa = EVP_PKEY_get1_RSA(pubpkey);
-       if (pubrsa == NULL) {
-               DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+       if (!opensslrsa_check_exponent_bits(pubpkey, RSA_MAX_PUBEXP_BITS)) {
+               DST_RET(ISC_R_RANGE);
        }
 
-       pkey = ENGINE_load_private_key(e, label, NULL, NULL);
-       if (pkey == NULL) {
+       privpkey = ENGINE_load_private_key(e, label, NULL, NULL);
+       if (privpkey == NULL) {
                DST_RET(dst__openssl_toresult2("ENGINE_load_private_key",
                                               DST_R_OPENSSLFAILURE));
        }
 
        key->engine = isc_mem_strdup(key->mctx, engine);
        key->label = isc_mem_strdup(key->mctx, label);
-
-       rsa = EVP_PKEY_get1_RSA(pkey);
-       if (rsa == NULL) {
-               DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
-       }
-       if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) {
-               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-       }
-       RSA_get0_key(rsa, NULL, &ex, NULL);
-
-       if (ex == NULL) {
-               DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY));
-       }
-       if (BN_num_bits(ex) > RSA_MAX_PUBEXP_BITS) {
-               DST_RET(ISC_R_RANGE);
-       }
-
-       key->key_size = EVP_PKEY_bits(pkey);
-       key->keydata.pkey = pkey;
-       pkey = NULL;
+       key->key_size = EVP_PKEY_bits(privpkey);
+       key->keydata.pkeypair.priv = privpkey;
+       key->keydata.pkeypair.pub = pubpkey;
+       privpkey = NULL;
+       pubpkey = NULL;
 
 err:
-       if (rsa != NULL) {
-               RSA_free(rsa);
-       }
-       if (pubrsa != NULL) {
-               RSA_free(pubrsa);
-       }
-       if (pkey != NULL) {
-               EVP_PKEY_free(pkey);
+       if (privpkey != NULL) {
+               EVP_PKEY_free(privpkey);
        }
        if (pubpkey != NULL) {
                EVP_PKEY_free(pubpkey);